In Azure, resource groups are very helpful to logically hold together a set of resources. For many reasons, at some point, you'll want to get rid of these resources but how can you achieve this and what are the pros and cons of each?

This is an actualized version of my popular post:
Effective ways to delete resources in a resource group on Azure

We'll cover Az PowerShell modules, Azure CLI, ARM template and Bicep. In my previous article I was speaking about three ways of doing this, in this article I'll stick with two, I dropped custom scripting. You have the link above, feel free to go check it if you're after a custom way to delete resources within a resource group.

You have basically two options depending on the end result you want. Both are effortless, it simply comes to: Do you want to delete it? Or only purge the resources inside?

Delete the resource group

It is the simplest, it deletes everything.

Advantages

  • No custom logic is required

To consider

  • All resources inside the resource group will be deleted
  • The resource group will be deleted (losing RBAC & Tags)
Remove-AzResourceGroup -Name MyResourceGroup -Verbose

After a few minutes, your resources and their container will be deleted.

Wait... What if I don't want to delete the resource group?

Deleting the resource group directly is the quickest way to remove all the resources inside it but you'll also delete the container itself. What are your options if you want to preserve the resource group ?

Purge the resource group

If you are looking for a way to keep the resource group but want all the resources inside it deleted, this last option is for you.

Advantages

  • No custom logic or dependency walking is required
  • Keep the resource group intact (including RBAC & Tags)
  • Native parallel delete support of non-dependent resources

To consider

  • All resources inside the resource group will be deleted

In Azure, you have the option of deploying resources using a template. You have two modes available when initiating a deployment:

Incremental: You can see this mode as "Additive". What I mean is that non-existing resources declared in your template will be added. Existing resources will be modified only if there is a difference between the actual version and what is declared in your template. Finally, if there's a resource in the resource group that is not present in the template, it will be ignored and left untouched.

Complete: You can see this mode as "Exact match". What I mean is that after your deployment is done, only the resources declared in your template will exist in the resource group. If there are existing resources in the resource group that are not present in the template, they will be deleted automatically.

Now that we understand what happens in "Complete" mode, we can use that to our advantage. We are looking for a way to purge all the resources in a resource group, without having to handle the complexity of resolving dependencies and parallel delete of resources. The trick, simple when you think about it, just ask the ARM engine to deploy an empty template (no resources) in an existing resource group in "Complete" mode. You'll end up exactly with the behavior we want.

We can do this with an ARM template containing no resources or an empty Bicep file.

Empty ARM template

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {   },
  "variables": {  },
  "resources": [  ],
  "outputs": {  }
}

Now, let's pretend the name of the ARM template is "ResourceGroupCleanup.template.jsonc".

A JSONC file is just a JSON file format that supports comments. Azure and Visual Studio code support this.

Empty Bicep file

Bicep is a DSL that is easier and compact to author than ARM templates (they are now considered more as an intermediate language - IL).

Knowing this, you don't have to remember the empty format of the ARM template. We just need to create an empty file, give it a bicep extension and you now have a lightweight ARM template.

$null > ResourceGroupCleanup.bicep
In order to deploy bicep files thru PowerShell or Azure CLI, you'll need a recent, 2021 version of them. In this article I've used Az 5.8.0 and Azure CLI 2.22.1

Powershell

Here is how to invoke the deployment in "Complete" mode in PowerShell.

# ARM template
New-AzResourceGroupDeployment -ResourceGroupName MyResourceGroup -Mode Complete -TemplateFile .\ResourceGroupCleanup.template.json -Force -Verbose

# Bicep
New-AzResourceGroupDeployment -ResourceGroupName MyResourceGroup -Mode Complete -TemplateFile .\ResourceGroupCleanup.bicep -Force -Verbose

After you run this command, you should have something similar to the following:

Azure-CLI

Here is how to invoke the deployment in "Complete" mode on a resource group in Azure CLI v2.22.1 or later.

az deployment group create -g MyResourceGroup -f .\ResourceGroupCleanup.bicep --mode Complete

After you run this command, you should have something similar to the following:

Hope you have fun with Azure Resource Manager and automation!

References