Skip to content

Instantly share code, notes, and snippets.

@systemcenterblog
Last active June 20, 2018 07:15
Show Gist options
  • Save systemcenterblog/6c0ca59c41c9a7ae3f2c36b69e5d1b19 to your computer and use it in GitHub Desktop.
Save systemcenterblog/6c0ca59c41c9a7ae3f2c36b69e5d1b19 to your computer and use it in GitHub Desktop.
<#
Script Disclaimer: The sample scripts provided here are not supported under any Microsoft standard support program or service. All scripts are provided AS IS without warranty of any kind.
Server Group - Drain Stop Script
Collects current operation status of all nodes in Cluster - i.e. Paused, Running
Checks if Localhost is Paused -- $LocalNodeStatus=$True
Checks if additional nodes in cluster are paused $AdditionalNodeStatus=$True
If $LocalNodeStatus=$False and $AdditionalNodeStatus=False Drain Stop the local node
Checks that the local node is in Paused State
Check that all the VM have evacuated the node
If the $LocalNodeStatus=$False or $LocalVMNodeStatus=$False implying the drain stop has not been successful report failure
Issue exit code 1 and revert the node to Running
Author:
Twitter @Syswow64blog
Web: systemcenterblog.co.uk
#>
#//Initialize
$LocalNodeIsPaused = $False
$LocalVMNodeStatus = $False
$OtherNodesOffline = @()
$LocalNode = $env:computername
#//Setting the log location
$env:LogPath = "$env:ProgramData\SystemCenterBlog\Logs"
#// Checking the log path
if((Test-Path $env:logpath) -eq $False)
{
New-Item -path $env:LogPath -type directory
}
#Starting the log file
Start-Transcript -path "$env:LogPath\PatchDrain.log" -append
#// SMTP Config
$mail = 'mail.SystemCenterBlog.co.uk'
$smtp = New-Object Net.Mail.SmtpClient($mail)
$from = 'SCCMReports@SystemCenterBlog.co.uk'
$to = 'Jonathan.Proctor@SystemCenterBlog.co.uk'
$sub = "Patch Start Script on [$LocalNode] $Node"
#// Functions
Function SendMail($subject,$message,[switch] $fail = $False) {
Write-Output "$subject`: $message"
$smtp.Send($from,$to,$subject,$message)
if ($Fail) {Throw $message}
}
Function Check-VMNodeStatus{
Param($NodeName)
Process
{
$count = 0
Do
{
write-host "$NodeName Checking Node has evacuated all running VM's.............. $(get-date)"
start-sleep 5
[void](Suspend-ClusterNode -drain -wait) # Graceful VM migration
#[void](Suspend-ClusterNode -drain -forcedrain -wait) # Forceful VM migration
$count += 1
}
Until (((get-VM).count -eq 0) -or ($count -eq 3))
if ($count -eq 3){return $False}
else {return $True}
}
}
Function Pause-LocalNode{
Param($NodeName)
Process
{
$count = 0
Write-host "$NodeName Drain node ...................... $(get-date)"
Suspend-ClusterNode -drain -wait
#Check that local node has been Paused
Do
{
write-host "$NodeName Checking Node is in a Paused state........................ $(get-date)"
start-sleep 2
$count += 1
#$PausedClusterNodes = Get-WmiObject -Class "MSCluster_Node" -Namespace "root\MSCluster" | Where-Object {$_.state -eq 2}
}
Until ((Get-WmiObject -Class "MSCluster_Node" -Namespace "root\MSCluster" | Where-Object {$_.state -eq 2}).name -eq $NodeName -or $count -eq 60)
if ($count -eq 20)
{
write-host "$NodeName did not enter a Paused state ........................................... $(get-date)"
return $False
}
else
{
write-host "$NodeName is in a Paused state ........................................... $(get-date)"
return $True
}
}
}
Function Write-Output{
Param($Node,$OperationStatus,$NodePaused,$VMStatus)
Process
{
write-host "$Node has Operation Status $OperationStatus ...... $(get-date)"
write-host "$Node $ LocalNodeStatus = $NodePaused .......... $(get-date)"
write-host "$Node $ LocalVMNodeStatus = $VMStatus ............ $(get-date)"
}
}
#Get Cluster Node Status
$ClusterNodes = Get-WmiObject -Class "MSCluster_Node" -Namespace "root\MSCluster"
foreach ($CNode in $ClusterNodes)
{
if($CNode.State -eq 2) # Paused state
{
if ($CNode.name -eq $LocalNode) # check if local node is paused
{
$LocalNodeIsPaused=$True
write-host "Local node in Paused state = $LocalNodeIsPaused -- "$CNode.name" .... $(get-date)"
}
else # another node is paused
{
$OtherNodesOffline += $CNode.name + "," + $CNode.state
write-host "Additional node in Paused State Will not proceed-- "$CNode.name" .... $(get-date)"
}
}
elseif ($CNode.State -eq 1) # Check for Failed state and exit
{
write-host "Node is in failed state = $CNode.name .... $(get-date)"
$OtherNodesOffline += $CNode.name + "," + $CNode.state
}
}
if ($OtherNodesOffline.count -gt 0)
{
if ($LocalNodeIsPaused) # Resume the local node if this is paused also as the SCCM script is going to fail
{
Resume-ClusterNode
}
foreach ($Node in $OtherNodesOffline)
{
$NodeName = $Node.split(",")[0]
$NodeState = $Node.split(",")[1]
write-host ""$NodeName" has Operation Status $NodeState .... $(get-date)"
}
write-host "SCCM Exit code 1................................................$(get-date)"
Return 1
}
else
{
if ($LocalNodeIsPaused -eq $False) # No nodes are paused, pause the local node
{
$LocalNodeIsPaused = Pause-LocalNode -NodeName $LocalNode # try to pause local node
}
if($LocalNodeIsPaused -eq $True) # Only Local Node paused, check VM Count
{
$CheckVMNode = Check-VMNodeStatus -NodeName $LocalNode
Write-Output -Node $LocalNode -OperationStatus 2 -NodePaused $LocalNodeIsPaused -VMStatus $CheckVMNode
if ($CheckVMNode -eq $true) # VM Status is true
{
write-host "SCCM Exit code 0................................................$(get-date)"
Return 0
}
else # VM Status is false
{
write-host "SCCM Exit code 1................................................$(get-date)"
Return 1
}
}
else
{
$NodeStatus = Get-WmiObject -Class "MSCluster_Node" -Namespace "root\MSCluster" | Where-Object {$_.name -like $LocalNode}
$CheckVMNode = Check-VMNodeStatus -NodeName $LocalNode
Write-Output -Node $LocalNode -OperationStatus $NodeStatus.state -NodePaused $LocalNodeIsPaused -VMStatus $CheckVMNode
Write-Host "SCCM Exit code 1................................................$(get-date)"
Return 1
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment