27 July 2011

Backup/Export Full DRS Rule Info via PowerShell

Updated 22 Jan 2015
Luc Dekens and I got together on a new PowerShell module for managing/exporting/importing DRS Rules and Groups. See our posts at http://www.lucd.info/2015/01/22/drsrule-drs-rules-and-groups-module and http://www.vnugglets.com/2015/01/drsrule-new-powershell-module-for-drs.html for all of the juicy details. Going forward, that DRSRule module is the way to go. I am leaving this post intact for posterity. Enjoy!
End of update - 22 Jan 2015

We, like many, had the need for a way to backup our DRS rules. Searches turned up many pages, all of which had the same basic recipe: use the Get-DrsRule to grab the rules, get a few properties, and export to CSV.

The problem: Addressing the task getting all of the pertinent info for rules of type ClusterVmHostRuleInfo, or, "VM-to-Host" rules. Rules of this type do not have the VM IDs in a property of the rule, but rather have the VMGroupName and HostGroupNames properties. From these properties, and the .NET view object of the given cluster, one can retrieve the VMs' and hosts' info.

So, we did a little work, and wrote the following to, for all DRS rule types, get the information that would be required if one wanted to recreate the rules:
## Script function: Gather/export DRS rule info, including VMGroup and HostGroup members
## Author: vNugglets.com

## file to which to write the DRS rules' info
$strOutputFilespec = "e:\someFolder\DRSrules_export.csv"

## get cluster .NET view objects, which hold the info about the DRS rules
Get-View -ViewType ClusterComputeResource -Property Name, ConfigurationEx | %{
    ## if the cluster has any DRS rules
    if ($_.ConfigurationEx.Rule -ne $null) {
        $viewCurrClus = $_
        $viewCurrClus.ConfigurationEx.Rule | %{
            $oRuleInfo = New-Object -Type PSObject -Property @{
                ClusterName = $viewCurrClus.Name
                RuleName = $_.Name
                RuleType = $_.GetType().Name
                bRuleEnabled = $_.Enabled
                bMandatory = $_.Mandatory
            } ## end new-object

            ## add members to the output object, to be populated in a bit
            "bKeepTogether,VMNames,VMGroupName,VMGroupMembers,AffineHostGrpName,AffineHostGrpMembers,AntiAffineHostGrpName,AntiAffineHostGrpMembers".Split(",") | %{Add-Member -InputObject $oRuleInfo -MemberType NoteProperty -Name $_ -Value $null}

            ## switch statement based on the object type of the .NET view object
            switch ($_){
                ## if it is a ClusterVmHostRuleInfo rule, get the VM info from the cluster View object
                #   a ClusterVmHostRuleInfo item "identifies virtual machines and host groups that determine virtual machine placement"
                {$_ -is [VMware.Vim.ClusterVmHostRuleInfo]} {
                    $oRuleInfo.VMGroupName = $_.VmGroupName
                    ## get the VM group members' names
                    $oRuleInfo.VMGroupMembers = (Get-View -Property Name -Id ($viewCurrClus.ConfigurationEx.Group | ?{($_ -is [VMware.Vim.ClusterVmGroup]) -and ($_.Name -eq $oRuleInfo.VMGroupName)}).Vm | %{$_.Name}) -join ","
                    $oRuleInfo.AffineHostGrpName = $_.AffineHostGroupName
                    ## get affine hosts' names
                    $oRuleInfo.AffineHostGrpMembers = if ($_.AffineHostGroupName -ne $null) {(Get-View -Property Name -Id ($viewCurrClus.ConfigurationEx.Group | ?{($_ -is [VMware.Vim.ClusterHostGroup]) -and ($_.Name -eq $oRuleInfo.AffineHostGrpName)}).Host | %{$_.Name}) -join ","}
                    $oRuleInfo.AntiAffineHostGrpName = $_.AntiAffineHostGroupName
                    ## get anti-affine hosts' names
                    $oRuleInfo.AntiAffineHostGrpMembers = if ($_.AntiAffineHostGroupName -ne $null) {(Get-View -Property Name -Id ($viewCurrClus.ConfigurationEx.Group | ?{($_ -is [VMware.Vim.ClusterHostGroup]) -and ($_.Name -eq $oRuleInfo.AntiAffineHostGrpName)}).Host | %{$_.Name}) -join ","}
                } ## end block
                ## if ClusterAffinityRuleSpec (or AntiAffinity), get the VM names (using Get-View)
                {($_ -is [VMware.Vim.ClusterAffinityRuleSpec]) -or ($_ -is [VMware.Vim.ClusterAntiAffinityRuleSpec])} {
                    $oRuleInfo.VMNames = if ($_.Vm.Count -gt 0) {(Get-View -Property Name -Id $_.Vm | %{$_.Name}) -join ","}
                } ## end block
                {$_ -is [VMware.Vim.ClusterAffinityRuleSpec]} {
                    $oRuleInfo.bKeepTogether = $true
                } ## end block
                {$_ -is [VMware.Vim.ClusterAntiAffinityRuleSpec]} {
                    $oRuleInfo.bKeepTogether = $false
                } ## end block
                default {"none of the above"}
            } ## end switch

        } ## end foreach-object
    } ## end if
} | Export-Csv -NoTypeInformation $strOutputFilespec

This bit of code, using the Get-View cmdlet for max speed and min memory footprint, starts off by getting a couple of select properties for all clusters. If the cluster has any DRS rules defined, then the code, for each rule:
  • creates a new PSObject to hold the pertinent info about the rule
  • includes basic rule info, the rule type, and info about the objects involved with the rule, including the VM group names/members and the host group names/members (for both Affine- and AntiAffine host groups)
  • returns the object
  • exports all of the gathered info to CSV for later consumption

Arnim van Lieshout wrote a good post with more information about DRS rules themselves at Managing VMware DRS rules using PowerCLI, and included a few functions for creating VMGroups ("Virtual Machines DRS Groups" in the vSphere client) and HostGroups ("Host DRS Groups"), and for creating new VM-to-Host rules. We will likely be using said functions for our "recreate the DRS rules/groups" work.