Keep your Azure Subscription for Development tidy

The tags

For our solution we came up with these 4 tags:

  • CreatedOnDate — creation date of the resource. This is automatically set by the policy as you will see (some resources like resource groups don’t have this property themselves).
  • OwnerEmail — the e-mail address of the owner for notifications. This is set manually in our case.
  • IsPermanent — indication whether this resource group must be kept at all times. This should only be used for carefully selected resource groups, e.g. the main deployment from your CI/CD pipelines. Set the value to ‘true’ to mark as permanent.
  • MaxExpirationDays — number of days this resource group needs to be kept active after the CreatedOnDate date. The default is set to 14 days, but this can be configured of course. And it can be modified manually to extend the expiration.

Setting up Azure Policies

Now we know which tags we want to use, we can setup the automatic creation of them for new Azure resources using Azure Policies. To do this using Azure Cli you can use this command to define the policy:

az policy definition create --name "Tag-CreatedOnDate" --display-name "Tag-CreatedOnDate" --mode 'All' --metadata "category=Tags" --rules "{ \"if\": {\"allOf\": [ { \"field\": \"tags['CreatedOnDate']\", \"exists\": \"false\" } ] }, \"then\": { \"effect\": \"append\", \"details\": [ { \"field\": \"tags['CreatedOnDate']\", \"value\": \"[utcNow()]\" } ] } }" --param "{}"
az policy assignment create --name "Tag-CreatedOnDate" --display-name "Tag-CreatedOnDate" --scope "/subscriptions/[subscription ID]" --policy "/subscriptions/[subscription ID]/providers/Microsoft.Authorization/policyDefinitions/Tag-CreatedOnDate"
az policy definition list --query "[?policyType=='Custom'&&contains()]"

The weekly process

In our project we created a pipeline running a script once a week to do a few things:

  • Delete all expired resource groups
  • Check all resource groups to expire in a week and notify owners
  • Validate the settings of the resource groups

The implementation of the script to check and delete resource groups

Using Azure Cli again you can use this command to get a list of all resource groups that match our conditions:

az group list --query "[?tags.IsPermanent!='true'].{Name:name,CreatedOn:tags.CreatedOnDate,MaxDays:tags.MaxExpirationDays,Owner:tags.OwnerEmail,IsPermanent:tags.IsPermanent}" -o tsv
az group list --query "[?tags.IsPermanent!='true'].{Name:name,CreatedOn:tags.CreatedOnDate,MaxDays:tags.MaxExpirationDays,Owner:tags.OwnerEmail,IsPermanent:tags.IsPermanent}" -o tsv |
while read -r Name CreatedOn MaxDays Owner IsPermanent; do
# handling per row here
# Use e.g. $Name for the resource group name
if [[ "$expirationDate" < "$checkdate" ]] || [[ "$expirationDate" == "$checkdate" ]]
# resource group expired
expired_list+=$(printf '%s\t%s\t%s\t%s\t%s\n\r' "$Name" "$CreatedOn" "$MaxDays" "$Owner" "$print_checkdate")
while read -r Name CreatedOn MaxDays Owner Expires; do
# handling per row here
# Use e.g. $Name for the resource group name
done <<<$expired_list
az group list --query "[?tags.MaxExpirationDays>='$thresholdExpirationDays'].{Name:name,CreatedOn:tags.CreatedOnDate,MaxDays:tags.MaxExpirationDays,Owner:tags.OwnerEmail}" -o tsv
./ -d -a "," -m "[subscription key]"
./ -c "$(date -d "+7 days")" -a "," -m "[subscription key]"

The pipeline

Now we have these scripts, we can setup an Azure DevOps Pipeline which runs on a schedule. We chose every Sunday evening at 10pm GMT. The secrets are coming from a key vault. The settings are coming from a template file:


Having this in place is saving us money and making people aware of what’s happening. Hope this will benefit you as well.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Martin Tirion

Martin Tirion


Senior Software Engineer at Microsoft working on Azure Services and Spatial Computing for enterprise customers around the world.