Tag hygiene matters. Inconsistent tag names break cost reporting, policy assignments, and automation. This script is a practical wrapper around a PowerShell function designed to rename a tag key (while preserving its value) across resource groups and resources in one or more Azure subscriptions.
This script is most likely to be useful in a somewhat unorganized Azure tenant where policies to enforce specific keys and to disallow unapproved keys has not been implemented.
What the Script Does
At a high level, the script:
- Authenticates to Azure
- Iterates through a defined list of subscriptions
- Finds resources and resource groups with an incorrect tag name
- Creates the new tag using the existing value
- Deletes the old tag
- Handles slow or eventually-consistent resource providers with throttling
Example use case:
- Replace
CreatedBywithCreatoreverywhere, without losing values
The Script
The script below is intentionally simple and is not intended as a long-term solution. It will gracefully fail where Resources or Reosurce Groups have locks.
function Correct-AZTag {
[cmdletbinding()]
Param (
[object]$Resources,
[switch]$isResourceGroup,
[string]$WrongTag,
[string]$NewTag
)
Process {
$count = 0;
foreach ($Resource in $Resources) {
$count++
$Name = if($Resource.ResourceGroupName) {$Resource.ResourceGroupName} else {$Resource.Name}
$ResourceTags = Get-AzTag -ResourceId $Resource.ResourceId
# If the RG has no tags then skip
if($ResourceTags.Properties.TagsProperty -eq $null) {
#Write-Host "1 - Skipped $Name"
continue
}
# If the RG doesn't contain the tag then skip
$Value = $ResourceTags.Properties.TagsProperty[$WrongTag]
if($Value -eq $null) {
#Write-Host "2 - Skipped $Name"
continue
}
# Calculate the values for old and new tags
$WrongTagObj = @{$WrongTag=$Value}
$NewTagObj = @{$NewTag=$Value}
#Create new tag with original value
try {
Update-AzTag -ResourceId $Resource.ResourceId -Tag $NewTagObj -Operation Merge
} catch {
Write-Warning $Name
Write-Warning "Failed on Merge - Count $count - $($Error[0])"
continue
}
if($Resource.ResourceType -eq "Microsoft.DocumentDB/databaseAccounts" -OR $Resource.ResourceType -eq "Microsoft.Network/privateDnsZones" -OR $Resource.ResourceType -eq "Microsoft.Network") {
Write-Host -ForegroundColor Yellow "Starting 30 second wait due to encountering slow Resource"
Start-Sleep 30
}
#Delete the old tag with incorrect name
try {
Update-AzTag -ResourceId $Resource.ResourceId -Tag $WrongTagObj -Operation Delete
} catch {
Write-Warning "Failed on Delete - $count - $($Error[0])"
continue
}
Write-Host -ForegroundColor green "Updated Tags for $Name"
}
}
}
Connect-AzAccount
# Only implement changes in the following Subscription
$Subscriptions = @(
'Name of Subscription'
)
#Define old and new tag names
$WrongName = "CreatedBy"
$CorrectName = "Creator"
#Subscription loop
foreach ($subscription in $Subscriptions) {
$Resources = @()
Write-Host "Selecting Subscription $($Subscription)... "
Get-AzSubscription -SubscriptionName $subscription -WarningAction SilentlyContinue | Set-AZContext -WarningAction SilentlyContinue *> $null
#Correct Resource Groups
Write-Host "Processing Resource Groups..."
$Resources = Get-AzResourceGroup
Correct-AZTag -Resources $Resources -isResourceGroup -WrongTag $WrongName -NewTag $CorrectName
#Correct Resources
Write-Host "Processing Resources"
$Resources = Get-AzResource -TagName $WrongName
if($Resources.length -gt 0) {
Correct-AZTag -Resources $Resources -WrongTag $WrongName -NewTag $CorrectName
}
}
Disconnect-AzAccount






Leave a comment