tests/build/Remove-VstsAgentOnWindowsServerCoreContainer.ps1

########################################################################################################################
# Script Disclaimer
########################################################################################################################
# This script is not supported under any Microsoft standard support program or service.
# This script is provided AS IS without warranty of any kind.
# Microsoft disclaims all implied warranties including, without limitation, any implied warranties of
# merchantability or of fitness for a particular purpose. The entire risk arising out of the use or
# performance of this script and documentation remains with you. In no event shall Microsoft, its authors,
# or anyone else involved in the creation, production, or delivery of this script be liable for any damages
# whatsoever (including, without limitation, damages for loss of business profits, business interruption,
# loss of business information, or other pecuniary loss) arising out of the use of or inability to use
# this script or documentation, even if Microsoft has been advised of the possibility of such damages.

<#
.SYNOPSIS
    This script removes the selected Azure Container Instance(s).
.DESCRIPTION
    This script removes the selected Azure Container Instance(s). It leaves the Resource Group (and other resources
     within it) intact. This script is designed and tested to be run from Azure Cloud Shell.
.PARAMETER SubscriptionName
    Name of the Subscription.
.PARAMETER ResourceGroupName
    Name of the Resource Group.
.PARAMETER ContainerName
    Name of the ACI container(s).
.PARAMETER PatToken
    PAT token required to log in to Azure DevOps to delete the Agent's registration from the pool.
.PARAMETER AzureDevOpsAccountName
    Name of the Azure DevOps account that the Agent is registered to.
.PARAMETER AgentPoolName
    Name of the Agent Pool that holds the Agent to delete.
.EXAMPLE
    .\Remove-VstsAgentOnWindowsServerCoreContainer.ps1 -SubscriptionName "<subscription name>" -ResourceGroupName "<resource group name>" -ContainerName "<container 1 name>", "<container 2 name>" -PatToken "<pat token to log in>" -AzureDevOpsAccountName "<ADOS account name>" -AgentPoolName "<name of the Agent Pool>"
    This removes the 2 requested containers and their registrations from Azure DevOps. It leaves the Resource Group (and other resources within) intact.
.INPUTS
    <none>
.OUTPUTS
    <none>
.NOTES
    Version: 1.1
    Author: Mate Barabas
    Creation Date: 2018-08-29
    Change log:
    - v1.1 (2019-04-06): the script now removes the Agent's registration from the Agent pool
#>


param(

    [Parameter(Mandatory = $true)][string]$SubscriptionName,
    [Parameter(Mandatory = $true)][string]$ResourceGroupName,
    [Parameter(Mandatory = $true)][array]$ContainerName,
    [Parameter(Mandatory = $true)][string]$PatToken, #Personal access token
    [Parameter(Mandatory = $true)][string]$AzureDevOpsAccountName, #Azure DevOps account name
    [Parameter(Mandatory = $true)][string]$AgentPoolName #Azure DevOps Agent pool name

)


#region Functions

function Set-AzureContext
{

    param (

        [Parameter(Mandatory = $false)][string]$SubscriptionName

    )


    # Select the desired Subscription based on the Subscription name provided
    if ($SubscriptionName)
    {
        $Subscription = (Get-AzureRmSubscription | Where-Object { $_.Name -eq $SubscriptionName })
            
        if (-not $Subscription)
        {
            Write-Error "There's no Subscription available with the provided name."
            return
        }
        else
        {
            $SubscriptionId = $Subscription.Id
            Select-AzureRmSubscription -SubscriptionId $SubscriptionId | Out-Null
            Write-Output "The following subscription was selected: ""$SubscriptionName"""
        }
    }
    # If no Subscription name was provided select the active Subscription based on the existing context
    else
    {
        $SubscriptionName = (Get-AzureRmContext).Subscription.Name
        $Subscription = (Get-AzureRmSubscription | Where-Object { $_.Name -eq $SubscriptionName })
        Write-Output "The following subscription was selected: ""$SubscriptionName"""
    }

    if ($Subscription.Count -gt 1)
    {
        Write-Error "You have more then 1 Subscription with the same name. Exiting..."
        return
    }
}

function Remove-Container
{

    param (

        [Parameter(Mandatory = $true)][array]$ContainerName

    )

    foreach ($Name in $ContainerName)
    {
        $Container = Get-AzureRmContainerGroup -ResourceGroupName $ResourceGroupName -Name $Name -ErrorAction SilentlyContinue
        if (-not $Container)
        {
            Write-Warning "No ACI container exists with the provided name ($Name)."
        }
        else 
        {
            Write-Warning "Removing selected ACI container ($Name)..."    
            Remove-AzureRmContainerGroup -ResourceGroupName $ResourceGroupName -Name $Name -Confirm:$false

            # Check success
            $Container = Get-AzureRmContainerGroup -ResourceGroupName $ResourceGroupName -Name $Name -ErrorAction SilentlyContinue
            if ($null -eq $Container)
            {
                Write-Output "ACI container ""$Name"" successfully deleted."
                if (-not ($PatToken -and $AgentPoolName -and $AzureDevOpsAccountName))
                {
                    Write-Warning "One or more containers have been deleted. Don't forget to clean your Agent pool in Azure DevOps (remove any agents that were created in a previous iteration and are now offline)!"
                }
            }
        }
    }

}

