Created
June 5, 2012 16:08
-
-
Save jwcarroll/2875967 to your computer and use it in GitHub Desktop.
A set of functions that can be used to automate a cluster using NLB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Name: Network Load Balancer Functions | |
# Description: Collection of functions for managing NLB on 2003 machines | |
# Author: Josh Carroll | |
Add-Type @' | |
public class NLBStatusCode | |
{ | |
public NLBStatusCode(int code, string name, System.ConsoleColor color){ | |
_code = code; | |
_name = name; | |
_color = color; | |
} | |
private int _code; | |
public int Code { | |
get { return _code; } | |
} | |
private string _name; | |
public string Name { | |
get { return _name; } | |
} | |
private System.ConsoleColor _color; | |
public System.ConsoleColor Color { | |
get { return _color; } | |
} | |
public override System.String ToString() { | |
return System.String.Format("{0} ({1})", Name,Code); | |
} | |
} | |
'@ | |
<# | |
.SYNOPSIS | |
Retrieves a single Node on an NLB Cluster by Machine/IP | |
.DESCRIPTION | |
This function queries a machine uwing WMI in order to retrieve a single Node object. | |
.PARAMETER nodeIp | |
The dedicated IP address of the Node in the NLB cluster | |
.PARAMETER computerName | |
Optional parameter to specify the machine name where the Node lives. Defaults to running computer name. | |
.PARAMETER credentials | |
Optional PSCredentials Object to use when making the WMI call to a remote machine. By default the current users credentials are used in the query. | |
.EXAMPLE | |
GetNode "10.1.1.100" | |
Description | |
----------- | |
Returns the node with dedicated IP of "10.1.1.100" on local machine | |
.EXAMPLE | |
GetNode "10.1.1.100" "server1" | |
Description | |
----------- | |
Returns the node with dedicated IP of "10.1.1.100" on remote machine using executing users credentials. | |
.EXAMPLE | |
$devpass = ConvertTo-SecureString "MyPassword" -AsPlainText -Force | |
C:\PS> $devlogin = new-object -typename System.Management.Automation.PSCredential -argumentlist "devuser@domain.net",$devpass | |
C:\PS> GetNode "10.1.1.100" "server1" $devlogin | |
Description | |
----------- | |
Returns the node with dedicated IP of "10.1.1.100" on remote machine using specified credentials | |
.EXAMPLE | |
$devpass = ConvertTo-SecureString "MyPassword" -AsPlainText -Force | |
C:\PS> $devlogin = new-object -typename System.Management.Automation.PSCredential -argumentlist "devuser@domain.net",$devpass | |
C:\PS> $node = GetNode "10.1.1.100" "server1" $devlogin | |
C:\PS> $node.DrainStop() | |
Description | |
----------- | |
Returns a node and then drainstops it. | |
.LINK | |
GetAllNodes | |
DrainStopAll | |
DrainStopAllAndWait | |
StartAll | |
StartAllAndWait | |
WaitForStatus | |
GetNodeStatus | |
#> | |
Function GetNode | |
{ | |
Param([string]$nodeIp, [string]$computerName=$env:computername, $credentials="") | |
if($credentials -eq ""){ | |
get-wmiobject -class MicrosoftNLB_Node -namespace "root/MicrosoftNLB" -computer $computerName | where-object {$_.DedicatedIPAddress -eq $nodeIp} | |
} | |
else{ | |
get-wmiobject -class MicrosoftNLB_Node -namespace "root/MicrosoftNLB" -computer $computerName -credential $credentials -authentication 6 | where-object {$_.DedicatedIPAddress -eq $nodeIp} | |
} | |
} | |
<# | |
.SYNOPSIS | |
Gets all nodes that are associated with a single machine | |
.DESCRIPTION | |
Given a computer name, a WMI query will be performed which returns all NLB Nodes associated with that machine. | |
.PARAMETER computerName | |
Optional parameter to specify the machine name where the Node lives. Defaults to running computer name. | |
.PARAMETER credentials | |
Optional PSCredentials Object to use when making the WMI call to a remote machine. By default the current users credentials are used in the query. | |
.EXAMPLE | |
GetAllNodes server1 | |
Description | |
----------- | |
Returns all available nodes associated with a remote machine using currently logged in users credentials. | |
.EXAMPLE | |
$devpass = ConvertTo-SecureString "MyPassword" -AsPlainText -Force | |
C:\PS>$devlogin = new-object -typename System.Management.Automation.PSCredential -argumentlist "devuser@domain.net",$devpass | |
C:\PS>GetAllNodes server1 $devlogin | |
Description | |
----------- | |
Returns all available nodes associated with a remote machine using provided credentials. | |
.LINK | |
GetNode | |
DrainStopAll | |
DrainStopAllAndWait | |
StartAll | |
StartAllAndWait | |
WaitForStatus | |
GetNodeStatus | |
#> | |
Function GetAllNodes | |
{ | |
Param([string]$computerName=$env:computername, $credentials="") | |
if($credentials -eq ""){ | |
get-wmiobject -class MicrosoftNLB_Node -namespace "root/MicrosoftNLB" -computer $computerName -ErrorAction SilentlyContinue | |
} | |
else{ | |
get-wmiobject -class MicrosoftNLB_Node -namespace "root/MicrosoftNLB" -computer $computerName -credential $credentials -authentication 6 -ErrorAction SilentlyContinue | |
} | |
} | |
Function GetNodeList | |
{ | |
Param($credentials="", [string[]]$computerNames) | |
$nodeList = New-Object 'System.Collections.Generic.List[object]' | |
foreach($computerName in $computerNames){ | |
$nodes = GetAllNodes $computerName $credentials | |
if(!$nodes){ | |
$nodes = @((CreateUndefinedNode $computerName)) | |
} | |
foreach($node in $nodes){ | |
$nodeList.Add($node) | |
} | |
} | |
$nodeList | |
} | |
<# | |
.SYNOPSIS | |
Performs a drainstop operation on every node on specified machine(s). | |
.DESCRIPTION | |
This operation will query each machine specified and issue a drainstop command for each node found. It does not wait for that operation to complete. | |
.PARAMETER credentials | |
Optional PSCredentials Object to use when making the WMI call to a remote machine. By default the current users credentials are used in the query. | |
.PARAMETER computerNames | |
An array of computer names that will be queried for their associated NLB Nodes. | |
.EXAMPLE | |
DrainStopAll -computerNames ("server1","server2") | |
Description | |
----------- | |
Issues a drainstop command for all nodes on "server1" and "server2" using currently logged in users credentials | |
.LINK | |
GetNode | |
GetAllNodes | |
DrainStopAllAndWait | |
StartAll | |
StartAllAndWait | |
WaitForStatus | |
GetNodeStatus | |
#> | |
Function DrainStopAll | |
{ | |
Param($credentials="", [string[]]$computerNames) | |
foreach($computerName in $computerNames){ | |
$nodes = GetAllNodes $computerName $credentials | |
foreach($node in $nodes){ | |
$ip = ($node).DedicatedIPAddress | |
$name = ($node).ComputerName | |
$output = "Drainstopping: {0,-15} {1,-30}" -f $ip, $name | |
Write-Host $output | |
($node).DrainStop() | |
} | |
} | |
} | |
<# | |
.SYNOPSIS | |
Performs a drainstop operation on every node on specified machine(s), and waits for the operation to complete successfully. | |
.DESCRIPTION | |
This operation will query each machine specified and issue a drainstop command for each node found. | |
It will poll on a regular interval to see if the operation has completed successfully. | |
A timeout can be specified to exit the function if the nodes have not reached their desired state within that timeframe. | |
.PARAMETER refreshRate | |
The amount of time, in seconds, between checking to see if all nodes have reached the "Stopped" state. Default is 30 seconds. | |
.PARAMETER timeoutSeconds | |
The maximum amount of time in seconds to before polling ceases and the function exits. Default is 5 minutes. | |
.PARAMETER forceStopOnTimeout | |
Optional parameter that will issue a stop command if nodes have not stopped when the timeout is reached. | |
.PARAMETER credentials | |
Optional PSCredentials Object to use when making the WMI call to a remote machine. By default the current users credentials are used in the query. | |
.PARAMETER computerNames | |
An array of computer names that will be queried for their associated NLB Nodes. | |
.EXAMPLE | |
DrainStopAllAndWait -refreshRate 10 -timeoutSeconds 1200 -computerNames ("server1","server2") | |
Description | |
----------- | |
Issues a drainstop command for all nodes on "server1" and "server2" using currently logged in users credentials. | |
This will continue to poll every 10 seconds to see if nodes have stopped, and exit after 20 minutes. | |
.LINK | |
GetNode | |
GetAllNodes | |
DrainStopAll | |
StartAll | |
StartAllAndWait | |
WaitForStatus | |
GetNodeStatus | |
#> | |
Function DrainStopAllAndWait | |
{ | |
Param([int]$refreshRate=30, [int]$timeoutSeconds=300, [bool]$forceStopOnTimeout=$false, $credentials="", [string[]]$computerNames) | |
DrainStopAll $credentials $computerNames | |
Write-Host | |
WaitForStatus "Stopped" $refreshRate $timeoutSeconds $credentials $computerNames | |
if($forceStopOnTimeout){ | |
$nodeList = GetNodeList $credentials $computerNames | |
$nodesNotInTargetStatus = FilterNodesByStatus $nodeList ("Stopped") | |
if($nodesNotInTargetStatus){ | |
Write-Host "Forcing Stop..." | |
Write-Host | |
WriteNodeStatus -writeHeader $true | |
foreach($node in $nodesNotInTargetStatus){ | |
($node).Stop() | |
WriteNodeStatus $node | |
} | |
} | |
} | |
} | |
<# | |
.SYNOPSIS | |
Allows a caller to wait for all nodes on a set of computers to reach a specific status. | |
For a list of available statuses use: | |
GetNLBStatusCode -list $true | |
.DESCRIPTION | |
This operation will query each machine specified and wait for a specific status. | |
It will poll on a regular interval to see if the operation has completed successfully. | |
A timeout can be specified to exit the function if the nodes have not reached their desired state within that timeframe. | |
.PARAMETER statusList | |
An array of Statuses to monitor the nodes for. | |
.PARAMETER refreshRate | |
The amount of time, in seconds, between checking to see if all nodes have reached the specified state. Default is 30 seconds. | |
.PARAMETER timeoutSeconds | |
The maximum amount of time in seconds to before polling ceases and the function exits. Default is 5 minutes. | |
.PARAMETER credentials | |
Optional PSCredentials Object to use when making the WMI call to a remote machine. By default the current users credentials are used in the query. | |
.PARAMETER computerNames | |
An array of computer names that will be queried for their associated NLB Nodes. | |
.EXAMPLE | |
WaitForStatus -statusList ("Started","Converged") -refreshRate 10 -timeoutSeconds 1200 -computerNames ("server1","server2") | |
Description | |
----------- | |
Issues a drainstop command for all nodes on "server1" and "server2" using currently logged in users credentials. | |
This will continue to poll every 10 seconds to see if nodes have stopped, and exit after 20 minutes. | |
.LINK | |
GetNode | |
GetAllNodes | |
DrainStopAll | |
DrainStopAllAndWait | |
StartAll | |
StartAllAndWait | |
GetNodeStatus | |
#> | |
Function WaitForStatus | |
{ | |
Param([string[]]$statusList, [int]$refreshRate=30, [int]$timeoutSeconds=300, $credentials="", [string[]]$computerNames) | |
try{ | |
if($refreshRate -lt 5){ | |
Write-Host "Refresh rate cannot be less than 5 seconds... resetting" | |
$refreshRate = 5 | |
} | |
$nodesNotInTargetStatus | |
$isTimeExpired | |
$sw = New-Object 'System.Diagnostics.Stopwatch' | |
$timeout = [System.TimeSpan]::FromSeconds($timeoutSeconds) | |
$formattedStatusList = [System.String]::Join(",",$statusList) | |
do{ | |
$nodeList = GetNodeList $credentials $computerNames | |
$updateMsg = "Target Status: {0} | Refresh Rate: {1} seconds | Elapsed Time: {2:mm\\:ss}" -f $formattedStatusList,$refreshRate,$sw.Elapsed | |
$nodesNotInTargetStatus = FilterNodesByStatus $nodeList $statusList | |
$isTimeExpired = $sw.Elapsed -ge $timeout | |
Write-Host | |
Write-Host $updateMsg | |
Write-Host | |
WriteNodeStatus -writeHeader $true | |
foreach($node in $nodeList){ | |
WriteNodeStatus $node | |
} | |
Write-Host | |
if($sw.IsRunning -and !$isTimeExpired){ | |
Start-Sleep -s $refreshRate | |
} | |
else{ | |
$sw.Start() | |
} | |
}while($nodesNotInTargetStatus -and !$isTimeExpired) | |
$sw.Stop() | |
if($isTimeExpired){ | |
"Timeout of {0} seconds has been reached." -f $timeoutSeconds | |
} | |
else{ | |
Write-Host | |
"All nodes have reached target status of: {0}" -f $formattedStatusList | |
} | |
Write-Host | |
} | |
catch [System.Exception]{ | |
Write-Error $_.Exception.ToString() | |
} | |
} | |
Function FilterNodesByStatus | |
{ | |
Param($nodeList, [string[]]$statusList) | |
$cmdList = New-Object 'System.Collections.Generic.List[string]' | |
foreach($status in $statusList){ | |
$statusCode = (GetNLBStatusCode $status).Code | |
$cmdItem = "`$_.StatusCode -ne $statusCode" | |
$cmdList.Add($cmdItem) | |
} | |
$cmdBody = [System.String]::Join(" -and ",$cmdList) | |
$cmd = "`$nodeList | where {{{0}}}" -f $cmdBody | |
$ExecutionContext.InvokeCommand.InvokeScript($cmd) | |
} | |
<# | |
.SYNOPSIS | |
Performs a start operation on every node on specified machine(s). | |
.DESCRIPTION | |
This operation will query each machine specified and issue a start command for each node found. It does not wait for that operation to complete. | |
.PARAMETER credentials | |
Optional PSCredentials Object to use when making the WMI call to a remote machine. By default the current users credentials are used in the query. | |
.PARAMETER computerNames | |
An array of computer names that will be queried for their associated NLB Nodes. | |
.EXAMPLE | |
DrainStopAll -computerNames ("server1","server2") | |
Description | |
----------- | |
Issues a start command for all nodes on "server1" and "server2" using currently logged in users credentials | |
.LINK | |
GetNode | |
GetAllNodes | |
DrainStopAll | |
DrainStopAllAndWait | |
StartAllAndWait | |
WaitForStatus | |
GetNodeStatus | |
#> | |
Function StartAll | |
{ | |
Param($credentials="", [string[]]$computerNames) | |
foreach($computerName in $computerNames){ | |
$nodes = GetAllNodes $computerName $credentials | |
foreach($node in $nodes){ | |
$ip = ($node).DedicatedIPAddress | |
$name = ($node).ComputerName | |
$output = "Starting: {0,-15} {1,-30}" -f $ip, $name | |
Write-Host $output | |
($node).Start() | |
} | |
} | |
} | |
<# | |
.SYNOPSIS | |
Performs a start operation on every node on specified machine(s), and waits for the operation to complete successfully. | |
.DESCRIPTION | |
This operation will query each machine specified and issue a drainstop command for each node found. | |
It will poll on a regular interval to see if the operation has completed successfully. | |
A timeout can be specified to exit the function if the nodes have not reached their desired state within that timeframe. | |
.PARAMETER refreshRate | |
The amount of time, in seconds, between checking to see if all nodes have reached the "Started" or "Converged" state. Default is 30 seconds. | |
.PARAMETER timeoutSeconds | |
The maximum amount of time in seconds to before polling ceases and the function exits. Default is 5 minutes. | |
.PARAMETER credentials | |
Optional PSCredentials Object to use when making the WMI call to a remote machine. By default the current users credentials are used in the query. | |
.PARAMETER computerNames | |
An array of computer names that will be queried for their associated NLB Nodes. | |
.EXAMPLE | |
StartAllAndWait -refreshRate 10 -timeoutSeconds 1200 -computerNames ("server1","server2") | |
Description | |
----------- | |
Issues a start command for all nodes on "server1" and "server2" using currently logged in users credentials. | |
This will continue to poll every 10 seconds to see if nodes have started, and exit after 20 minutes. | |
.LINK | |
GetNode | |
GetAllNodes | |
DrainStopAll | |
DrainStopAllAndWait | |
StartAll | |
StartAllAndWait | |
WaitForStatus | |
GetNodeStatus | |
#> | |
Function StartAllAndWait | |
{ | |
Param([int]$refreshRate=30, [int]$timeoutSeconds=300, $credentials="", [string[]]$computerNames) | |
StartAll $credentials $computerNames | |
Write-Host | |
WaitForStatus ("Started","Converged") $refreshRate $timeoutSeconds $credentials $computerNames | |
} | |
<# | |
.SYNOPSIS | |
Returns the current status for all nodes on the computers specified, and displays it in a friendly format. | |
.DESCRIPTION | |
Returns the current status for all nodes on the computers specified, and displays it in a friendly format. | |
.PARAMETER credentials | |
Optional PSCredentials Object to use when making the WMI call to a remote machine. By default the current users credentials are used in the query. | |
.PARAMETER computerNames | |
An array of computer names that will be queried for their associated NLB Nodes. | |
.EXAMPLE | |
GetNodeStatus -computerNames server1,server2 | |
IP Server Status | |
--------------- ------------------------------ ------------------------- | |
10.1.1.100 server1.domain.net Converging | |
10.1.1.102 server2.domain.net Converged | |
Description | |
----------- | |
Returns each node and a snapshot of their current status displayed in a friendly format. | |
.LINK | |
GetAllNodes | |
DrainStopAll | |
DrainStopAllAndWait | |
StartAll | |
StartAllAndWait | |
WaitForStatus | |
GetNodeStatus | |
#> | |
Function GetNodeStatus | |
{ | |
Param($credentials="", [string[]]$computerNames) | |
Write-Host | |
WriteNodeStatus -writeHeader $true | |
foreach($computerName in $computerNames){ | |
$nodes = GetAllNodes $computerName $credentials | |
if(!$nodes){ | |
$nodes = @((CreateUndefinedNode $computerName)) | |
} | |
foreach($node in $nodes){ | |
WriteNodeStatus $node | |
} | |
} | |
Write-Host | |
} | |
Function CreateStatusCodeMappings | |
{ | |
$strCmprIgnoreCase = [System.StringComparer]::OrdinalIgnoreCase | |
$nlbStatusCodeMapping = New-Object -TypeName "System.Collections.Generic.Dictionary[string,System.Object]" -ArgumentList $strCmprIgnoreCase | |
$nlbStatusCodeMapping.Add("Undefined",(New-Object NLBStatusCode @(0,"Undefined",[ConsoleColor]::DarkGray))) | |
$nlbStatusCodeMapping.Add("Stopped",(New-Object NLBStatusCode @(1005,"Stopped",[ConsoleColor]::Red))) | |
$nlbStatusCodeMapping.Add("Converging",(New-Object NLBStatusCode @(1006,"Converging",[ConsoleColor]::Yellow))) | |
$nlbStatusCodeMapping.Add("Converged",(New-Object NLBStatusCode @(1007,"Converged",[ConsoleColor]::DarkGreen))) | |
$nlbStatusCodeMapping.Add("Started",(New-Object NLBStatusCode @(1008,"Started",[ConsoleColor]::Green))) | |
$nlbStatusCodeMapping.Add("Draining",(New-Object NLBStatusCode @(1009,"Draining",[ConsoleColor]::Yellow))) | |
$nlbStatusCodeMapping.Add("Suspended",(New-Object NLBStatusCode @(1013,"Suspended",[ConsoleColor]::Gray))) | |
$nlbStatusCodeMapping | |
} | |
Function CreateUndefinedNode() | |
{ | |
Param([string]$serverName) | |
New-Object PSObject -Property @{ | |
StatusCode = 0; | |
DedicatedIPAddress = "0.0.0.0"; | |
ComputerName = $serverName | |
} | |
} | |
Function WriteNodeStatus() | |
{ | |
Param($node, [bool]$writeHeader=$false) | |
if($writeHeader){ | |
"{0,-15} {1,-30} {2,-25}" -f "IP","Server","Status" | |
"{0,-15} {1,-30} {2,-25}" -f (RepeatString "-" 15),(RepeatString "-" 30),(RepeatString "-" 25) | |
} | |
if($node){ | |
$status = TranslateNodeStatusCode ($node).StatusCode | |
$ip = ($node).DedicatedIPAddress | |
$name = ($node).ComputerName | |
Write-Host ("{0,-15} {1,-30} " -f $ip, $name) -NoNewLine | |
Write-Host ("{0,-25}" -f $status.Name) -ForegroundColor $status.Color | |
} | |
} | |
Function RepeatString() | |
{ | |
Param([string]$str="",[int]$count=1) | |
new-object -TypeName System.String -ArgumentList $str,$count | |
} | |
Function TranslateNodeStatusCode | |
{ | |
Param([int]$statusCode) | |
$codesMap = $nlbStatusCodeMapping | |
switch($statusCode){ | |
0 { $codesMap["Undefined"] } | |
1005 { $codesMap["Stopped"] } | |
1006 { $codesMap["Converging"] } | |
1007 { $codesMap["Converged"] } | |
1008 { $codesMap["Started"] } | |
1009 { $codesMap["Draining"] } | |
1013 { $codesMap["Suspended"] } | |
} | |
} | |
Function GetNLBStatusCode | |
{ | |
Param([string]$statusCode, [boolean]$list=$false) | |
$codesMap = $nlbStatusCodeMapping | |
if($list){ | |
"" | |
"{0,-15} {1,-4}" -f "Status","Code" | |
"{0,-15} {1,-4}" -f (RepeatString "-" 15),(RepeatString "-" 4) | |
foreach($key in $codesMap.Keys){ | |
"{0,-15} {1,-4}" -f $key,$codesMap[$key] | |
} | |
"" | |
} | |
else{ | |
if($codesMap.ContainsKey($statusCode)){ | |
$codesMap[$statusCode] | |
} | |
else{ | |
$codesMap["Undefined"] | |
} | |
} | |
} | |
$nlbStatusCodeMapping = CreateStatusCodeMappings |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment