During a recent cost optimization workshop with a customer, they mentioned that although they had some tagging policies in place there was no consistency of tag names across the Azure environment. This post introduces a script to remediate this and remove some confusion from your tagging strategy.
The customer was trying to ensure that all resources were being tagged with a cost centre tag. Some of this was automatic and some was done manually by people. While there was a policy in place to control this in the future, they needed a way to remediate the existing resources.
An example of what their tags looked like is below – notice the different spelling and casing for the tag names.
There are a number of different tag names – the customer wanted to standardise all of these using one tag – “costcentre” .
I have a written a script which can do this – based on the parameters supplied it will look at all resources in a scope and correct all the different versions of the tags while maintaining all the values, let’s look at how it works.
The script is in my GitHub repository – you will need to download it. You will also need to have PowerShell 7 and the Az.ResourceGraph module should be installed.
The user or principal running the script will need to have Reader and Tag Contributor rights across the scope in order to make any changes.
Creating the Parameters
So that you can rectify all the above tag values, the script takes in a hash table of values. Each of the keys in the hash table corresponds to one of the incorrect tag values, and the value of each key represents the correct tag name. We also must add a key with the correct tag name with its own name as well which is used to correct incorrect casing for tags.
For the example above – I can create a table to represent the hash table as below:-
Incorrect Tag Name
Correct Tag Name
The final row in that table represents the casing correction – it is important to have that in there.
If I take this table and represent it as a hash table for my script it would look like the code below: -
The other parameter required is to define a scope of where the script should run. This is used in the query to the Azure Resource Graph which retrieves the objects.
If I wanted to run this script at the management group level, I would use the -ManagementGroupId parameter and supply the correct id, however if I wanted to run it at the subscription level I could use the -SubscriptionId parameter.
I’m going to run it across my management group so I would call it as below: -
I’ve cleaned up the output below – but the script will output all the changes it is going to make, it will show which resources are going to have their tags changed and the operations being performed e.g., add or remove.
It is important to review the changes above to make sure everything is going to work correctly. I would suggest testing this on a smaller scope e.g., a test subscription to make sure it works before using it to correct tags across your whole environment.
Apply The Changes
To apply the changes to the environment you can just re-run the script with the -UpdateTags switch added like below.
This time the script not only shows you the changes but then loops through them all the performs the operations on the resource. Remember that Azure Policies and RBAC still apply so if any of the changes are prevented from happening the script will error out.
When complete I can wait a minute for the changes to propagate – but refreshing my tags view now shows all the values have been corrected.
You can also change multiple tag names at the same time – for instance if I also wanted to fix up an application name tag I can just add the values into my hash table. Remember that you need to have that extra entry with the same key/value to ensure the casing is corrected.
I hope this gives you a quick way to rectify any inconsistencies in your environment's tagging strategy! Please ensure you test thoroughly before applying.
The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.