Get-AllInstalledExtensioons.ps1
<# .Synopsis Get 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 [Mandatory] 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 listOfOrganizations Comma/Delimeted separated list of Azure DevOps organizatins if you want to run for specific list of organizations. .Example Get-AllInstalledExtensions -PAT <TOKEN> -approvedpublisherId ms,ms-devlabs,AammirMirza,AmazonWebServices,azsdktm,AzureSynapseWorkspace # Using with list of approved ExtensionsID Output: Executing for mv-shoppable-apps |-- Azure Artifacts | Microsoft |-- Package Management for TFS 2017 and TFS 2018 | Microsoft |-- Pipeline Artifacts | Microsoft |-- Aex Code Mapper | Microsoft |-- Aex platform | Microsoft |-- Aex user management | Microsoft |-- User Management | Microsoft |-- Bill | Microsoft |-- Gallery extensions for Portal Extension | Microsoft |-- Distributed Task | Microsoft |-- Service connections | Microsoft |-- Extensions | Microsoft |-- Favorites | Microsoft |-- Enterprise Administration | Microsoft |-- Package Search | Microsoft |-- Pipelines | Microsoft |-- Release | Microsoft |-- Release Artifacts | Microsoft |-- Release Management | Microsoft |-- Service Hooks | Microsoft |-- Service Hooks Web UI | Microsoft |-- Docker Tools | Microsoft ##[error] |-- SonarQube build breaker | Simon de Lang ##[error] |-- Tokenize in archive | Solidify Labs ##[error] |-- SonarQube | SonarSource ##[error] |-- Synopsys Detect | Synopsys Inc. .Example Get-AllInstalledExtensions -PAT <TOKEN> -approvedpublisherId ms,ms-devlabs,AammirMirza,AmazonWebServices,azsdktm,AzureSynapseWorkspace -listOfOrganizations Organization1,Organization2,Orgaanization3 # Using with the list of organizations instead of all organizations #> function Get-AllInstalledExtensions { param ( [Parameter(Mandatory = $true)] [string]$PAT, [Parameter(Mandatory = $true)] $approvedpublisherId = @(), $listOfOrganizations = @() ) ################################################################ ## Signature $t = @" Package designed and managed _ _ _ | |__ _ _ /_\ __ _ _ __ (_) _ _ | '_ \| || | / _ \ / _` || ' \ | || '_| |_.__/ \_, | /_/ \_\\__,_||_|_|_||_||_| |__/ Azure DevOps extensions management. Validate, Verify and Action for newly installed extensions accross organizations. Please suggest improvements at aammir.mirza@hotmail.com "@ for ($i=0;$i -lt $t.length;$i++) { if ($i%2) { $c = "white" } elseif ($i%5) { $c = "white" } elseif ($i%7) { $c = "white" } else { $c = "white" } write-host $t[$i] -NoNewline -ForegroundColor $c } ################################################################ $AzureDevOpsAuthenicationHeader = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($PAT)")) } # Getting list of all organization within the AzDO $uProfile = Invoke-RestMethod -Uri "https://app.vssps.visualstudio.com/_apis/profile/profiles/me?api-version=6.0" -Method get -Headers $AzureDevOpsAuthenicationHeader # $uProfile.publicAlias $organizationtoProcess = @() $allOrganization = Invoke-RestMethod -Uri "https://app.vssps.visualstudio.com/_apis/accounts?memberId=$($uprofile.publicAlias)&api-version=6.0" -Method get -Headers $AzureDevOpsAuthenicationHeader if (!$listOfOrganizations) { $organizationtoProcess = $allOrganization.value.accountName } else { $organizationtoProcess = $listOfOrganizations } Write-Host "---------------------------------------------" get-help Get-AllInstalledExtensions -Detailed Write-Host "---------------------------------------------" Write-Host "---------------------------------------------" Write-Host "##[command]Summary" Write-Host "##[command]Number_of_Organizations : $($organizationtoProcess.count)" Write-Host "---------------------------------------------" try { foreach ($Organization in $organizationtoProcess) { try { Write-Host "##[command]Executing for $($Organization)" $UriInstalledExtensions = "https://extmgmt.dev.azure.com/$($Organization)/_apis/extensionmanagement/installedextensions?api-version=6.0-preview.1" $InstalledExtensionsResult = Invoke-RestMethod -Uri $UriInstalledExtensions -Method get -Headers $AzureDevOpsAuthenicationHeader $result = @() Foreach ($extension in $InstalledExtensionsResult.value) { $extName = $($extension.extensionName).Replace("'", "") $extPublisherName = $($extension.publisherName).Replace("'", "") $extPublisherId = $($extension.publisherId).Replace("'", "") if (!$approvedpublisherId) { Write-Host " |-- $($extName) | $($extPublisherName)" } elseif ($extPublisherId -in $approvedpublisherId) { Write-Host " |-- $($extName) | $($extPublisherName)" } else { Write-Host "##[error] |-- $($extName) | $($extPublisherName)" } #Write-Host ('{0,30}{10}' -f $extName,$extPublisherName) $obj = [PSCustomObject]@{ Organization = "[$($Organization)](https://dev.azure.com/$($Organization)/_settings/extensions)" ExtensionId = $extension.extensionId ExtensionName = $extName ExtensionPublisherName = $extPublisherName PublisherId = $extension.publisherId ExtensionVersion = $extension.version ExtensionLastPublished = $extension.lastPublished } $result += $obj } # $result | Export-Csv -Path "C:\Custom_Data\Scripts\allExtensions.csv" -NoTypeInformation -Append $result | Export-Csv -Path __AllInstalledExtensions.csv -NoTypeInformation -Append $result | ConvertTo-Json | Out-File "$($Organization).json" Continue } catch { Write-Host "##[error]!!! Exeption raised for $($Organization) !!!" Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription } } $allFiles = Get-ChildItem *.json | Select-Object -ExpandProperty Name foreach ($item in $allFiles) { $allResults += Get-Content -Path $item -Raw | ConvertFrom-Json $allResults | ConvertTo-Json -Depth 5 | Out-File -FilePath latestInstalledExtensions.json Write-Host "##[warning]Completed parsing for $($item)" } } catch { Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription } } |