Public/Remove-PSCFNStack.ps1
function Remove-PSCFNStack { <# .SYNOPSIS Delete one or more stacks. .DESCRIPTION Delete one or more stacks. Deletion of multiple stacks can be either sequential or parallel. If deleting a gruop of stacks where there are dependencies between them use the -Sequential switch and list the stacks in dependency order. .PARAMETER StackName Either stack names or the object returned by Get-CFNStack, New-CFNStack, Update-CFNStack and other functions in this module when run with -Wait. .PARAMETER Wait If set and -Sequential is not set (so deleting in parallel), wait for all stacks to be deleted before returning. .PARAMETER Sequential If set, delete stacks in the order they are specified on the command line or received from the pipeline, waiting for each stack to delete successfully before proceeding to the next one. .INPUTS System.String[] You can pipe the names or ARNs of the stacks to delete to this function .OUTPUTS System.String[] ARN(s) of deleted stack(s) else nothing if the stack did not exist. .EXAMPLE Remove-PSCFNStack -StackName MyStack Deletes a single stack. .EXAMPLE 'DependentStack', 'BaseStack' | Remove-PSCFNStack -Sequential Deletes 'DependentStack', waits for completion, then deletes 'BaseStack'. .EXAMPLE 'Stack1', 'Stack2' | Remove-PSCFNStack -Wait Sets both stacks deleting in parallel, then waits for them both to complete. .EXAMPLE 'Stack1', 'Stack2' | Remove-PSCFNStack Sets both stacks deleting in parallel, and returns immediately. See the CloudFormation console to monitor progress. .EXAMPLE Get-CFNStack | Remove-PSCFNStack You would NOT want to do this, just like you wouldn't do rm -rf / ! It is for illustration only. Sets ALL stacks in the region deleting simultaneously, which would probably trash some stacks and then others would fail due to dependent resources. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [string[]]$StackName, [switch]$Wait, [switch]$Sequential ) DynamicParam { #Create the RuntimeDefinedParameterDictionary New-Object System.Management.Automation.RuntimeDefinedParameterDictionary | New-CredentialDynamicParameters } begin { $endStates = @('DELETE_COMPLETE', 'DELETE_FAILED') $credentialArguments = Get-CommonCredentialParameters -CallerBoundParameters $PSBoundParameters $deleteBegin = [DateTime]::Now } process { $arns = $StackName | ForEach-Object { if (Test-StackExists -StackName $_ -CredentialArguments $credentialArguments) { $arn = (Get-CFNStack -StackName $_ @credentialArguments).StackId Remove-CFNStack -StackName $arn -Force if ($Sequential -or ($Wait -and ($StackName | Measure-Object).Count -eq 1)) { # Wait for this delete to complete before starting the next Write-Host "Waiting for delete: $arn" $stack = Wait-CFNStack -StackName $arn -Timeout ([TimeSpan]::FromMinutes(60).TotalSeconds) -Status $endStates @credentialArguments if ($stack.StackStatus -like 'DELETE_FAILED') { Write-Host -ForegroundColor Red -BackgroundColor Black "Delete failed: $arn" Write-Host -ForegroundColor Red -BackgroundColor Black (Get-StackFailureEvents -StackName $arn -CredentialArguments $credentialArguments | Sort-Object -Descending Timestamp | Out-String) # Have to give up now as chained stack almost certainly is used by this one throw $stack.StackStatusReason } } else { $arn } } else { Write-Warning "Stack does not exist: $StackName" } } } end { if ($Wait -and ($arns | Measure-Object).Count -gt 0) { Write-Host "Waiting for delete:`n$($arns -join "`n")" while ($arns.Length -gt 0) { Start-Sleep -Seconds 5 foreach ($arn in $arns) { $stack = Get-CFNStack -StackName $arn @credentialArguments if ($endStates -icontains $stack.StackStatus) { $arns = $arns | Where-Object { $_ -ine $arn } if ($stack.StackStatus -like 'DELETE_FAILED') { Write-Host -ForegroundColor Red -BackgroundColor Black "Delete failed: $arn" Write-Host -ForegroundColor Red -BackgroundColor Black "$($stack.StackStatusReason)" Write-Host -ForegroundColor Red -BackgroundColor Black ( Get-StackFailureEvents -StackName $StackName -CredentialArguments $credentialArguments | Where-Object { $_.Timestamp -ge $deleteBegin } | Sort-Object -Descending Timestamp | Out-String ) } else { Write-Host "Delete complete: $arn" $arn } } } } } else { $arns } } } |