Bulk-Correcting Azure Tag Keys Across Subscriptions

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 CreatedBy with Creator everywhere, 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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Design a site like this with WordPress.com
Get started