Delete-Extensions.ps1
<# .Synopsis Delete/Un-Install all installed extensions accross the Azure DevOps Organizations .Description Calling this function will return list of all installed extensions accross the organizations. It will help understand what is happening around the organizational elevated access for the projects. .Parameter Token Specifies the access token to use for the communication. See description above for any access token requirements and run 'Get-Help Get-Token -Detailed' for additional detailed notes. (Mandatory) .Parameter ApprovedpublisherId [Mandatory] Comma/Delimeted separated list of approved PublishersID to differentiate between approved and unapproved etxnsions as output .Parameter unApprovedExtensionId [Mandatory] Comma/Delimeted separated list of UN-APPROVED ExtensionID to more granually restrict the extensions by specific IDs instead of PublisherID as a whole. .Parameter listOfOrganizations Comma/Delimeted separated list of Azure DevOps organizatins if you want to run for specific list of organizations. .Example Delete-Extensions -PAT <PAT> -approvedpublisherId ms,ms-devlabs -unApprovedExtensionId browserstack-vsts-extension,PeterGroenewegen-Xpirit-Vsts-Release-Terraform,upload-sp-provider-hosted-app,upload-sp-files-app,sonar-buildbreaker -WhatIf .Example Delete-Extensions -PAT <PAT> -approvedpublisherId ms,ms-devlabs -unApprovedExtensionId browserstack-vsts-extension,PeterGroenewegen-Xpirit-Vsts-Release-Terraform,upload-sp-provider-hosted-app,upload-sp-files-app,sonar-buildbreaker #> function Delete-Extensions { param ( [Parameter(Mandatory = $true)] [string]$PAT, [Parameter(Mandatory = $true)] $approvedPublisherId = @(), [Parameter(Mandatory = $true)] $unApprovedExtensionId = @(), $listOfOrganizations = @(), [switch]$WhatIf ) $Count = 0 $result = @() if (!(Test-Path -Path latestInstalledExtensions.json -PathType Leaf)) { Write-Host "Missing JSON for parsing. Creating from the supplied params." Get-AllInstalledExtensions -PAT $PAT -approvedpublisherId $approvedPublisherId -listOfOrganizations $listOfOrganizations } $json = Get-Content -Raw -Path latestInstalledExtensions.json | Out-String | ConvertFrom-Json foreach ($Object in $json) { # Allowed by PublisherID if ($Object.PublisherId -notin $approvedPublisherId) { # Blocked by ExtensionID if ($Object.ExtensionId -in $unApprovedExtensionId) { Write-Host "##[debug] Below extension can be un-installed - $($Object.ExtensionName)." $Object $result += $Object # # Disableling unapproved extensions if ($WhatIf -eq $true) { ('-' * 50) Write-Host "Initiating DELETE API call for extenison - $($Object.publisherId)" # $body = "{ # `n `"publisherId`": `"$($Object.publisherId)`", # `n `"extensionId`":`"$($Object.extensionId)`", # `n `"installState`": { # `n `"flags`": `"disabled`" # `n } # `n}" # $response = Invoke-RestMethod 'https://extmgmt.dev.azure.com/$($Object.Organization)/_apis/extensionmanagement/installedextensions?api-version=6.0-preview.1' -Method 'PATCH' -Headers $headers -Body $body # $response | ConvertTo-Json # $response = Invoke-RestMethod 'https://extmgmt.dev.azure.com/$($Object.Organization)/_apis/extensionmanagement/installedextensionsbyname/$($Object.PublisherId)/$($Object.ExtensionId)?reason=InvalideUnAuthorisedExtension&reasonCode={reasonCode}&api-version=6.0-preview.1' -Method 'DELETE' -Headers $headers # $response | ConvertTo-Json } ('-' * 50) $Count = $Count + 1 } else { if (($Object.PublisherId -notin $approvedPublisherId) -and ($Object.ExtensionId -notin $unApprovedExtensionId)) { Write-Host "##[warning] New publisher identified" $Object $result += $Object $Count = $Count + 1 } } } } ('=' * 50) Write-Host "##[debug] $($Count) extension marked for deletion" Write-Host "##vso[task.logissue type=warning] $($Count) extension marked for deletion" ('=' * 50) $result | Export-Csv -Path "nonCompliant.csv" -NoTypeInformation -Append } |