PowerShell for Assigning and Querying Tags in Azure

Tags in Azure are useful pieces of metadata for documenting (annotating) things such as:

  • Billing or cost center categories (ex: general ledger code)

  • Environment names (ex: Dev, Test, Prod, Sandbox)

  • Project or system

  • Purpose or application

  • Team, group, department, or business unit

  • Who owns or supports the resource

  • Release or version numbers (ex: for testing infrastructure)

  • Archival date (ex: if infrastructure is only needed temporarily)

  • Who initially created the resource

  • Which customer a resource applies to (ex: for an ISV)

  • Service level agreement

  • Patching or maintenance window

  • etc…

Tags are free-form key/value pairs. So, they can be used for tracking anything you find to be helpful. Tags are particularly helpful for breaking down invoicing costs. For instance, rather than seeing the entire cost for certain resources (like VMs or storage) in a resource group, tags allow you to subdivide the resource costs further, or to group costs in another way across resource groups. Here's what the tags look like when you download usage (the new V2 format) for your subscription:

You can assign tags for resource groups, as well as individual resources which support Azure Resource Manager. The individual resources do not automatically inherit tags from the resource group parent. A maximum of 15 key/value pairs can be assigned (though you could store concatenated values or embedded JSON in a single tag value as a workaround). You may want to just assign tags at just the resource group level, and use custom queries to "inherit" at the resource level. Alternatively, you may want to assign tags to the individual resources directly particularly if you want to see them clearly on the standard "download usage" report of billing.

Since the key/value pairs are just free-form text, watch out for uniformity issues. To improve consistency, you can utilize policies to require tags and/or apply defaults if you'd like (for example, you might want to enforce a "Created By" tag). Tags can be set in the ARM template when you initially deploy a resource (which is best so that no billing occurs without proper tagging), or afterwards to existing resources via the portal, PowerShell, or CLI.

The three tags I'm currently using in an implementation are Billing Category, Environment Type, and Support Contact:

 

The above screen shot shows setting tags within the portal. If you have more than a handful of resources, that won't be efficient at all. Following are a few PowerShell scripts to help with that setting tags.

Assign Tags to a Resource

This script will *overwrite* any and all tags previously assigned to one resource.

$resourceGroupName = 'InternalReportingRGDev'
$resourceName = 'bisqlvm1datastdstrgdev'

$azureResourceInfo = Find-AzureRmResource -ResourceGroupNameEquals $resourceGroupName -ResourceNameEquals $resourceName 

Set-AzureRmResource -Tag @{ billingCategory="Internal Analytics"; supportContact="Analytics Team"; environmentType="Dev" } -ResourceName $resourceName -ResourceType $azureResourceInfo.ResourceType -ResourceGroupName $resourceGroupName -Force 

Assign Tags to a Resource Group

This script will *overwrite* any and all tags previously assigned to one resource group.

$resourceGroupName = 'InternalReportingRGDev'

$azureRGInfo = Get-AzureRmResourceGroup -Name $resourceGroupName

Set-AzureRmResourceGroup -Id $azureRGInfo.ResourceId -Tag @{ billingCategory="Internal Analytics"; supportContact="Analytics Team"; environmentType="Dev" } 

Assign Tags to All Resources Within a Resource Group (Inherited from the RG)

This script will *overwrite* any and all tags previously assigned to one resource.

Updated 3/10/2019: change from Find-AzureRmResource which ended with PowerShell 5.7.0 to Get-AzureRmResource which is still supported in 6.13.0.

$resourceGroupName = 'InternalReportingRGDev'

$azureRGInfo = Get-AzureRmResourceGroup -Name $resourceGroupName
foreach ($item in $azureRGInfo) 
{
Get-AzureRmResource -ResourceGroupName $item.ResourceGroupName | ForEach-Object {Set-AzureRmResource -ResourceId $PSItem.ResourceId -Tag $item.Tags -Force } 
}

Add an Additional Tag to a Resource Group

This script adds a new tag and preserves existing tags for one resource group. It only accepts new tags (i.e., it will error out if you repeat existing tags).

$resourceGroupName = 'InternalReportingRGDev'

$azureRGTags = (Get-AzureRmResourceGroup -Name $resourceGroupName).Tags

$azureRGTags+= @{ billingCategory345="Internal Analytics" }

Set-AzureRmResourceGroup -Tag $azureRGTags-Name $resourceGroupName 

 

Query to Get List of Tag Names & Values for a Specific Resource

This checks for the tags assigned to one resource.

$resourceGroupName = 'InternalReportingRGDev'
$resourceName = 'bisqlvm1datastdstrgdev'

(Find-AzureRmResource -ResourceGroupNameEquals $resourceGroupName -ResourceNameEquals $resourceName).Tags

Output is a list of each Name/Value pair which has been assigned:

 

Query to Get List of Resource Groups With a Specific Tag Value Assigned

(Find-AzureRmResourceGroup -Tag @{ billingCategory="Internal Analytics" }).Name 

Output is a list of resource groups which have been assigned that tag name and value.

 

Query to Get List of Resources With a Specific Tag Value Assigned

(Find-AzureRmResource -Tag @{ environmentType="Dev" }).Name 

Output is a list of resources which have been assigned that tag name and value.

 

Query to Get List of Resources With a Tag Set Based on Tag Name

(Find-AzureRmResource -TagName 'billingCategory').Name 

Output is a list of which resources have a specific tag assigned (regardless of the tag's value).

 

You Might Also Like...

Naming Conventions in Azure

Getting Started with Azure

Setting Up Disk Encryption for a Virtual Machine with PowerShell