ManageTagsOnDisk.ps1
<#PSScriptInfo .VERSION 1.0 .GUID 39ac4585-7daf-4509-bfc0-089ec25db7fe .AUTHOR AlexG .COMPANYNAME GooberWorks .COPYRIGHT GooberWorks (c) 2020 .TAGS Azure AzureRM Automation TAGS Tags Disk replace remove delete copy add tags Unattached ManageTagsOn .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES 1.0 - 2/13/2020 Original Release .PRIVATEDATA #> <# .DESCRIPTION This is a Powershell script to help manage TAGS on Azure Disk Resource While it is very easy to add and change tags using console, it is not so easy to delete a specific tag from a resource. The console also limits the number of resources you can update to 100. So if you need to change tags on more than 100 VMs, then you'll need to rinse and repeat as often as neccessary This script will allow you to add, replace or remove a specific tag from any Disk that matches a search criteria using parameters -ManageThisTag or ManageThisTag and ManageThisTagValue. It will also allow you to Copy tags from the Virtual Machine that owns the Disk. The Copy function of the script will overwrite the existing Tags on the Disk with those from the VM. If you wanted to keep some of the Tags on the Disk that are not on the Virtual Machine, then you can you Merge function. The Merge Function will combine Tags from the VM and Disk. For those tags that exist on both VM and Disk, you can specify which of the two values will be kept by using the switches -vmwins or -diskwins While running the -merge process, the script will identify and Disk Resource that is not Managed, not attached, to any Virtual Machine. You may want to carefully review that list to see if you are spending on Disk Storage for the VMs you have deleted a while back. This script is part of a set of ManageTagsOn scripts. Please look for ManageTagsOnVM ManageTagsOnDisk ManageTagsOnNetworkCard ManageTagsOnPublicIP ManageTagsOnNetworkSecurityGroup ManageTagsOnAvailabilitySet ManageTagsOnRouteTable ManageTagsOnAutomationRunbooks .SYNOPSIS Add, Remove, Replace, Merge or Copy Tags on Disk Resource in Azure .DESCRIPTION This script will allow you to add, replace or remove a specific tag from any Disk that matches a search criteria using parameters -ManageThisTag or ManageThisTag and ManageThisTagValue. It will also allow you to Copy tags from the Virtual Machine that owns the Disk. The Copy function of the script will overwrite the existing Tags on the Disk with those from the VM. If you wanted to keep some of the Tags on the Disk that are not on the Virtual Machine, then you can you Merge function. The Merge Function will combine Tags from the VM and Disk. For those tags that exist on both VM and Disk, you can specify which of the two values will be kept by using the switches -vmwins or -diskwins. .PARAMETER ManageThisTag The name of the TAG to be use as a search criteria. Filters only those Disk Resources where this tag exists. .PARAMETER ManageThisTagValue The value of the TAG specified by ManageThisTag. This further filters only those Disk Resources where this tag exists and it value matches ManageThisTagValue. .PARAMETER FromGroup The name of the Resource Group to limit search scope. Filters only those Disk Resource in the specific Resource Group. .PARAMETER addtag The -addtag switch works together with NewTagKey and NewTagValue parameters. This will make the script add a new tag NewTagKey with value of NewTagValue to the Disk Resource that match the search criteria .PARAMETER replacetag The -replacetag switch will tell the script to delete the tag specified by ManageThisTag, no matter of its value is and replace it with a new tag NewTagKey with value of NewTagValue .PARAMETER replacetagvalue The -replacetagvalue switch will tell the script to delete the tag specified by ManageThisTag, only if its value matches ManageThisTagValue and replace it with a new tag NewTagKey with value of NewTagValue .PARAMETER removetag The -removetag parameter will tell the script to delete the tag specified by ManageThisTag, no matter of its value is. .PARAMETER removetagvalue The -removetagvalue parameter will tell the script to delete the tag specified by ManageThisTag, only if its value matches ManageThisTagValue .PARAMETER merge The -merge switch works together with -vmwins, -diskwins and -replace switches. The Merge Function will combine Tags from the VM and Disk. For those tags that exist on both VM and Disk, you can specify which of the two values will be kept by using the switches -vmwins or -diskwins. The -replace switch will make the script perform what amounts to a copy of the tags from the Virtual Machine to the Disk Resources it "owns" .PARAMETER WhatIf Safe run of the script without any changes to preview changes that would be made. .EXAMPLE ManageTagsOnDisk.ps1 -ManageThisTag "Environment" -removetag -FromGroup "test-vm-servers-rg" .EXAMPLE ManageTagsOnDisk.ps1 -ManageThisTag "Environment" -ManageThisTagValue "Development" -replacetagvalue -NewTagKey "Environment" -NewTagValue "Test" .EXAMPLE ManageTagsOnDisk.ps1 -merge -vmwins -FromGroup "test-vm-servers-rg" .EXAMPLE ManageTagsOnDisk.ps1 -merge -replace .NOTES AUTHOR: Alexander Goldberg LASTEDIT: Feb 12, 2020 WEBSITE: www.alexgoldberg.com #> param( [string]$ManageThisTag, [string]$ManageThisTagValue, [string]$NewTagKey, [string]$NewTagValue, [string]$FromGroup, [switch]$addtag, [switch]$replacetag, [switch]$replacetagvalue, [switch]$removetag, [switch]$removetagvalue, [switch]$merge, [switch]$diskwins, [switch]$vmwins, [switch]$replace, [switch]$WhatIf ) function Merge-HashTable { param( [hashtable] $default, # Your original set [hashtable] $uppend # The set you want to update/append to the original set ) # Clone for idempotence $default1 = $default.Clone(); # We need to remove any key-value pairs in $default1 that we will # be replacing with key-value pairs from $uppend foreach ($key in $uppend.Keys) { if ($default1.ContainsKey($key)) { $default1.Remove($key); } } # Union both sets return $default1 + $uppend; } if ( 1 -ne $replacetag.IsPresent + $replacetagvalue.IsPresent + $removetag.IsPresent + $removetagvalue.IsPresent + $addtag.IsPresent + $merge.IsPresent) { 'Usage: ManageTagsOnDisk -ManageThisTag [-ManageThisTagValue] [-FromGroup] { -addtag | -replacetag | -replacetagvalue | -removetag | -removetagvalue | -merge } [-diskwins | -vmwins | -replace] [-WhatIf]' exit 1 } if ($merge.IsPresent) { if ( 1 -ne $diskwins.IsPresent + $vmwins.IsPresent + $replace.IsPresent) { 'When merging tags, specify who wins if tags exists on both VM and Disk. Usage: -merge { -diskwins | -vmwins | -replace}' exit 1 } } # Initilize an Array to hold unattached disks $UnattachedDisks = New-Object 'System.Collections.Generic.Dictionary[String,String]' if ($FromGroup.Length -eq 0) { # Getting the list of all Disks in the subscription. $Resources = Get-AzureRmDisk } else { # Getting the list of Disks based on the resource group. $Resources = Get-AzureRmDisk -ResourceGroupName $FromGroup } # Details of the tag to remove are stored in the $TagToManage variable. $TagToManage = @{Key="$ManageThisTag";Value="$ManageThisTagValue"} foreach ($Resource in $Resources) { Write-Output ('processing: ' + $Resource.Name) # Initialize UpdateTags to false $UpdateTags = $false # Getting the list of all the tags for the disk. $ResourceTags = $Resource.tags if ($addtag) { if ($null -ne $ResourceTags -and $ResourceTags.ContainsKey($TagToManage.Key)) { Write-Output ("Tag " + $TagToManage.Key + " exists in the " + $Resource.Name + ". The new tag will be Added here") # Adding new tag to the Resource because it has the TagToManage.Key $Resource.Tags.Add($NewTagKey, $NewTagValue) # In addition to the new tag key and value, you can also hardcode any additonal tag value key pairs here # I know, it's not pretty, but it works if you want to add multiple tags #$Resource.Tags.Add("tag name","tag value") # Adding the tag to update with new value #$Resource.Tags.Add("tag name","tag value") # Adding the tag to update with new value #set UpdateTags to true $UpdateTags = $true } } # The replacetag parameter will tell the script to delete the specified tag, no matter of its value is # and replace it with a new tag and value if ($replacetag) { if ($null -ne $ResourceTags -and $ResourceTags.ContainsKey($TagToManage.Key)) { Write-Output ("Tag " + $TagToManage.Key + " exists in the " + $Resource.Name + " and will be Replaced") $Resource.Tags.Remove($TagToManage.Key) $Resource.Tags.Add($NewTagKey, $NewTagValue) #set UpdateTags to true $UpdateTags = $true } } # The replacetagvalue parameter will tell the script to delete the specified tag, only if its value matches ManageThisTagValue # and replace it with a new tag and value if ($replacetagvalue) { if ($null -ne $ResourceTags -and $ResourceTags.ContainsKey($TagToManage.Key) -and ($ResourceTags.($TagToManage.Key) -eq $TagToManage.Value)) { Write-Output ("Tag " + $TagToManage.Key + " with value of " + $TagToManage.Value + " exists in the " + $Resource.Name + " and will be Replaced") $Resource.Tags.Remove($TagToManage.Key) $Resource.Tags.Add($NewTagKey, $NewTagValue) #set UpdateTags to true $UpdateTags = $true } } # The removetag parameter will tell the script to delete the specified tag, no matter of its value is if ($removetag) { If ($Resourcetag.Key -eq $TagToManage.Key) { Write-Output ("Tag " + $TagToManage.Key + " exists in the " + $Resource.Name + " and will be Removed") $Resource.Tags.Remove($TagToManage.Key) $UpdateTags = $true } } # The removetagvalue parameter will tell the script to delete the specified tag, only if its value matches ManageThisTagValue if ($removetagvalue) { if ($null -ne $ResourceTags -and $ResourceTags.ContainsKey($TagToManage.Key) -and ($ResourceTags.($TagToManage.Key) -eq $TagToManage.Value)) { Write-Output ("Tag " + $TagToManage.Key + " with value of " + $TagToManage.Value + " exists in the " + $Resource.Name + " and will be Removed") $Resource.Tags.Remove($TagToManage.Key) #set UpdateTags to true $UpdateTags = $true } } if ($merge) { # Before we go after the ManagerVM let's find out if the disk is attached to a VM # Because if Disk is not Managed, we can't copy the tags from VM if ($null -eq $Resource.ManagedBy) { # No ManagerVM found, Add to unattached disk hashtable to report at the end of the script run $UnattachedDisks.Add($Resource.Name, $Resource.ResourceGroupName) } else { # Get id of the Virtual Machine that manages the disk. Property: ManagedBy # Get tags from the Manager VM $ManagerVM = Get-AzureRmResource -ResourceId $Resource.ManagedBy $ManagerVMTags = $ManagerVM.Tags # If ManagerVMTags does not have tags then there is nothing to merge, so skip it if ($null -ne $ManagerVMTags) { Write-Output ("Merging Tags from " + $ManagerVM.Name + " with tags on Disk " + $Resource.Name) if ($diskwins) { $NewTags = Merge-HashTable $ManagerVMTags $ResourceTags } if ($vmwins) { $NewTags = Merge-HashTable $ResourceTags $ManagerVMTags } if ($replace) { $NewTags = $ManagerVMTags } # The merged HashTable uses object dictionary, we need to use String dictionary. # So we loop through the NewTags and copy all the values to the $ReplacementTags variable $ReplacementTags = New-Object 'System.Collections.Generic.Dictionary[String,String]' foreach ($MergedTagValue in $NewTags.GetEnumerator()) { $ReplacementTags.add($MergedTagValue.Key,$MergedTagValue.Value) # Setting newtags as string hash table } $Resource.Tags = $ReplacementTags #set UpdateTags to true $UpdateTags = $true } } } if ($UpdateTags) { Write-Output ("Updating Tags on: " + $Resource.Name) $Resource | Update-AzureRmDisk -WhatIf:$WhatIf Write-Output ($Resource.Tags | Out-String) } } if ($UnattachedDisks.Count -gt 0) { Write-Warning ($UnattachedDisks | Out-String) } |