utilities/pipelines/resourceRemoval/helper/Invoke-ResourcePostRemoval.ps1 (139 lines of code) (raw):

<# .SYNOPSIS Remove any artifacts that remain of the given resource .DESCRIPTION Remove any artifacts that remain of the given resource. For example, some resources such as key vaults usually go into a soft-delete state from which we want to purge them from. .PARAMETER ResourceId Mandatory. The resourceID of the resource to remove .PARAMETER Type Mandatory. The type of the resource to remove .EXAMPLE Invoke-ResourcePostRemoval -Type 'Microsoft.KeyVault/vaults' -ResourceId '/subscriptions/.../resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/myVault' Purge the resource 'myVault' of type 'Microsoft.KeyVault/vaults' with ID '/subscriptions/.../resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/myVault' if no purge protection is enabled #> function Invoke-ResourcePostRemoval { [CmdletBinding(SupportsShouldProcess)] param ( [Parameter(Mandatory = $true)] [string] $ResourceId, [Parameter(Mandatory = $true)] [string] $Type ) switch ($Type) { 'Microsoft.AppConfiguration/configurationStores' { $subscriptionId = $ResourceId.Split('/')[2] $resourceName = Split-Path $ResourceId -Leaf # Fetch service in soft-delete $getPath = '/subscriptions/{0}/providers/Microsoft.AppConfiguration/deletedConfigurationStores?api-version=2021-10-01-preview' -f $subscriptionId $getRequestInputObject = @{ Method = 'GET' Path = $getPath } $softDeletedConfigurationStore = ((Invoke-AzRestMethod @getRequestInputObject).Content | ConvertFrom-Json).value | Where-Object { $_.properties.configurationStoreId -eq $ResourceId } if ($softDeletedConfigurationStore) { # Purge service $purgePath = '/subscriptions/{0}/providers/Microsoft.AppConfiguration/locations/{1}/deletedConfigurationStores/{2}/purge?api-version=2021-10-01-preview' -f $subscriptionId, $softDeletedConfigurationStore.properties.location, $resourceName $purgeRequestInputObject = @{ Method = 'POST' Path = $purgePath } Write-Verbose ('[*] Purging resource [{0}] of type [{1}]' -f $resourceName, $Type) -Verbose if ($PSCmdlet.ShouldProcess(('App Configuration Store with ID [{0}]' -f $softDeletedConfigurationStore.properties.configurationStoreId), 'Purge')) { $response = Invoke-AzRestMethod @purgeRequestInputObject if ($response.StatusCode -ne 200) { throw ('Purge of resource [{0}] failed with error code [{1}]' -f $ResourceId, $response.StatusCode) } } } break } 'Microsoft.KeyVault/vaults' { $resourceName = Split-Path $ResourceId -Leaf $matchingKeyVault = Get-AzKeyVault -InRemovedState | Where-Object { $_.resourceId -eq $ResourceId } if ($matchingKeyVault -and -not $matchingKeyVault.EnablePurgeProtection) { Write-Verbose ('[*] Purging resource [{0}] of type [{1}]' -f $resourceName, $Type) -Verbose if ($PSCmdlet.ShouldProcess(('Key Vault with ID [{0}]' -f $matchingKeyVault.Id), 'Purge')) { try { $null = Remove-AzKeyVault -ResourceId $matchingKeyVault.Id -InRemovedState -Force -Location $matchingKeyVault.Location -ErrorAction 'Stop' } catch { if ($_.Exception.Message -like '*DeletedVaultPurge*') { Write-Warning ('Purge protection for key vault [{0}] enabled. Skipping. Scheduled purge date is [{1}]' -f $resourceName, $matchingKeyVault.ScheduledPurgeDate) } else { throw $_ } } } } break } 'Microsoft.CognitiveServices/accounts' { $resourceGroupName = $ResourceId.Split('/')[4] $resourceName = Split-Path $ResourceId -Leaf $matchingAccount = Get-AzCognitiveServicesAccount -InRemovedState | Where-Object { $_.AccountName -eq $resourceName } if ($matchingAccount) { Write-Verbose ('[*] Purging resource [{0}] of type [{1}]' -f $resourceName, $Type) -Verbose if ($PSCmdlet.ShouldProcess(('Cognitive services account with ID [{0}]' -f $matchingAccount.Id), 'Purge')) { $null = Remove-AzCognitiveServicesAccount -InRemovedState -Force -Location $matchingAccount.Location -ResourceGroupName $resourceGroupName -Name $matchingAccount.AccountName } } break } 'Microsoft.ApiManagement/service' { $subscriptionId = $ResourceId.Split('/')[2] $resourceName = Split-Path $ResourceId -Leaf # Fetch service in soft-delete $getPath = '/subscriptions/{0}/providers/Microsoft.ApiManagement/deletedservices?api-version=2021-08-01' -f $subscriptionId $getRequestInputObject = @{ Method = 'GET' Path = $getPath } $softDeletedService = ((Invoke-AzRestMethod @getRequestInputObject).Content | ConvertFrom-Json).value | Where-Object { $_.properties.serviceId -eq $ResourceId } if ($softDeletedService) { # Purge service $purgePath = '/subscriptions/{0}/providers/Microsoft.ApiManagement/locations/{1}/deletedservices/{2}?api-version=2020-06-01-preview' -f $subscriptionId, $softDeletedService.location, $resourceName $purgeRequestInputObject = @{ Method = 'DELETE' Path = $purgePath } Write-Verbose ('[*] Purging resource [{0}] of type [{1}]' -f $resourceName, $Type) -Verbose if ($PSCmdlet.ShouldProcess(('API management service with ID [{0}]' -f $softDeletedService.properties.serviceId), 'Purge')) { $null = Invoke-AzRestMethod @purgeRequestInputObject } } break } 'Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems' { # Remove protected VM # Required if e.g. a VM was listed in an RSV and only that VM is removed $vaultId = $ResourceId.split('/backupFabrics/')[0] $resourceName = Split-Path $ResourceId -Leaf $softDeleteStatus = (Get-AzRecoveryServicesVaultProperty -VaultId $vaultId).SoftDeleteFeatureState if ($softDeleteStatus -ne 'Disabled') { if ($PSCmdlet.ShouldProcess(('Soft-delete on RSV [{0}]' -f $vaultId), 'Set')) { $null = Set-AzRecoveryServicesVaultProperty -VaultId $vaultId -SoftDeleteFeatureState 'Disable' } } $backupItemInputObject = @{ BackupManagementType = 'AzureVM' WorkloadType = 'AzureVM' VaultId = $vaultId Name = $resourceName } if ($backupItem = Get-AzRecoveryServicesBackupItem @backupItemInputObject -ErrorAction 'SilentlyContinue') { Write-Verbose (' [-] Removing Backup item [{0}] from RSV [{1}]' -f $backupItem.Name, $vaultId) -Verbose if ($backupItem.DeleteState -eq 'ToBeDeleted') { if ($PSCmdlet.ShouldProcess('Soft-deleted backup data removal', 'Undo')) { $null = Undo-AzRecoveryServicesBackupItemDeletion -Item $backupItem -VaultId $vaultId -Force } } if ($PSCmdlet.ShouldProcess(('Backup item [{0}] from RSV [{1}]' -f $backupItem.Name, $vaultId), 'Remove')) { $null = Disable-AzRecoveryServicesBackupProtection -Item $backupItem -VaultId $vaultId -RemoveRecoveryPoints -Force } } # Undo a potential soft delete state change $null = Set-AzRecoveryServicesVaultProperty -VaultId $vaultId -SoftDeleteFeatureState $softDeleteStatus.TrimEnd('d') break } ### CODE LOCATION: Add custom post-removal operation here } }