Public/func_Remove-TemplatePlatform.ps1
|
Function Remove-TemplatePlatform { <# .SYNOPSIS Removes a platform runtime instance. .DESCRIPTION Remove Azure resources for a CDF template platform. .PARAMETER CdfConfig The CDFConfig object that holds the current scope configuration .PARAMETER DryRun Shows what resources would be removed when command is run. .INPUTS CDFConfig .EXAMPLE PS> $config = Get-CdfConfigPlatform PS> Remove-CdfTemplatePlatform ` -CdfConfig $config ` -DryRun PS> Remove-CdfTemplatePlatform ` -CdfConfig $config .LINK Deploy-CdfTemplatePlatform Get-CdfConfigPlatform #> [CmdletBinding()] Param( [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [Object]$CdfConfig, [Parameter(Mandatory = $false)] [switch] $DryRun ) Begin { if (-not (Get-Module Az.ResourceGraph -ListAvailable)) { Install-Module -Name Az.ResourceGraph -Scope CurrentUser -Force } Import-Module -Force -Name Az.ResourceGraph } Process { if ($CdfConfig.Platform.IsDeployed -eq $false) { $errMsg = 'Provided platform configuration is not deployed versions.' Write-Warning -Message $errMsg # Write-Error -Message $errMsg # throw $errMsg } $region = $CdfConfig.Platform.Env.region $regionCode = $CdfConfig.Platform.Env.regionCode $platformKey = "$($CdfConfig.Platform.Config.platformId)$($CdfConfig.Platform.Config.instanceId)" $platformEnvKey = "$platformKey$($CdfConfig.Platform.Env.nameId)" $templateInstance = "$platformKey-$regionCode" $templateEnvInstance = "$platformEnvKey-$regionCode" $deploymentName = "platform-$templateEnvInstance" $azCtx = Get-CdfAzureContext -SubscriptionId $CdfConfig.Platform.Env.subscriptionId Write-Host "Starting removal of platform resources for '$templateInstance' at '$region' within subscription [$($azCtx.Subscription.Name)]." Write-Host "-- Begin Phase #1 (Resources without dependencies) -----------------------" $azJobs = @() # Remove resources in Phase #1 - exclude those that fail on dependencies in first run. $excludedResoureTypeP1 = ' "Microsoft.Compute/disks"' # Must have virtual machine removed first. $excludedResoureTypeP1 += ', "Microsoft.Network/publicIPAddresses"' # Resources using Public IPs always have to be removed first $excludedResoureTypeP1 += ', "Microsoft.Network/privateDnsZones"' # Any Virtual Network Links have to be removed first $excludedResoureTypeP1 += ', "Microsoft.Network/virtualNetworks/subnets"' # Network specific $excludedResoureTypeP1 += ', "Microsoft.Network/networkSecurityGroups"' # Network specific, after subnet $excludedResoureTypeP1 += ', "Microsoft.Network/routeTables"' # Network specific, after subnet $query = "Resources " $query += " | where not(type in~ ( $excludedResoureTypeP1 )) " $query += " | where type != 'Microsoft.Network/VirtualNetwork' " # Explicitly exclude virtual networks not accidentally remove spoke vnet. $query += " | where tags.TemplateScope=~'$($CdfConfig.Platform.Config.templateScope)' " $query += " and tags.TemplateName=~'$($CdfConfig.Platform.Config.templateName)' " $query += " and tags.TemplateVersion=~'$($CdfConfig.Platform.Config.templateVersion)' " $query += " and tags.TemplateEnv=~'$($CdfConfig.Platform.Env.definitionId)' " $query += " and tags.TemplateInstance=~'$templateInstance' " $query += " | project id, name, tags " $resourcesP1 = Search-AzGraph -DefaultProfile $azCtx -Query $query $allResources = $resourcesP1 foreach ($resource in $resourcesP1) { Write-Host "`tRemoving resource $($resource.Name)" if ($false -eq $DryRun) { Write-Verbose " resource id: $($resource.Id)" $azJobs += Remove-AzResource ` -DefaultProfile $azCtx ` -ResourceId $resource.Id ` -Force ` -AsJob } } # Wait for jobs to complete if ($azJobs.Length -gt 0) { if ($true -eq $DryRun) { Write-Error "Dry-run, but still found jobs." } Write-Host -NoNewline "`tWaiting for jobs to complete" $azJobs | ForEach-Object { Write-Host -NoNewline "." $_ | Receive-Job -Wait -AutoRemoveJob -Force -ErrorAction:Continue | Out-Null } Write-Host " Done." } Write-Host "-- End Phase #1" # $azJobs = @() # $query = "Resources " # $query += " | where type != 'Microsoft.Network/VirtualNetwork' " # $query += " | where tags.TemplateScope=~'$($CdfConfig.Platform.Config.templateScope)' " # $query += " and tags.TemplateName=~'$($CdfConfig.Platform.Config.templateName)' " # $query += " and tags.TemplateVersion=~'$($CdfConfig.Platform.Config.templateVersion)' " # $query += " and tags.TemplateEnv=~'$($CdfConfig.Platform.Env.definitionId)' " # $query += " and tags.TemplateInstance=~'$templateInstance' " # $query += " | project id, name, tags " # $resources = Search-AzGraph -DefaultProfile $azCtx -Query $query # foreach ($resource in $resources) { # Write-Host "Removing resource $($resource.Name)" # if ($false -eq $DryRun) { # Write-Verbose " resource id: $($resource.Id)" # $azJobs += Remove-AzResource ` # -DefaultProfile $azCtx ` # -ResourceId $resource.Id ` # -Force ` # -AsJob # } # } # Start second phase $azJobs = @() Write-Host "-- Begin Phase #2 (Resource Groups, Networks, Dependencies) -----------------------" # Remove Platform resource groups Write-Verbose "Phase #2 (Resource Group)" $query = "ResourceContainers " $query += " | where type =~ 'Microsoft.Resources/subscriptions/resourceGroups' " $query += " | where tags.TemplateScope=~'$($CdfConfig.Platform.Config.templateScope)' " $query += " and tags.TemplateName=~'$($CdfConfig.Platform.Config.templateName)' " $query += " and tags.TemplateVersion=~'$($CdfConfig.Platform.Config.templateVersion)' " $query += " and tags.TemplateEnv=~'$($CdfConfig.Platform.Env.definitionId)' " $query += " and tags.TemplateInstance=~'$templateInstance' " $query += " | project id, name, tags " $resourceGroups = Search-AzGraph -DefaultProfile $azCtx -Query $query Write-Verbose "Phase #2 (Resource Group) Query: " Write-Verbose $query foreach ($resourceGroup in $resourceGroups) { $locked = Get-AzResourceLock -DefaultProfile $azCtx -ResourceGroupName $resourceGroup.Name if (!$locked) { # Recovery Service Vault require specific removal procedures and will block resource group removal if not deleted. $query = "Resources " $query += " | where type =~ 'Microsoft.RecoveryServices/vaults' " $query += " | where resourceGroup =~'$($resourceGroup.Name)' " $query += " | project id, name, resourceGroup, tags " Write-Verbose "Phase #2 (Recovery Services Vault) Query: " Write-Verbose $query $rsvResources = Search-AzGraph -DefaultProfile $azCtx -Query $query $allResources += $rsvResources $rsvResources | ForEach-Object -Process { Write-Host "`tRemoving recovery services vault $($_.Name)" if ($false -eq $DryRun) { Write-Verbose " recovery services id: $($_.Id)" $CdfConfig | Remove-RecoveryServicesVault -VaultName $_.Name -ResourceGroup $_.ResourceGroup } } Write-Host "`tRemoving resource group $($resourceGroup.Name)" if ($false -eq $DryRun) { Write-Verbose " resource group id: $($resourceGroup.Id)" $azJobs += Remove-AzResource ` -DefaultProfile $azCtx ` -ResourceId $resourceGroup.Id ` -Force ` -AsJob } } else { Write-Host "`tLeaving locked resource group: $($resourceGroup.Name)" } } Write-Verbose "Phase #2 End (Resource Group)" if ($CdfConfig.Platform.IsDeployed) { # Get Network Configuration and clean up $vNetRGName = $CdfConfig.Platform.ResourceNames.networkingResourceGroupName $vNetName = $CdfConfig.Platform.ResourceNames.alzSpokeVNetName if ($vNetRGName -and $vNetName) { Write-Verbose "Phase #2 Begin (Networking)" $vNet = Get-AzVirtualNetwork ` -DefaultProfile $azCtx ` -Name $vNetName ` -ResourceGroupName $vNetRGName if ($null -ne $vNet) { # Remove subnets $CdfConfig.Platform.ResourceNames.GetEnumerator() | Where-Object Key -like '*SubNetName*' | ForEach-Object -Process { if ($vNet -and $vNet.Subnets -and ($vNet.Subnets | Foreach-Object -Process { $_.Name }).Contains($_.Value)) { Write-Host "`tRemoving Subnet [$($_.Value)] of vnet [$($vNet.Name)]" if ($false -eq $DryRun) { Remove-AzVirtualNetworkSubnetConfig ` -DefaultProfile $azCtx ` -VirtualNetwork $vNet ` -Name $_.Value ` | Set-AzVirtualNetwork | Out-Null } } } } Write-Verbose "Phase #2 End (Networking)" } } else { Write-Warning "Network resources may not have been removed (Application config is not deployed version)" } # Remove resources in Phase #2 - those that were not removed in first run. $query = "Resources " $query += " | where type != 'Microsoft.Network/VirtualNetwork' " # Explicitly exclude virtual networks not accidentally remove spoke vnet. $query += " | where tags.TemplateScope=~'$($CdfConfig.Platform.Config.templateScope)' " $query += " and tags.TemplateName=~'$($CdfConfig.Platform.Config.templateName)' " $query += " and tags.TemplateVersion=~'$($CdfConfig.Platform.Config.templateVersion)' " $query += " and tags.TemplateEnv=~'$($CdfConfig.Platform.Env.definitionId)' " $query += " and tags.TemplateInstance=~'$templateInstance' " $query += " | project id, name, tags " $resourcesP2 = Search-AzGraph -DefaultProfile $azCtx -Query $query $allResources += $resourcesP2 foreach ($resource in $resourcesP2) { Write-Host "`tRemoving resource $($resource.Name)" if ($false -eq $DryRun) { Write-Verbose " resource id: $($resource.Id)" $azJobs += Remove-AzResource ` -DefaultProfile $azCtx ` -ResourceId $resource.Id ` -Force ` -AsJob } } # Remove deployment Write-Host "Removing deployment [$deploymentName]" if ($false -eq $DryRun) { Remove-AzDeployment -DefaultProfile $azCtx -Name $deploymentName -ErrorAction SilentlyContinue } if ($azJobs.Length -gt 0) { if ($true -eq $DryRun) { Write-Error "Dry-run, but still found jobs." } Write-Host -NoNewline "Waiting for long running jobs such as removing resource groups to complete " $azJobs | ForEach-Object { Write-Host -NoNewline "." $_ | Receive-Job -Wait -AutoRemoveJob -Force | Out-Null } Write-Host " Done." } if ($CdfConfig.Platform.Config.configStoreType -and $false -eq $DryRun) { $regionDetails = [ordered] @{ region = $region code = $regionCode name = $region } Remove-ConfigFromStore ` -CdfConfig $CdfConfig ` -Scope 'Platform' ` -EnvKey $platformEnvKey ` -RegionDetails $regionDetails ` -ErrorAction Continue } } End { } } |