To list the tags in use in Azure, read the tags of every resource and resource group through Resource Graph and count each tag name and its values. Azure treats tag names without regard to case but keeps values as written, so Env and env are 1 tag, while Prod and prod are 2 values.
| Method | Best fit |
|---|---|
| PowerShell | A CSV of each tag name with how many resources and groups carry it and its values. |
| Admin centre | A quick look at the tags in use, and the resources that carry 1 of them. |
| Altivane | Recommended for regular tagging reviews, with the untagged resources listed beside the tags in use. |
Before you start
Use an Azure account with read access to the subscriptions you want to check. The built-in Reader role is enough to run Resource Graph queries; assign it at each subscription or a scope above. The Microsoft references list no separate Resource Graph licence.
Know what the count covers. The script reads resources and resource groups; subscriptions can carry tags too and are left out, and management groups can't be tagged. It leaves out tag names that start with hidden-, as Microsoft's own sample does. Resource Graph is a near real-time index, so a tag added a moment ago may not show yet. The examples read Azure and export a CSV; they don't add, rename or remove any tag. The script's finally block disconnects the account and clears its saved Azure contexts.
Option 1
List the tags in use with PowerShell
Install the modules once, sign in, and query the subscriptions the account can read. The script reads every tagged resource and resource group, then counts each tag name and its different values.
Install-Module -Name Az.Accounts, Az.ResourceGraph -Repository PSGallery -Scope CurrentUser$ErrorActionPreference = 'Stop'
Connect-AzAccount -ErrorAction Stop
try {
$subscriptionIds = @(
Get-AzSubscription | Where-Object State -eq 'Enabled' | Select-Object -ExpandProperty Id
)
if ($subscriptionIds.Count -eq 0) {
Write-Output 'No enabled subscriptions are available to this account.'
return
}
$groupType = '"microsoft.resources/subscriptions/resourcegroups"'
$queries = @(
'Resources | where isnotempty(tags) | project id, tags | order by id asc'
"ResourceContainers | where type =~ $groupType | where isnotempty(tags)" +
' | project id, tags | order by id asc'
)
$uses = [System.Collections.Generic.List[object]]::new()
foreach ($query in $queries) {
$skipToken = $null
do {
$arguments = @{ Query = $query; Subscription = $subscriptionIds; First = 1000 }
if ($skipToken) { $arguments.SkipToken = $skipToken }
$page = Search-AzGraph @arguments
foreach ($row in $page.Data) {
foreach ($tag in $row.tags.PSObject.Properties) {
if ($tag.Name -like 'hidden-*') { continue }
$uses.Add([pscustomobject]@{ Name = $tag.Name; Value = [string]$tag.Value })
}
}
$skipToken = $page.SkipToken
} while ($skipToken)
}
if ($uses.Count -eq 0) {
Write-Output 'No resource or resource group in these subscriptions has a tag.'
return
}
$report = @($uses | Group-Object Name | ForEach-Object {
$values = @($_.Group | Group-Object Value -CaseSensitive | Sort-Object Count -Descending)
[pscustomobject]@{
Tag = $_.Name
Resources = $_.Count
Values = $values.Count
Examples = ($values | Select-Object -First 3 -ExpandProperty Name) -join ', '
}
} | Sort-Object Resources -Descending)
$report | Export-Csv -Path './tags-in-use.csv' -NoTypeInformation -Encoding utf8
Write-Output "$($report.Count) tag names saved to tags-in-use.csv."
} finally {
Disconnect-AzAccount | Out-Null
}The CSV has 1 row per tag name, the most used first: how many resources and resource groups carry it, how many different values it holds and the 3 values used most. Names are grouped without regard to case, as Azure treats them, and shown in the spelling found first; values keep their case. To include subscriptions, add a third query like the second, with the type microsoft..
Option 2
Review the tags in use in the Azure portal
- Sign in to the Azure portal with an account that can read the subscriptions.
- Search for tags and choose Tags to see the tags in use.
- Select a tag to list the resources that carry it.
- For every name and value in 1 list, search for resource graph, choose Resource Graph Explorer, paste this read-only query in Query 1 and choose Run query:
ResourceContainers | where isnotempty(tags) | project tags | mv-expand tags | extend tagKey = tostring(bag_keys(tags)[0]) | extend tagValue = tostring(tags[tagKey]) | union ( Resources | where isnotempty(tags) | project tags | mv-expand tags | extend tagKey = tostring(bag_keys(tags)[0]) | extend tagValue = tostring(tags[tagKey]) ) | distinct tagKey, tagValue | where tagKey !startswith "hidden-" - Choose Download as CSV to keep the pairs.
The query follows Microsoft's sample: it lists each name and value once, from subscriptions and resource groups as well as resources, but doesn't count them. It suits a quick look; for counts you can compare each month, use PowerShell or Altivane.
Option 3 ยท Recommended for regular tagging reviews
List the tags in use with Altivane
- Open Altivane and choose the tenant.
- Run the Azure Tags report.
- Open the Excel workbook and find Tags in use: each tag name, the most used first, with how many resources and resource groups carry it, how many values it holds and up to 3 of them.
- Read Untagged resources next for every resource with no tag at all.
The report covers every subscription where you gave Altivane the Reader role. Like Azure, it counts CostCenter and costcenter as 1 tag, shown in the spelling used most; values keep their case, and an empty value shows as (empty). Tags on subscriptions aren't counted. With every name in 1 list, names such as Env and Environment used side by side are easy to spot.
Contact usCommon questions
Why does the portal show a tag name twice?
A tag with a large set of values comes back over more than 1 page, and the tag's name is repeated on the next page. Microsoft says this can make tools such as the Azure portal show the name twice; it's still 1 tag.
Do resources take the tags of their resource group?
No. Resources don't inherit the tags of their resource group or subscription; Azure Policy definitions for tags can copy them down. To find the resources with none, see how to find resources without tags in Azure.
Is there a limit to how many tags a resource can have?
Yes. Each resource, resource group and subscription can hold up to 50 name and value pairs. A name can be up to 512 characters and a value up to 256, and a storage account's names stop at 128. Tags are stored as plain text, so keep sensitive values out of them.
Microsoft references
Technical references checked on 7 November 2026. The example scripts have been reviewed and syntax checked; they have not been run against a live tenant.
- Install-Module cmdlet reference
- Connect-AzAccount cmdlet reference
- Search-AzGraph cmdlet reference
- Disconnect-AzAccount cmdlet reference
- Use tags to organise your Azure resources
- Apply tags with the Azure portal
- Azure Resource Graph sample queries for Azure Resource Manager
- Run a Resource Graph query in the Azure portal
- Azure Resource Graph query language