Using System Center 2012 for Host Cluster Remediation (Patching) and Host Cluster VM Rebalancing for Private Cloud – Part 2 of Many (VM Rebalancing)
This is Part 2 in my series “Using System Center 2012 for Host Cluster Remediation (Patching) and Host Cluster VM Rebalancing”, and this post will focus on rebalancing your VMs to their original host after you have done a Host Remediation to your Microsoft Private Cloud infrastructure using System Center Virtual Machine Manager 2012. Again this solution involves using System Center products Virtual Machine Manager 2012, System Center Operations Manager 2012, and System Center Orchestrator 2012. The script in this post, just as in Part 1, are intended to run in a System Center Orchestrator 2012 runbook, but you can alter the script to run it in your environment without Orchestrator, but you will need System Center Virtual Machine Manager 2012.
Prerequisites
The following script assumes that you have utilized the SCVMMClusterRemediation.ps1 Windows PowerShell script from the Part 1 post of this series to automate your Microsoft Private Cloud Host Remediation. If you have not utilized that script, or a variation of that script, to populate the Custom Fields of your VM with the VM Host name then this script will not be able to rebalance the VMs back to running on their original VM Host they were prior to the System Center Virtual Machine Manager 2012 Host Remediation job. To prepare your Microsoft Private Cloud VMs to utilize the following script please see the Part 1 post in this series at https://blogs.technet.com/b/phillipgibson/archive/2012/05/09/using-system-center-2012-for-host-cluster-remediation-patching-and-host-cluster-vm-rebalancing-part-1-of-many.aspx.
The VM Rebalancing Script Breakdown
Below is the VM rebalancing script that you can run against your Microsoft Private Cloud Hyper-V host clusters in your System Center Virtual Machine Manager 2012 environment after the VMs have been tagged with their VM Host server in their Custom Field 1 property. Prior to running this script you should check the properties of your VMs to ensure they have their original VM Host name populated in the Custom1 field they were running on prior to the host cluster remediation. The properties of the VM should look similar to the picture below.
Unlike the Windows PowerShell script in Part 1 of the series (SCVMMClusterRemediation.ps1) the SCVMMClusterVMRebalance.ps1 is much less involved and doing less so I will not document it so thoroughly as I’ve done for the previous script. Overall this script is just running against the VM Host Clusters you filter on, enumerating all VMs on each node of the Host Cluster, and running the SCVMM PowerShell cmdlet Move-SCVirtualMachine to the Host Cluster node listed in the Custom1 field of the VM. That activity is specifically happening from Lines 68-90 and when this script runs you should see SCVMM job activity similar to the picture below. I’ve removed private data out of the picture such as the VM name and the Host Cluster Nodes.
Another key thing the script is doing is writing the Move-SCVirtualMachine SCVMM Job GUID to the event log (Line 85). Again, that SCVMM Job GUID will be used in the total solution to monitor the result of the SCVMM Job, with a runbook that get initiated when that event is written.
The next post in this series (Part 3) will focus on automating these scripts utilizing System Center Orchestrator 2012 runbooks. The runbooks will detail how the solution is scheduled, how the SCVMM Job GUIDs are captured for monitoring, and how I use the VM Host time zone properties to ensure that Host Clusters are patched during a specific time local to the Host Cluster.
As always feel free to post your comments or questions. You can also email me too.
Phil Gibson | Senior Consultant | Microsoft | System Center & Private Cloud Infrastructure & Development
SCVMMClusterVMRebalance.ps1
- <#
- Purpose : Rebalance VMs on Hyper-V Clusters using SCVMM 2012
- Author : pgibson.online@hotmail.com [MSFT]
- Disclaimer: THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
- EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
- #>
- ####### Functions ###############
- Function global:WriteEvent
- {
- <#
- Purpose : Write events into the eventlog of the executing machine.
- Setup : Please edit the $EventSoure variable to the EventLog source you want your script to utilize as default. Ex. $EventSource = "MyLogSource"
- Example 1: WriteEvent -EventSource "TEST" -EventID 101 -EventType "Warning" -EventMessage "This is really a test."
- Example 2: WriteEvent -Source "TEST" -ID 101 -Type "Warning" -Message "This is really a test."
- **NOTE** : This function will default the EventLog source you supplied with a "Information" event to the "Application" log if the parameters are not used/overridden
- Author : pgibson.online@live.com [MSFT]
- #>
- param (
- [parameter(Mandatory=$false,Helpmessage="Please enter the source of the Eventlog entry. Example: -Source ""MyLogSource""")][alias("Source")][string]$EventSource = "SCVMMHostRemediation",
- [parameter(Mandatory=$true,Helpmessage="Please enter the event ID of the Eventlog entry. Example: -ID 101")][alias("ID")][int]$EventID,
- [parameter(Mandatory=$false)][alias("Type")][ValidateSet("Error", "Information", "Warning")][string]$EventType = "Information",
- [parameter(Mandatory=$true,Helpmessage="Please enter the event description of the Eventlog entry. Example: -Message ""This is a test.""")][alias("Message")][string]$EventMessage,
- [parameter(Mandatory=$false)][alias("Log")][ValidateSet("Application", "Security", "System")][string]$EventLog = "Application"
- )
- # Create event source if it does not exist
- If (![System.Diagnostics.EventLog]::SourceExists($EventSource))
- {
- [System.Diagnostics.EventLog]::CreateEventSource($EventSource, $EventLog)
- write-eventlog -logname $EventLog -Source $EventSource -eventid $EventID -entrytype $EventType -message $EventMessage
- }
- Else
- {
- write-eventlog -logname $EventLog -Source $EventSource -eventid $EventID -entrytype $EventType -message $EventMessage
- }
- }
- ####### End Functions #############
- ######## Start Main ###########
- $ErrorActionPreference = "Stop"
- WriteEvent -EventID 100 -EventMessage "Start VM Cluster Rebalancing Process."
- Try
- {
- $HostClusters = Get-SCVMHostCluster | where { ($_.ClusterName -eq "HVCLSRV01")}
- ForEach ($HostCluster in $HostClusters)
- {
- WriteEvent -EventID 100 -EventMessage "Processing Host Cluster $HostCluster."
- $Cluster = Get-SCVMHostCluster -Name $HostCluster.ToString()
- #Get all Nodes in Cluster
- $HostClusterNodes = $HostCluster.Nodes
- ForEach ($Node in $HostClusterNodes)
- {
- $VMHost = Get-SCVMHost -ComputerName $Node -VMHostCluster $Cluster
- WriteEvent -EventID 100 -EventMessage "Processing Node $VMHost of Host Cluster $HostCluster."
- ##### - Start VM to VMHost Rebalancing Sequence - ###### # This will move the VM to the VMHost listed in the Custom1 field property of the VM.
- ForEach ($VM in $VMHost.VMs)
- {
- WriteEvent -EventID 100 -EventMessage "Processing VM $VM on Node $VMHost of Host Cluster $HostCluster."
- #Generate Remediation JobGroup SCJob GUID
- $JobGroupGUID = [System.Guid]::NewGuid()
- WriteEvent -EventID 100 -EventMessage "The SCVMM VM Move Job GUID for VM $VM on Node $VMHost of Host Cluster $HostCluster is $JobGroupGUID."
- $VMCustomProperty1 = Get-SCCustomProperty -Name "Custom1"
- $VMCustomProperty1Value = Get-SCCustomPropertyValue -InputObject $VM -CustomProperty $VMCustomProperty1
- WriteEvent -EventID 100 -EventMessage "Checking the Custom Field 1 VM Host Value for VM $VM on Node $VMHost of Host Cluster $HostCluster."
- If ($VMHost.Name -ne $VMCustomProperty1Value.Value.ToString())
- {
- WriteEvent -EventID 100 -EventMessage "Moving VM $VM on Node $VMHost of Host Cluster $HostCluster to $VMCustomProperty1Value.Value."
- $NewVMHost = Get-VMHost | where {$_.Name -eq $VMCustomProperty1Value.Value.ToString()}
- Move-SCVirtualMachine -VM $VM -VMHost $NewVMHost -HighlyAvailable $true -RunAsynchronously -JobGroup $JobGroupGUID.ToString()
- WriteEvent -EventID 101 -EventMessage $JobGroupGUID
- }
- #Clear JobGroupGUID variable
- Clear-Variable -Name JobGroupGUID
- }
- ##### - End VM to VMHost Rebalancing Sequence - ######
- }
- }
- }
- Catch
- {
- Throw $_.Exception
- WriteEvent -EventID 200 -Type "Error" -EventMessage "VM Cluster Rebalancing Process Failed. Error message: $_.Exception.Message"
- }
- Finally
- {
- WriteEvent -EventID 100 -EventMessage "Completed VM Cluster Rebalancing Process."
- }