Azure Tip 7: Bulk Deleting and Purging Azure Resource Groups

Posted by

During the delivery of my Azure training sessions, I often end up with a lot of resource groups. Deleting many resource groups at once would be a good tool. Here are 3 solutions:

  • Delete multiple resource groups with Powershell
  • Delete multiple resource groups with Azure CLI
  • Purge resource groups with Powershell

WARNING:

Deleting a resource group is permanent. Once you delete a group, nobody can bring it back. And I mean NOBODY!!

The approaches that I describe here could make you delete EVERYTHING YOU HAVE. So please proceed with caution.

That said, lets get started:

Option 1: Delete Multiple Resource Groups via Powershell

For these examples to work, you need a locally installed powershell with the Az Azure Modules and you need to be connected to a subscription using Connect-AzAccount.

You might know that you can delete a resource group with powershell using the Remove-AzResourceGroup cmdlet, as so:

Remove-AzResourceGroup -Name "rg-az204-mme-001"

However, this approach kinda sucks because of 3 reasons:

  • It deletes only one resource group
  • It asks you if you are sure
  • It runs synchronously and blocks your session until its completed. And you know how long that could take.

Of course, we can solve 2 of these problems using the -AsJob (= execute asynchronously) and -Force (= trust me, I know what I am doing) switches:

Remove-AzResourceGroup -Name "rg-az204-mme-001" -AsJob -Force

The interesting part is how to delete multiple resource groups. And of course I want to know which ones are in question. Here is how I do it:

  1. Use a filter string and query the resource groups
#Use a filter to select resource groups by substring
$filter = 'az204'

#Find Resource Groups by Filter -> Verify Selection
Get-AzResourceGroup | ? ResourceGroupName -match $filter | Select-Object ResourceGroupName

2. Make sure these are the resource groups you REALLY want to delete.
3. Run the same query but pipe the result to Remove-AzResourceGroup with the -AsJob and -Force parameters.

#Async Delete ResourceGroups by Filter. Uncomment the following line when you are sure. :-)
#Get-AzResourceGroup | ? ResourceGroupName -match $filter | Remove-AzResourceGroup -AsJob -Force

And that is it. The resource groups that you selected will be deleted in the background. Here is the full script: Note that I wrote the dangerous part as a comment. Execute

#Use a filter to select resource groups by substring
$filter = 'az204'

#Find Resource Groups by Filter -> Verify Selection
Get-AzResourceGroup | ? ResourceGroupName -match $filter | Select-Object ResourceGroupName

#Async Delete ResourceGroups by Filter. Uncomment the following line if you understand what you are doing. :-)
# Get-AzResourceGroup | ? ResourceGroupName -match $filter | Remove-AzResourceGroup -AsJob -Force


Option 2: Delete multiple Resource Groups using the Azure CLI

Please note that the full CLI statement including the FOR loop will only work on a real bash console. If you are running Azure CLI inside Powershell, the full statement will not work!

For these examples to work, you need to be connected to a subscription using “az login”.

The steps that I propose for the Azure CLI variant are very similar to the steps for PowerShell.

First, we select the resource groups to be deleted. We can do this by submitting a filter query in JMESPath syntax to our cli command. This will give us the list of resource groups to be deleted.

We use the contains() method to filter, the [].{name:name} to project and -o tsv to format the results as tab separated.

az group list --query "[? contains(name,'rg-az204-mme')][].{name:name}" -o tsv

Once we are sure that we selected the correct resource groups, we add the query to a for loop.

for rgname in `az group list --query "[? contains(name,'rg-az204-mme')][].{name:name}" -o tsv`; do
echo Deleting ${rgname}
az group delete -n ${rgname} --yes --no-wait
done

And that is it. Our resource groups are being deleted asynchronously.

Option 3: Purge Resource Groups using an ARM Template and Powershell

There is not really a possibility to “purge” a resource group. But sometimes, you do not want to completely remove the resource group. One reason could be that you have RBAC Role Assignment on the group that you do not want to lose.

A very nice workarkound is to use an empty ARM templates. ARM templates are executed in “Incremental” mode by default. That means:

  • Existing resources that are not in the template will not be touched.
  • New resources in the template will be created.
  • Existing resources that are in the template will be updated.

However, when you submit a deployment, you can change the deployment mode to “Complete”:

We can use this trick to purge a resource group (delete all the resources but not the group).

To make things simple, we do everything in powershell and not use a separate template file. First, we need an empty template:

$emptyARMTemplate = @{
    '$schema' = 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#'
    contentVersion = '1.0.0.0'
    resources = @()
    }

Then we create a new Resource Group Deployment:

New-AzResourceGroupDeployment -Name PurgeResourceGroup `
    -ResourceGroupName "rg-az204-mme-001" `
    -TemplateObject $emptyARMTemplate `
    -Mode Complete -AsJob -Force

And the full script is:

$emptyARMTemplate = @{
    '$schema' = 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#'
    contentVersion = '1.0.0.0'
    resources = @()
    }

New-AzResourceGroupDeployment -Name PurgeResourceGroup `
    -ResourceGroupName "rg-az204-mme-001" `
    -TemplateObject $emptyARMTemplate `
    -Mode Complete -AsJob -Force

Of course, you can combine both approaches and as well purge a list of resource groups:

#Use a filter to select resource groups by substring
$filter = 'rg-az204-'

#Find Resource Groups by Filter -> Verify Selection
Get-AzResourceGroup | ? ResourceGroupName -match $filter | Select-Object ResourceGroupName


#!!!#
#Continue only if you are sure...
 $emptyARMTemplate = @{
    '$schema' = 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#'
    contentVersion = '1.0.0.0'
    resources = @()
    }

$selectedResourceGroups = Get-AzResourceGroup | ? ResourceGroupName -match $filter | Select-Object ResourceGroupName

foreach($g in $selectedResourceGroups)
{
    New-AzResourceGroupDeployment -Name PurgeResourceGroup `
        -ResourceGroupName $g `
        -TemplateObject $emptyARMTemplate `
        -Mode Complete -AsJob -Force
}

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.