Monitoring Failover Cluster Patching
Windows Failover Clustering is a great way to run services like DHCP, Hyper-V, etc. resiliently. Microsoft makes it easy to schedule patching using Cluster Aware Updating. Once you have Cluster Aware Updating setup, you'll need to monitor it.
First let's get the results of the last run:
$ Get-CauReport -Last
ClusterName : hv-clstr
Status : Succeeded
StartTimestamp : 12/11/2020 3:00:00 AM
CountOfSucceededResults : 6
CountOfFailedResults : 0
CountOfCanceledResults : 0
HadTransientInstallError : FalseIf the Status field is Succeeded, great, your last run succeeded and the CountOfSucceededResults field shows that 6 updates were installed (in my case, 3 on each node of the cluster).
If there is a failure, add the -Detailed flag to get more results about the failure:
$ Get-CauReport -Last -Detailed
ClusterName : hv-clstr
ClusterResult.Status : Failed
ClusterResult.RunDuration : 4:35:00
ClusterResult.NodeResults : {...}
ClusterResult.ErrorRecordData : MaxFailedNodes limit (0) exceeded.
...If ClusterResult.Status is Failed, then we can look at ClusteResult.ErrorRecordData for the failure reason and ClusterResult.NodeResults for the results on individual nodes.
Here's the script to monitor the results of the most recent Cluster Aware Updating run and create alerts in Atera for failed nodes:
$Report = Get-CauReport -Last -Detailed
$UpdateSuccessful = $false
$FailureReason = ""
$FailedNodes = @()
if ($null -eq (Get-Module -ListAvailable PSAtera)) {
Install-Module PSAtera -Force
}
function New-RMMAlert($Data, $RunId) {
Set-AteraAPIKey -APIKey ""
$CurrentAlerts = Get-AteraAlertsFiltered -Open
$Data | Format-Table
foreach ($node in $Data) {
$Agent = Get-AteraAgent -MachineName $node.Node
if ($CurrentAlerts | Where-Object { $_.DeviceGuid -eq $Agent.DeviceGuid -and $_.AdditionalInfo -eq $RunId }) { continue }
Write-Host "Creating alert"
New-AteraAlert -DeviceGuid $Agent.DeviceGuid -CustomerID $Agent.CustomerId -Title "Cluster Updates Failed" -Severity Critical -AlertCategoryID General `
-MessageTemplate $Node.ErrorRecordData.ExceptionData.Message -AdditionalInfo $RunId
}
}
if ($Report.ClusterResult.Status -eq "Succeeded") {
$UpdateSuccessful = $true
} else {
$FailureReason = $Report.ClusterResult.ErrorRecordData
$FailedNodes = $Report.ClusterResult.NodeResults | Where-Object Status -ne "Succeeded" | Select-Object Node, Status, ErrorRecordData
New-RMMAlert -Data $FailedNodes -RunId $Report.ClusterResult.RunId
}