function Remove-AzureDevOpsAgentFromPool
{
    Param(
        [string]$PatToken, #Personal access token
        [string]$AzureDevOpsAccountName, #Azure DevOps account name
        [string]$AgentPoolName, #Azure DevOps Agent pool name
        [array]$ContainerName  #Azure DevOps Agent pool name
    )
        
    $base64AuthInfo = [System.Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($PatToken)"))
    $Header = @{Authorization = ("Basic $base64AuthInfo") }

    # Get Agent Pool
    Write-Output "Getting Agent Pool ($AgentPoolName)..."
    $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools"
    $result = Invoke-RestMethod -Uri $uri -Method GET -ContentType "application/json" -Headers $Header
    $AgentPool = $result.value | Where-Object { $_.Name -eq "$AgentPoolName" }
    $AgentPoolId = $AgentPool.id

    if (-not $AgentPoolId)
    {
        Write-Error "The Agent Pool ($AgentPoolName) doesn't exist!"
    }
    else
    {
        # Get Agents
        Write-Output "Getting Agents from Pool..."
        $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools/$AgentPoolId/agents?includeCapabilities=false&includeAssignedRequest=true"
        $result = Invoke-RestMethod -Uri $uri -Method GET -ContentType "application/json" -Headers $Header
        $Agents = $result.value

        if (-not $Agents)
        {
            Write-Output "There are no Agents in this Agent Pool"
        }
        else
        {
            Write-Output "The following agents were found:"
            foreach ($Agent in $Agents)
            {
                $AgentName = $Agent.name
                $AgentStatus = $Agent.status
                Write-Output "$AgentName ($AgentStatus)"
            }

            # Delete Agent(s) from Pool
            foreach ($Name in $ContainerName)
            {
                Write-Output "Attempting to remove any Agent(s) that belonged to this ACI container: $Name..."
                foreach ($Agent in $Agents)
                {
                    $AgentName = $Agent.name

                    if ($AgentName -match "^$Name-")
                    {
                        # Delete Agent
                        $AgentIds = $Agent.id
                        foreach ($AgentId in $AgentIds)
                        {
                            Write-Output "Deleting Agent ($AgentName) - (Agent ID: $AgentId)..."
                            $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools/$AgentPoolId/agents/$($AgentId)?api-version=5.0"
                            $result = Invoke-RestMethod -Uri $uri -Method DELETE -ContentType "application/json" -Headers $Header

                            # Check success
                            Write-Output "Checking if the Agent ($AgentName) - (Agent ID: $AgentId) is still there..."
                            $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools/$AgentPoolId/agents?includeCapabilities=false&includeAssignedRequest=true"
                            $result = Invoke-RestMethod -Uri $uri -Method GET -ContentType "application/json" -Headers $Header
                            $AgentStillThere = $result.value.id -contains $AgentId
                            if ($AgentStillThere)
                            {
                                Write-Warning "Agent ($AgentName) could not be deleted. Don't forget to clean your Agent pool in Azure Devops (remove any agents that were created in a previous iteration and are now offline)!"
                            }
                            else
                            {
                                Write-Output "Agent ($AgentName) successfully deleted."    
                            }
                        }
                    }
                }
            }
        }
    }
}

#endregion


#region Main

# Login to Azure and select Subscription
Set-AzureContext -SubscriptionName $SubscriptionName

# Delete selected containers
Remove-Container -ContainerName $ContainerName

# Delete Agent registration from Azure DevOps Agent pool
Remove-AzureDevOpsAgentFromPool -PatToken $PatToken -AzureDevOpsAccountName $AzureDevOpsAccountName -AgentPoolName $AgentPoolName -ContainerName $ContainerName

#endregion
# SIG # Begin signature block
# MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUqnC17MmjLJIModmCDDzDSlmd
# OEGgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B
# AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz
# c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx
# MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD
# VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s
# czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt
# Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202
# 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh
# K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0
# Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3
# tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys
# Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y
# MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw
# EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny
# bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0
# dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG
# A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
# LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI
# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC
# aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ
# RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD
# ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA
# QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj
# sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M
# asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD
# xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn
# daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv
# lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp
# Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp
# Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw
# MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx
# GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI
# QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA
# A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx
# 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj
# lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN
# YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2
# DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9
# hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV
# HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF
# BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp
# Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu
# Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig
# NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v
# dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo
# BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB
# hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU
# Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi
# 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l
# jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k
# riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P
# QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d
# 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm
# oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM
# RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD
# EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo
# dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh
# AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM
# BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTRWXL978E8G0Ad7rqqqhCDE2a2
# WDANBgkqhkiG9w0BAQEFAASCAQAJLXwSjpFXNvsRTGaJCps/BdPTa4vslCLFIiqk
# Hnk9YAdT4avJIEWFJeYPtNG9YYMueEQ778aigPyvFDwdIormXm5ECfm3Ijfo2Pn2
# RXd8zBwb/bNnAYsnmBLw1J9nCz0umVVqv2gGGDZWykclyZXFd4C+qZihRoRS6bUi
# rDUDkSN61nPtcv3naa2a99NV8qcZeXEvXhivDxz7gqGSTqWCEDzt868q4dAN81gi
# sWbrsiUCrNL313euZRW5zH6DICgmXLacqKam1gvIdWqLpYVX/OSfZh1DIR7UG/xm
# CFMzSSJ0SeOYYEGQd6vzv9qz2woDmsQcsbnHqZjimWzEIeJa
# SIG # End signature block