Manage Azure Tags using PowerShell or Azure CLI

Use tags for your Azure resources, resource groups, and subscriptions to logically organize them into a taxonomy. Tag consists of a name and a value pair. To apply tags to a resource, you must have write access to the Microsoft.Resources/tags resource type.

Many Azure users apply tags to their resources such as a cost center or development environment (production and test) to better categorize charges. Tags appear as a dimension in cost analysis. You can use the dimension to gain insights into your custom tagging categorizations.


In this article I will use both PowerShell and Azure CLI to manage Tags. Lets start with installing latest Powershell Az module.

#Install the Azure PowerShell module
Install-Module -Name Az -AllowClobber
Get-InstalledModule -Name Az -AllVersions

# Connect to subscription
Login-AzAccount -SubscriptionId "<subscription id>"

# Get subscription id if you not have
Get-AzSubscription
# Chose subscrption to login
Select-AzSubscription -SubscriptionId "<subscriptionid>"

#which subscription your commands are run against
Get-AzContext

#To change your working context to a different subscription
Set-AzContext -SubscriptionId <subscriptionid>

#########################################################
#######################   TAGS   ########################
#########################################################
#To see the existing tags for a resource group
Get-AzTag -Name "IT"
(Get-AzResourceGroup -Name examplegroup).Tags
# In Azure CLI
az group show -n examplegroup --query tags

#To get resources that have a specific tag
(Get-AzResource -Tag @{ Creator="Hasnain"}).Name
# In Azure CLI
az group list --tag Dept=IT

# Get Values of specific Tag Key (XYZ_Environment)
(get-azTag -Name XYZ_Environment).Values

#To get resources that have a specific tag name
Get-AzResource -TagName 'Creator' | FT Name,ResourceGroupName
az resource list --tag Dept=Finance

#To see the existing tags for a resource that has a specified resource ID or resource name
(Get-AzResource -ResourceId /subscriptions/<subscription-id>/resourceGroups/<rg-name>/providers/Microsoft.Storage/storageAccounts/<storage-name>).Tags
(Get-AzResource -Name "<resourcename>").Tags
# In Azure CLI
az resource show -n examplevnet -g examplegroup --resource-type "Microsoft.Network/virtualNetworks" --query tags
az resource show --id <resource-id> --query tags

#To add tags to a resource without existing tags, use:
$r = Get-AzResource -ResourceName examplevnet -ResourceGroupName examplegroup
Set-AzResource -Tag @{ Dept="IT"; Environment="Test" } -ResourceId $r.ResourceId -Force

# get resource which is not having any Tag
Get-AzResource | ? Tags -eq $null | select Name, ResourceType

# get resource which is not having Tag XYZ_Environment
Get-AzResource | ? Tags.Name -ne "XYZ_Environment" | select Name, ResourceType | sort
#OR
Get-AzResource | Where-Object { $_.Name -notlike '*XYZ_Environment*'}| select Name, ResourceType | sort

#To add tags to a resource or group without existing tags
New-AzTag -Name "IT" -Value "Dev"  #create new tag
Set-AzResourceGroup -Name examplegroup -Tag @{ IT = 'Prod'}
Set-AzResourceGroup -Name examplegroup -Tag @{ Dept="IT"; Environment="Test" }
# In Azure CLI
az group update -n examplegroup --set tags.Environment=Test tags.Dept=IT
az resource tag --tags Dept=IT Environment=Test -g examplegroup -n examplevnet --resource-type "Microsoft.Network/virtualNetworks"

# NOTE: Every time you apply tags to a resource or a resource group, you overwrite the existing tags on that resource or resource group. Therefore, you must use a different approach based on whether the resource or resource group has existing tags
#To add tags to a resource group that has existing tags, retrieve the existing tags, add the new tag, and reapply the tags:

$tags = (Get-AzResourceGroup -Name examplegroup).Tags
$tags.Add("Status", "Approved")
Set-AzResourceGroup -Tag $tags -Name examplegroup
# In Azure CLI
jsonrtag=$(az resource show -g examplegroup -n examplevnet --resource-type "Microsoft.Network/virtualNetworks" --query tags)
rt=$(echo $jsonrtag | tr -d '"{},' | sed 's/: /=/g')
az resource tag --tags $rt Project=Redesign -g examplegroup -n examplevnet --resource-type "Microsoft.Network/virtualNetworks"

##### To Manage Tags to a resource that has existing tags #####

# Merge a new Tag in resource (filter from a specific Tag)
# NOTE: this is risky command and can change all Tags be careful
$oldtag = @{"Environment"="Prod"}
$newtagname = @{"XYZ_Environment"="Prod"}
Get-AzResource -Tag $oldtag | Update-AzTag -Tag $newtagname -Operation Merge

# Delete a Tag in resource (filter from a specific Tag)
# NOTE: this is risky command and can change all Tags be careful
$oldtag = @{"Environment"="Prod"}
Get-AzResource -Tag $oldtag | Update-AzTag -Tag $oldtag -Operation Delete

#To apply all tags from a resource group to its resources, and not keep existing tags on the resources
$groups = Get-AzResourceGroup
foreach ($g in $groups)
{
    Get-AzResource -ResourceGroupName $g.ResourceGroupName | ForEach-Object {Set-AzResource -ResourceId $_.ResourceId -Tag $g.Tags -Force }
}

groups=$(az group list --query [].name --output tsv)
for rg in $groups
do
  jsontag=$(az group show -n $rg --query tags)
  t=$(echo $jsontag | tr -d '"{},' | sed 's/: /=/g')
  r=$(az resource list -g $rg --query [].id --output tsv)
  for resid in $r
  do
    az resource tag --tags $t --id $resid
  done
done

#To apply all tags from a resource group to its resources, and keep existing tags on resources that aren't duplicates, use the following script
$group = Get-AzResourceGroup "examplegroup"
if ($null -ne $group.Tags) {
    $resources = Get-AzResource -ResourceGroupName $group.ResourceGroupName
    foreach ($r in $resources)
    {
        $resourcetags = (Get-AzResource -ResourceId $r.ResourceId).Tags
        if ($resourcetags)
        {
            foreach ($key in $group.Tags.Keys)
            {
                if (-not($resourcetags.ContainsKey($key)))
                {
                    $resourcetags.Add($key, $group.Tags[$key])
                }
            }
            Set-AzResource -Tag $resourcetags -ResourceId $r.ResourceId -Force
        }
        else
        {
            Set-AzResource -Tag $group.Tags -ResourceId $r.ResourceId -Force
        }
    }
}

groups=$(az group list --query [].name --output tsv)
for rg in $groups
do
  jsontag=$(az group show -n $rg --query tags)
  t=$(echo $jsontag | tr -d '"{},' | sed 's/: /=/g')
  r=$(az resource list -g $rg --query [].id --output tsv)
  for resid in $r
  do
    jsonrtag=$(az resource show --id $resid --query tags)
    rt=$(echo $jsonrtag | tr -d '"{},' | sed 's/: /=/g')
    az resource tag --tags $t$rt --id $resid
  done
done

#To remove all tags, pass an empty hash table:
Set-AzResourceGroup -Tag @{} -Name examplegroup
Remove-AzTag -Name "IT" #remove tag once it has been removed from all resources or groups


Post a Comment

Thanks for your comment !
I will review your this and will respond you as soon as possible.