Generating VM Tags with PowerCLI
With the our new infrastructure upgrade it also included an upgrade to our backup solution. So we now have EMC Avamar for backups, and with this it means a chance to architect the backup solution the best possible way. So during the initial stage, I worked closely with our storage team to get the method that they chose to work. They chose to use VM tags and to base the backup policies on them. So we’ll need to have 6 categories with several tags in each. So with this method of configuration we should be able to have a granular backup policy to meet the needs of our customers.
The Birth of a Category
New-TagCategory -Name Test -Description "This is a test category" -Cardinality Single -EntityType VM
It is fairly simple to create a category. When I think about categories and tags, it reminds me of the chicken and the egg. Which came first? When it comes to categories and tags, categories always come first. Categories are needed before the tags can be created as the tags need to belong in a category. They are used to group like tags together, like environments or applications. Categories can be configured so that the object or entity type, in our case the VM, can only get a single tag assigned from each category by setting the cardinality setting to single. This makes it nice so there is a mechanism to help prevent multiple tags being assigned from the same category.
In the image below, I have pulled the get-help for the command to show the varies options for the EntityType and Cardinality parameters.
So I now need to create the categories that will be used to generate the policies for Avamar. The storage engineers and I came up with 6 different categories as mentioned before, Quiesce, Backup Status, DataSet, Retention, Schedule, and Zone.
"Quiesce","Backup Status","DataSet","Retention","Schedule","Zone" | Foreach {New-TagCategory -Name $_ -Cardinality Single -EntityType VM}
VM Tag You’re It
Now that I have the categories created, I need some tags. During the initial meeting with the storage engineers, we planed out the required tags that Avamar would read from the VMs so it could associate them with the backup policies. Each category would have 2 or more tags as it has multiple policies to try and fit everyone’s needs.
New-Tag -Name Test -Category Test -Description "This is a test tag"
So now I just need generate the tags that were used to setup the backup policies and then they can be assigned to the VMs.
Please Take a Tag
Its time to assign the tags to the VMs that are going to be backup. So we created a default backup policy that all VMs with start with: Q2, B2, D1, R5, S2, Z* (where * is the numeric value given to the VM cluster the VM resides on).
So I wrote a script to apply the tags to the VMs. I had to put a little bit of smarts so the script would assign the correct Z* tag for cluster the VM lives on.
$VMs = Get-cluster Prod, Non-Prod, Mgmt, Citrix | Get-vm foreach ($VM in $VMs){ $cluster = (Get-cluster -VM $VM).Name If ($cluster -eq "Prod"){ $VMName | New-TagAssignment -Tag R5 $VMName | New-TagAssignment -Tag D1 $VMName | New-TagAssignment -Tag S2 $VMName | New-TagAssignment -Tag B2 $VMName | New-TagAssignment -Tag Q2 $VMName | New-TagAssignment -Tag Z4 } If ($cluster -eq "Non-Prod"){ $VMName | New-TagAssignment -Tag R5 $VMName | New-TagAssignment -Tag D1 $VMName | New-TagAssignment -Tag S2 $VMName | New-TagAssignment -Tag B2 $VMName | New-TagAssignment -Tag Q2 $VMName | New-TagAssignment -Tag Z3 } If ($cluster -eq "Mgmt"){ $VMName | New-TagAssignment -Tag R5 $VMName | New-TagAssignment -Tag D1 $VMName | New-TagAssignment -Tag S2 $VMName | New-TagAssignment -Tag B2 $VMName | New-TagAssignment -Tag Q2 $VMName | New-TagAssignment -Tag Z1 } If ($cluster -eq "Citrix"){ $VMName | New-TagAssignment -Tag R5 $VMName | New-TagAssignment -Tag D1 $VMName | New-TagAssignment -Tag S2 $VMName | New-TagAssignment -Tag B2 $VMName | New-TagAssignment -Tag Q2 $VMName | New-TagAssignment -Tag Z2 } }
Switching VM Tags with Ease
Since we are all in on VM tags for the Avamar backup I thought it would be good to have an easy way to switch the tags if needed on a VM. It would take some time to remove and re-add a new tag if a customer decided they no longer wanted backups, or they wanted any kind of change to the policies of several VMs. So I generated a function that I added into my PS profile so I could call it to do the changes when needed.
function Update-AvamarTag { [CmdletBinding()] Param ( # This is the Virtual Machine that needs the tag changed [Parameter(Mandatory=$true, Position=0, ParameterSetName='VMname')] [ValidateNotNullOrEmpty()] $VMname ) DynamicParam { # Set the dynamic parameters' name $ParameterName = 'NewTag' # Create the dictionary $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary # Create the collection of attributes $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] # Create and set the parameters' attributes $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute $ParameterAttribute.Mandatory = $true $ParameterAttribute.Position = 2 # Add the attributes to the attributes collection $AttributeCollection.Add($ParameterAttribute) # Generate and set the ValidateSet $arrSet = (Get-TagCategory "Avamar*" | Get-Tag).Name $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet) # Add the ValidateSet to the attributes collection $AttributeCollection.Add($ValidateSetAttribute) # Create and return the dynamic parameter $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection) $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter) return $RuntimeParameterDictionary } Begin { $NewTag = $PsBoundParameters[$ParameterName] } Process { $TagCategory = (Get-Tag -name $NewTag).Category $oldTag = (Get-VM $VMname | Get-TagAssignment -Category $TagCategory).Tag.Name Write-host "Removing Tag $oldTag for tag Category $TagCategory" -ForegroundColor Yellow -BackgroundColor Black Get-VM $VMName | Get-TagAssignment -Category $TagCategory | Remove-TagAssignment -Confirm:$false Write-host "Adding new tag $NewTag to VM $VMname" -ForegroundColor Yellow -BackgroundColor Black Get-VM $VMName | New-TagAssignment -Tag $NewTag | Out-Null { } } End { } }
The beauty of this function is it will query the tag categories named Avamar* to get all of the valid tags and numerate them in a list. As seen below in the image.
Have You Been Tag?
With all of this tag awesomeness there needs to be a way to verify en masse what has been tagged. So yet another script from a scripting blog, who would have guessed. 🙂
$ErrorActionPreference = 'SilentlyContinue' $VMs = get-cluster Citrix, Non-Prod, Prod, Mgmt | Get-VM $report = @() foreach ($Vm in $VMs){ $Line = "" | Select Name, Cluster, "Avamar Retention", "Avamar DataSet", "Avamar Schedule", "Avamar Backup Status", "Avamar Quiesce", "Avamar Zone" $line.name = $VM.name $line.cluster = (Get-cluster -vm $VM).name $Tags = Get-vm $VM | Get-TagAssignment Foreach ($Tag in $tags){ $Category = $tag.tag.Category $line.$category = $tag.tag.name } $report += $line } $report | export-csv C:\scripts\logs\AvamarTags-$date.csv -NoTypeInformation -UseCulture
So this script will gather all of the VMs on the cluster that are listed on the 2nd line. Then once the machines are gathered it will query for the assigned tags under the Avamar* category, and put them all in a neat like CSV file for your viewing pleasure.
-Stuart