Last active
June 8, 2023 01:50
-
-
Save lukemurraynz/367e94e408ffafce7eb55a643a364ee3 to your computer and use it in GitHub Desktop.
Deletes all resource groups under a management group except for the ones with a specific tag.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This runbook deletes all resource groups under a management group except for the ones with a specific tag. | |
<# | |
.SYNOPSIS | |
Deletes all resource groups under a management group except for the ones with a specific tag. | |
.DESCRIPTION | |
This script deletes all resource groups under a specified management group except for the ones with a specific tag. It can also delete policy assignments and subscription role assignments if specified. | |
.PARAMETER ManagementGroupId | |
The ID of the management group to delete resource groups under. WARNING: This script will delete all resource groups under the specified management group except for the ones with the specified tag. Make sure you have specified the correct management group ID, or you may accidentally delete resources that you did not intend to delete. | |
.PARAMETER TagName | |
The name of the tag to check for. WARNING: This script will delete all resource groups that do not have this tag. Make sure you have specified the correct tag name, or you may accidentally delete resources that you did not intend to delete. | |
.PARAMETER RemoveResourceGroups | |
If specified, deletes the resource groups that do not have the specified tag. | |
.PARAMETER DeletePolicyAssignments | |
If specified, deletes the policy assignments for the management group and all child subscriptions. | |
.PARAMETER DeleteSubRoleAssignments | |
If specified, deletes the subscription role assignments for all child subscriptions. | |
.EXAMPLE | |
.\Initiate-DakaraSuperWeapon.ps1 -ManagementGroupId "my-management-group" -TagName "my-tag" -RemoveResourceGroups -DeletePolicyAssignments -DeleteSubRoleAssignments | |
Deletes all resource groups under the "my-management-group" management group that do not have the "my-tag" tag, and deletes the policy assignments and subscription role assignments for all child subscriptions. | |
.NOTES | |
This script requires the Azure PowerShell module to be installed. It also requires Owner rights (or User Administrator role) in order to remove roles from a subscription. Make sure your rights are set to be inherited from a management group before running this script. | |
#> | |
param ( | |
[Parameter(Mandatory = $true, HelpMessage = "The ID of the management group to delete resource groups under. WARNING: This script will delete all resource groups under the specified management group except for the ones with the specified tag. Make sure you have specified the correct management group ID, or you may accidentally delete resources that you did not intend to delete.")] | |
[string]$ManagementGroupId, | |
[Parameter(Mandatory = $true, HelpMessage = "The name of the tag to check for. WARNING: This script will delete all resource groups that do not have this tag. Make sure you have specified the correct tag name, or you may accidentally delete resources that you did not intend to delete.")] | |
[string]$TagName, | |
[Parameter(Mandatory = $false)] | |
[switch][bool]$RemoveResourceGroups = $false, | |
[Parameter(Mandatory = $false)] | |
[switch][bool]$DeletePolicyAssignments = $false, | |
[Parameter(Mandatory = $false, HelpMessage = "This will need Owner rights (or User Administrator role) in order to remove roles from a Subscription. Make sure your rights are set to be inherited from an Management Group, before running this.")] | |
[switch][bool]$DeleteSubRoleAssignments = $false | |
) | |
# Convert string values to boolean values | |
$RemoveResourceGroups = [System.Boolean]::Parse($RemoveResourceGroups) | |
$DeletePolicyAssignments = [System.Boolean]::Parse($DeletePolicyAssignments) | |
$DeleteSubRoleAssignments = [System.Boolean]::Parse($DeleteSubRoleAssignments) | |
# Ensures you do not inherit an AzContext in your runbook | |
Disable-AzContextAutosave -Scope Process | |
#Toggle to stop warnings with regards to Breaking Changes in Azure PowerShell | |
Set-Item -Path Env:\SuppressAzurePowerShellBreakingChangeWarnings -Value $true | |
# Connect to Azure with system-assigned managed identity | |
(Connect-AzAccount -Identity).context | |
# Write an initial log message | |
Write-Output "Initilizing superweapon...." | |
# Get the subscription IDs under the specified management group AND child management groups | |
function Get-AzSubscriptionsFromManagementGroup { | |
param($ManagementGroupName) | |
$mg = Get-AzManagementGroup -GroupId $ManagementGroupName -Expand | |
foreach ($child in $mg.Children) { | |
if ($child.Type -match '/managementGroups$') { | |
Get-AzSubscriptionsFromManagementGroup -ManagementGroupName $child.Name | |
} | |
else { | |
$child | Select-Object @{N = 'Name'; E = { $_.DisplayName } }, @{N = 'Id'; E = { $_.Name } } | |
} | |
} | |
} | |
$mgid = Get-AzManagementGroup -GroupId $ManagementGroupID -Expand | |
$subIds = (Get-AzSubscriptionsFromManagementGroup -ManagementGroupName $mgid.DisplayName).id | |
# Delete the policy assignments | |
if ($DeletePolicyAssignments -eq $true) { | |
Write-Output "Deleting management group policy assignments..." | |
Get-AzPolicyAssignment -Scope $mgid.Id | Remove-AzPolicyAssignment -Verbose | |
Write-Output "Deleting subscription group policy assignments..." | |
foreach ($subId in $subIds) { | |
Write-Output "Setting subscription context..." | |
Set-AzContext -Subscription $subId | |
Write-Output "Deleting subscription group policy assignments..." | |
Get-AzPolicyAssignment -Scope "/subscriptions/$($subId)" | Remove-AzPolicyAssignment -Verbose | |
} | |
} | |
else { | |
Write-Output "Skipping policy assignment deletion..." | |
} | |
# Delete the resource groups | |
if ($RemoveResourceGroups -eq $true) { | |
Write-Output "Deleting resource groups..." | |
if ($null -ne $subIds -and $subIds.Count -gt 0) { | |
foreach ($subId in $subIds) { | |
Write-Output "Setting subscription context..." | |
Set-AzContext -Subscription $subId | |
$ResourceGroupsfordeletion = Get-AzResourceGroup | Where-Object { $_.Tags -eq $null -or $_.Tags.ContainsKey($tagName) -eq $false } | |
Write-Output "The following Resource Groups will be deleted..." | |
Write-Output -InputObject $ResourceGroupsfordeletion | |
## Checks to see if a Recovery Services Vaults exists, the Recovery Services Vault and backups need to be deleted first. | |
$RSV = Get-AzRecoveryServicesVault | Where-Object { $_.ResourceGroupName -in $ResourceGroupsfordeletion.ResourceGroupName } | |
if ($null -ne $RSV) { | |
ForEach ($RV in $RSV) { | |
Write-Output "Backup Vault deletion supports deletion of Azure VM backup vaults ONLY currently." | |
#Credit to Wim Matthyssen for reference in the backup section of the script - https://wmatthyssen.com/2020/11/17/azure-backup-remove-a-recovery-services-vault-and-all-cloud-backup-items-with-azure-powershell/ | |
Set-AzRecoveryServicesVaultProperty -Vault $RV.ID -SoftDeleteFeatureState Disable | |
Set-AzRecoveryServicesVaultContext -Vault $RV | |
$containerSoftDelete = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM | Where-Object { $_.DeleteState -eq "ToBeDeleted" } | |
foreach ($item in $containerSoftDelete) { | |
Undo-AzRecoveryServicesBackupItemDeletion -Item $item -Force -Verbose | |
} | |
$containerBackup = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM | Where-Object { $_.DeleteState -eq "NotDeleted" } | |
foreach ($item in $containerBackup) { | |
Disable-AzRecoveryServicesBackupProtection -Item $item -RemoveRecoveryPoints -Force -Verbose | |
} | |
Remove-AzRecoveryServicesVault -Vault $RV -Verbose | |
} | |
} | |
## Checks to see if a Azure Resource Mover resource exists, as this need to be deleted first. | |
$ARM = Get-AzResource | Where-Object { $_.ResourceGroupName -in $ResourceGroupsfordeletion.ResourceGroupName -and $_.ResourceType -eq 'Microsoft.Migrate/moveCollections' } | |
Write-Output -InputObject $ARM | |
if ($null -ne $ARM) { | |
ForEach ($RM in $ARM) { | |
Write-Output "Azure Resource Mover collections exists." | |
Write-Output -InputObject $RM | |
$a = Get-AzResourceMoverMoveResource -ResourceGroupName $RM.ResourceGroupName -MoveCollectionName $RM.Name | |
Foreach ($b in $a) { | |
Write-Output -InputObject $b | |
# Remove a resource using the resource ID | |
Invoke-AzResourceMoverDiscard -ResourceGroupName $RM.ResourceGroupName -MoveResourceInputType $b.Id -MoveResource $b.Name | |
Remove-AzResourceMoverMoveResource -ResourceGroupName $RM.ResourceGroupName -MoveCollectionName $RM.Name -Name $b.Name -Verbose | |
} | |
Remove-AzResourceMoverMoveCollection -ResourceGroupName $RM.ResourceGroupName -MoveCollectionName $RM.Name | |
} | |
} | |
Write-Output "Deleting resource groups..." | |
$ResourceGroupsfordeletion | ForEach-Object -Parallel { | |
Remove-AzResourceGroup -Name $_.ResourceGroupName -Force | |
} -ThrottleLimit 20 -Verbose | |
# Remove the Network Watcher resource group - if remaining - in some scenarios the script left this RG behind. | |
# Get the resource group with the specified tag | |
$networkWatcherRG = Get-AzResourceGroup | Where-Object { $_.ResourceGroupName -eq 'NetworkWatcherRG' } | |
if ($null -ne $networkWatcherRG -and $null -ne $networkWatcherRG.Tags -and $networkWatcherRG.Tags.ContainsKey($tagName) -eq $false) { | |
Remove-AzResourceGroup -Name $networkWatcherRG.ResourceGroupName -Force -ErrorAction Continue -Verbose | |
} | |
} | |
# Write a final log message | |
Write-Output "Resource group deletion process completed." | |
} | |
else { | |
Write-Output "No child subscriptions found under the specified management group." | |
} | |
} | |
else { | |
Write-Output "Skipping resource group deletion..." | |
} | |
if ($DeleteSubRoleAssignments -eq $true) { | |
if ($null -ne $subIds -and $subIds.Count -gt 0) { | |
foreach ($subId in $subIds) { | |
Write-Output "Setting subscription context..." | |
Set-AzContext -Subscription $subId | |
$roleAssignments = Get-AzRoleAssignment -Scope "/subscriptions/$($subId)" -IncludeClassicAdministrators | |
Write-Output -InputObject $roleAssignments | |
# Loop through each role assignment and delete it if it is not inherited a management group | |
foreach ($roleAssignment in $roleAssignments) { | |
if ($roleAssignment.Scope -like "/subscriptions/*" -and $null -ne $roleAssignment.ObjectId -and $roleAssignment.ObjectId -ne "") { | |
Write-Output "Deleting role assignment..." | |
Remove-AzRoleAssignment -Scope $roleAssignment.Scope -ObjectId $roleAssignment.ObjectId -RoleDefinitionName $roleAssignment.RoleDefinitionName -Verbose -ErrorAction Continue | |
} | |
} | |
Write-Output "Deleting subscription role assignments..." | |
} | |
} | |
} | |
else { | |
Write-Output "Skipping policy subscription role assignments deletion..." | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment