CAU Local VM Script

Cluster Aware Updating (CAU) introduced in Server 2012 allows you to update your Fail-Over cluster by draining all the Highly Available (HA) roles from the node, performing the updates and then restoring the roles.

While this works great for Clustered HA VMs on a Hyper-V cluster, it appears CUA completely ignores any unclustered VMs on the Nodes. We have non-HA VMs on our Hyper-V Hosts that act as nodes in a File server Fail-Over Cluster and Exchange DAG groups. When CUA runs it ignores the shutdown settings of these VMs and just powers them off, this can causes loss of data in nodes and causes the cluster to have to bring up a down resource rather than just transfer the role.

To fix this we had to create scripts that shut down all the local VMs and then start them back up. These can then be set in the PreUpdateScript and PostUpdateScript profile settings for CUA. I stored the scripts on the CSV volume in C:\ClusterStorage\Volume1\Hyper-V\CAU\. These could then be added as a local file in CAU configuration wizard.

PreUpdateScript = ShutdownLocal.ps1

# VM Delay
$CheckDelay = 30

# Local VMs
$LocalVMs = Get-VM | Where-Object { ($_.IsClustered -eq $false) -and ($_.State -ne "Off")} 

$Node = $env:computername
$LogFile = "C:\ClusterStorage\Volume1\Hyper-V\CAU\Log\$(get-date -f yyyy-MM-dd)-$Node.log"

(Get-Date -Format s) + " CAU Shutdown Script" >> $LogFile

#Shutdown Each VM
ForEach ($VM in $LocalVMs) {
    $VMName = $VM.Name
    # Check State
    If ($VM.State -ne "Off") {
        If ($VM.AutomaticStopAction -eq "ShutDown") {
            # Change State
            (Get-Date -Format s) + " Shutting Down $VMName" >> $LogFile
            Stop-VM -AsJob -VM $VM  #-WhatIf
        } 
        ElseIf ($VM.AutomaticStopAction -eq "Save") {
            # Change State
            (Get-Date -Format s) + " Saving $VMName" >> $LogFile
            Stop-VM -AsJob -VM $VM -Save  #-WhatIf
        } 
    }
}

# Wait for all VMs to Shutdown
$i = 0
Do {
    $VMon = 0
    $i++
    $TimeWait = $CheckDelay * $i
    Start-Sleep -Seconds $CheckDelay
    (Get-Date -Format s) + " Waited $TimeWait seconds for:" >> $LogFile
    ForEach ($VM in $LocalVMs) {      
        $VMName = $VM.Name
        # Check State
        If ((Get-VM -Name $VMName).State -ne "Off" -and (Get-VM -Name $VMName).State -ne "Saved") {
            # Report State
            (Get-Date -Format s) + " -$VMName" >> $LogFile
            $VMon++
        }
    }
}
Until ( ($i -gt 10) -or ($VMon -eq 0) )

(Get-Date -Format s) + " CAU Shutdown Script Completed" >> $LogFile

PostUpdateScript = StartLocal.ps1


$Node = $env:computername
$LogFile = "C:\ClusterStorage\Volume1\Hyper-V\CAU\Log\$(get-date -f yyyy-MM-dd)-$Node.log"

$PauseDelay = 300
# Local VMs
$LocalVMs = Get-VM | 
  Where-Object { ($_.IsClustered -eq $false) -and  ($_.AutomaticStartAction -like 'Start*') -and ($_.State -ne "Running")} | 
  Sort-Object AutomaticStartDelay

(Get-Date -Format s) + " CAU Startup Script" >> $LogFile

$DelayElapsed = 0
#Start Each VM
ForEach ($VM in $LocalVMs) {
    $VMName = $VM.Name
    $VMDelay = $VM.AutomaticStartDelay
    # Check State
    If ($VM.State -ne "Running") {
        $VMDiff = $VMDelay - $DelayElapsed
        If ($VMDiff -gt 0) { Start-Sleep -Seconds $VMDiff }
        $DelayElapsed += $VMDiff
        # Change State
        (Get-Date -Format s) + " Starting $VMName" >> $LogFile
        Start-VM -AsJob -VM $VM  #-WhatIf
    }
}
# Delay as will immediately start shutting down next node
(Get-Date -Format s) + " VMs Started waiting $PauseDelay seconds for clusters to stabilise" >> $LogFile
Start-Sleep -Seconds $PauseDelay
(Get-Date -Format s) + " CAU Startup Script Completed" >> $LogFile

About James Rudd

Network Administrator at Sydney Boys High School
This entry was posted in Windows and tagged , , , , . Bookmark the permalink.

Leave a Reply