search
top

Using PowerShell to Failover Cluster Resources for Patching

Introduction

So you are having to patch cluster nodes and would like a way to automate the failover of the resources and log what when it was done and who did the work. In this post we will cover a simple PowerShell script that will drain and pull resources in a 2 node active / passive cluster.

About the Script

The purpose of the PowerShell script is to allow two operations to occur, they are to drain all the resources on the node you are running the script on to the other node in the two node cluster and the other is to bring all (pullall) the resources from a node to the node. While doing this to also create a local log file  and also to create a Event in the Application event log. Using this script you can automate patching of clusters with SCCM and other methods. Another note is that the script be able to work on Windows Server 2008, 2008 R2, 2012 and 2012 R2 versions.

To achieve this we will create two functions and also set a string parameter to look for drain and pullall at the PowerShell command line. For the PowerShell cluster operations we will be using the FailOverClusters module and several get cmdlets such as Get-ClusterGroup, Get-ClusterResource, Move-ClusterGroup and Get-ClusterNode.

For the logging events portion we will be capturing who is doing the failover, the date and time and what operation is performed into the local logfile stored in c:\support directory using Out-File and Add-Content cmdlets. For the Event logging we will use the Write-EventLog cmdlet and create the event in Application Log. Below is the script and is fairly easy to read and can be modified to your liking. In a future post we will add the balance feature to allow this script to be used to send Cluster Groups to preferred owners in Active / Active clusters and some error checking.

The Script

Here is the script in it’s entirety. Download Now

<# 
           .SYNOPSIS  
           This script will Pull or drain cluster resources from the command line. 
 
           .DESCRIPTION 
           The script will Pull or drain cluster resources from the command line. 
           
           .NOTES 
           File Name : ClusterResourceMover.ps1
           Authors   : 
           Requires  : Windows Server 2012 R2 PowerShell
                       Windows Server 2012 R2 Clustering Cmdlets 
                       Windows Server 2008 R2 PowerShell
                       Windows Server 2008 R2 Clustering Cmdlets 
           Version   : 1.0 (July 26 2016)
     
           .PARAMETER drain or pullall 
           Specifies send, retrieve or delegate cluster resources 
 
           .INPUTS 
           ClusterResourceMover2 accepts drain and pullall 
 
           .OUTPUTS 
           Log to c:\support directory and log to EventLog. 
 
           .EXAMPLE 
           C:\PS> .\ClusterResourceMover drain # drains all cluster resources to the other node. 
            
           .EXAMPLE 
           C:\PS> .\ClusterResourceMover pullall # Retrives all cluster resources to the current node.
           
#> 
# Get User input and execute function Must be first line in code and not in a function.

Param([Parameter(Mandatory=$true,HelpMessage="Enter in drain, pullall")][String]$ClusOp)

# Create Local logfile
$node = hostname
$date1=Get-Date -Format "yyyy-MM-dd hh:mm tt"
$admin = (Get-Content -Path env:username).ToString()
$LogFileName = "c:\Support\ClusterResMove-"+ $node +".txt"
Out-File -append -FilePath $LogFileName -Encoding ASCII
Add-Content -Path $LogFileName -Value "Computer: $node" -Encoding ASCII
Add-Content -Path $LogFileName -Value "*****************************" -Encoding ASCII


Function Drain {
Write-EventLog -LogName "Application" -Source "ServerMaint" -EventID 101 -EntryType Information -Message "Cluster Drain Operation started for Windows Patching"
Import-Module FailoverClusters
Add-Content -Path $LogFileName -Value "Date: $date1" -Encoding ASCII
Add-Content -Path $LogFileName -Value "Executed By: $admin" -Encoding ASCII
Add-Content -Path $LogFileName -Value "Current Cluster Assignments" -Encoding ASCII
Get-ClusterGroup | Out-File -append  -Encoding ASCII -FilePath $LogFileName 
$computer = get-content env:computername
$computer = $computer.ToLower()
$destnode = Get-clusternode | select Name

# Convert to string for use in foreach-object
[string]$drainnode = ($destnode.Name -ne $computer) 

Get-ClusterGroup |
foreach-object `
    {
    If ($_.Name -ne $computer)
        {
        Move-ClusterGroup -Name $_.Name -Node $drainnode
        }
    
    }
    
Add-Content -Path $LogFileName -Value "Drain Operation Completed to $drainnode " -Encoding ASCII
Add-Content -Path $LogFileName -Value "New Cluster Assignments" -Encoding ASCII
Get-ClusterGroup | Out-File -append  -Encoding ASCII -FilePath $LogFileName
Write-EventLog -LogName "Application" -Source "ServerMaint" -EventID 201 -EntryType Information -Message "Cluster Drain Operation completed for Windows Patching"
}

Function PullAll {
Write-EventLog -LogName "Application"  -Source "ServerMaint" -EventID 101 -EntryType Information -Message "Cluster PullAll Operation Started for Windows Patching"
Import-Module FailoverClusters
Add-Content -Path $LogFileName -Value "Date: $date1" -Encoding ASCII
Add-Content -Path $LogFileName -Value "Executed By: $admin" -Encoding ASCII
Add-Content -Path $LogFileName -Value "Current Cluster Assignments" -Encoding ASCII
Get-ClusterGroup | Out-File -append  -Encoding ASCII -FilePath $LogFileName 
$computer = get-content env:computername
$computer = $computer.ToLower()
Get-clusternode | Get-ClusterGroup |
foreach-object `
    {
    
    If ($_.Name -ne $computer)
        { 
        Move-ClusterGroup -Name $_.Name -Node $computer
        }
    }
Add-Content -Path $LogFileName -Value "PullAll Operation Completed to $computer " -Encoding ASCII
Add-Content -Path $LogFileName -Value "New Cluster Assignments" -Encoding ASCII
Get-ClusterGroup | Out-File -append  -Encoding ASCII -FilePath $LogFileName
Write-EventLog -LogName "Application" -Source "ServerMaint" -EventID 201 -EntryType Information -Message "Cluster PullAll Operation completed for Windows Patching"
}

# Take the parameter and validate the input and call the functions.
If ("drain","pullall" -NotContains $ClusOp) 
  { 
    Throw "Not a valid option! Please use drain, pullall or balance option" | Out-File -append  -Encoding ASCII -FilePath $LogFileName 
  } 
        
 # All parameters are valid call function 
If ($ClusOp -eq "drain") { Drain }
If ($ClusOp -eq "pullall") { PullAll }

 

So we have the script, how do we run it and what does it look like?  By running ClusterResourceMover2 drain or ClusterResourceMover2 pullall we can make the script do its magic.

clustermovepullall

Conclusion

So we see it is possible to use the FailoverClusters PowerShell module to automate patching of Windows Servers 2008 / 2012 clusters and also log operations for tracking. Stay tuned for more features being added to this script!

Leave a Reply

Your email address will not be published. Required fields are marked *

top