utilities/pipelines/e2eValidation/resourceRemoval/helper/Remove-ResourceList.ps1 (112 lines of code) (raw):

#region helperScripts <# .SYNOPSIS Remove the given resource(s) .DESCRIPTION Remove the given resource(s). Resources that the script fails to removed are returned in an array. .PARAMETER ResourcesToRemove Mandatory. The resource(s) to remove. Each resource must have a type & resourceId property. .EXAMPLE Remove-ResourceListInner -ResourcesToRemove @( @{ Type = 'Microsoft.Storage/storageAccounts'; ResourceId = 'subscriptions/.../storageAccounts/resourceName' } ) #> function Remove-ResourceListInner { [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory = $false)] [Hashtable[]] $ResourcesToRemove = @() ) begin { Write-Debug ('{0} entered' -f $MyInvocation.MyCommand) # Load functions . (Join-Path $PSScriptRoot 'Invoke-ResourceRemoval.ps1') . (Join-Path $PSScriptRoot 'Invoke-ResourcePostRemoval.ps1') } process { $resourcesToRemove | ForEach-Object { Write-Verbose ('- Remove [{0}]' -f $_.resourceId) -Verbose } $resourcesToRetry = @() $processedResources = @() Write-Verbose '----------------------------------' -Verbose foreach ($resource in $resourcesToRemove) { $resourceName = Split-Path $resource.resourceId -Leaf $alreadyProcessed = $processedResources.count -gt 0 ? (($processedResources | Where-Object { $resource.resourceId -like ('{0}/*' -f $_) }).Count -gt 0) : $false if ($alreadyProcessed) { # Skipping Write-Verbose ('[/] Skipping resource [{0}] of type [{1}]. Reason: Its parent resource was already processed' -f $resourceName, $resource.type) -Verbose [array]$processedResources += $resource.resourceId [array]$resourcesToRetry = $resourcesToRetry | Where-Object { $_.resourceId -notmatch $resource.resourceId } } else { Write-Verbose ('[-] Removing resource [{0}] of type [{1}]' -f $resourceName, $resource.type) -Verbose try { if ($PSCmdlet.ShouldProcess(('Resource [{0}]' -f $resource.resourceId), 'Remove')) { Invoke-ResourceRemoval -Type $resource.type -ResourceId $resource.resourceId } # If we removed a parent remove its children [array]$processedResources += $resource.resourceId [array]$resourcesToRetry = $resourcesToRetry | Where-Object { $_.resourceId -notmatch $resource.resourceId } } catch { if ($_.Exception.HttpStatus -in @(404, 'NotFound')) { # Skipping because resource/parent is missing. This 'exception handling' can be required in case the parent resource removal ran into an issue, but was completed regardless Write-Verbose ('[/] Skipping resource [{0}] of type [{1}]. Reason: It or its parent cannot be found.' -f $resourceName, $resource.type) -Verbose [array]$processedResources += $resource.resourceId [array]$resourcesToRetry = $resourcesToRetry | Where-Object { $_.resourceId -notmatch $resource.resourceId } } else { Write-Warning ('[!] Removal moved back for retry. Reason: [{0}]' -f $_.Exception.Message) [array]$resourcesToRetry += $resource } } } # We want to purge resources even if they were not explicitly removed because they were 'alreadyProcessed' if ($PSCmdlet.ShouldProcess(('Post-resource-removal for [{0}]' -f $resource.resourceId), 'Execute')) { Invoke-ResourcePostRemoval -Type $resource.type -ResourceId $resource.resourceId } } Write-Verbose '----------------------------------' -Verbose return $resourcesToRetry } end { Write-Debug ('{0} exited' -f $MyInvocation.MyCommand) } } #endregion <# .SYNOPSIS Remove all resources in the provided array from Azure .DESCRIPTION Remove all resources in the provided array from Azure. Resources are removed with a retry mechanism. .PARAMETER ResourcesToRemove Optional. The array of resources to remove. Has to contain objects with at least a 'resourceId' & 'type' property .EXAMPLE Remove-ResourceList @( @{ Type = 'Microsoft.Storage/storageAccounts'; ResourceId = 'subscriptions/.../storageAccounts/resourceName' } ) Remove resource with ID 'subscriptions/.../storageAccounts/resourceName'. #> function Remove-ResourceList { [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory = $false)] [PSObject[]] $ResourcesToRemove = @(), [Parameter(Mandatory = $false)] [int] $RemovalRetryLimit = 3, [Parameter(Mandatory = $false)] [int] $RemovalRetryInterval = 15 ) $removalRetryCount = 1 $resourcesToRetry = $resourcesToRemove do { if ($PSCmdlet.ShouldProcess(("[{0}] Resource(s) with a maximum of [$removalRetryLimit] attempts." -f (($resourcesToRetry -is [array]) ? $resourcesToRetry.Count : 1)), 'Remove')) { $resourcesToRetry = Remove-ResourceListInner -ResourcesToRemove $resourcesToRetry } else { Remove-ResourceListInner -ResourcesToRemove $resourcesToRemove -WhatIf } if (-not $resourcesToRetry) { break } Write-Verbose ('Retry removal of remaining [{0}] resources. Waiting [{1}] seconds. Round [{2}|{3}]' -f (($resourcesToRetry -is [array]) ? $resourcesToRetry.Count : 1), $removalRetryInterval, $removalRetryCount, $removalRetryLimit) $removalRetryCount++ Start-Sleep $removalRetryInterval } while ($removalRetryCount -le $removalRetryLimit) if ($resourcesToRetry.Count -gt 0) { throw ('The removal failed for resources [{0}]' -f ((Split-Path $resourcesToRetry.resourceId -Leaf) -join ', ')) } else { Write-Verbose ('The removal of the [{0}] completed successfully' -f $ResourcesToRemove.Count) } }