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
}