Under Azure Resource Manager, 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?

You have basically three options depending on the end result you want. Some will require more effort than others but will give you more granular control over what is deleted or not.

UPDATE: 2018-06-28 - Replaced Find-AzureRmResource usage it do not exist anymore in Azure PowerShell 6.x+
UPDATE: 2016-06-01 - Azure CLI now support Complete mode

Delete the resource group

This one 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
Remove-AzureRmResourceGroup -Name MyResourceGroup -Verbose

After a few minutes, your resources and their container will be deleted
Remove-AzureRmResourceGroup

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 or want granular control over which resources will be deleted?

Enumerate and delete all the resources yourself

Advantages

  • Keep the resource group intact (including RBAC & Tags)
  • Ability to control which resources to keep (if required)

To consider

  • Requires custom logic to handle resources dependencies
  • Requires custom logic to handle parallel delete

Some coding skill is required here because you'll need to:

  • Enumerate all the resources under the resource group
  • [Optional] Filter out some resource types
  • [Optional] Handle resources dependencies
  • Delete the resources

In most cases your resources will have dependencies on others. When that happen, you'll need a dependency graph discovery mechanism or you can go with a simpler approach: an ordered list of resource types to perform the deletion properly.

A good example of resources depending on others to be the following: you cannot delete a storage account hosting the VHD of a virtual machine before deleting the VM itself.

Below is a sample script that will find and delete VM related resources in a resource group using a hard-coded resource type list. If you are dealing with other resource types, you can adjust the types in the array to control the deletion order of types. At the end of the array, there is a '*' that will remove any other resources not caught by the previous types, whenever they have a dependency or not. This is just a sample to give you an idea, you can start from here or go your own way. ;)

param(
  [Parameter(Position = 0, Mandatory = $true)]
  [string]
  $SubscriptionId,

  [Parameter(Position = 1, Mandatory = $true)]
  [string]
  $ResourceGroupName
)
$ErrorAction = 'Stop'

$null = Set-AzureRmContext -SubscriptionId $SubscriptionId

@(
  'Microsoft.Compute/virtualMachineScaleSets'
  'Microsoft.Compute/virtualMachines'
  'Microsoft.Storage/storageAccounts'
  'Microsoft.Compute/availabilitySets'
  'Microsoft.ServiceBus/namespaces'
  'Microsoft.Network/connections'
  'Microsoft.Network/virtualNetworkGateways'
  'Microsoft.Network/loadBalancers'
  'Microsoft.Network/networkInterfaces'
  'Microsoft.Network/publicIPAddresses'
  'Microsoft.Network/networkSecurityGroups'
  'Microsoft.Network/virtualNetworks'

  '*' # this will remove everything else in the resource group regarding of resource type
) | % {
  $odataQuery = "`$filter=resourcegroup eq '$ResourceGroupName'"

  if ($_ -ne '*') {
    $odataQuery += " and resourcetype eq '$_'"
  }

  $resources = Get-AzureRmResource -ODataQuery $odataQuery
  $resources | Where-Object { $_.ResourceGroupName -eq $ResourceGroupName } | % { 
    Write-Host ('Processing {0}/{1}' -f $_.ResourceType, $_.ResourceName)
    $_ | Remove-AzureRmResource -Verbose -Force
  }
}

Purge the resource group

In the previous option you got all the flexibility you want but it comes with a price, complexity and maintenance. 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

Under Azure Resource Manager 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.

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

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

Powershell

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

New-AzureRmResourceGroupDeployment -ResourceGroupName MyResourceGroup -Mode Complete -TemplateFile .\ResourceGroupCleanup.template.json -Force -Verbose

After you run this command, you should have something similar to the following:
Purge all resources in a resource group using PowerShell

Azure-CLI

Here is how to invoke the deployment in "Complete" mode in Azure CLI v0.10.0 or later.

azure group deployment create -g MyResourceGroup -f .\ResourceGroupCleanup.template.json -m Complete

After you run this command, you should have something similar to the following:
Purge all resources in a resource group using Azure-CLI

Hope you have fun with Azure Resource Manager and automation!

References