Skip to content

Instantly share code, notes, and snippets.

@mczerniawski
Last active October 10, 2018 19:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mczerniawski/1b28453cf890a3b0578bb7b9e38f0083 to your computer and use it in GitHub Desktop.
Save mczerniawski/1b28453cf890a3b0578bb7b9e38f0083 to your computer and use it in GitHub Desktop.
function Set-ClusterVMPossibleOwner {
<#
.SYNOPSIS
Will configure Possible Owners for Virtual Machine running on Failover Cluster
.DESCRIPTION
Uses Invoke-Command to allow for PSCredential.
If PossibleOwner is provided first will verify if it matches cluster Owner Nodes.
If yes - will set PossibleOwner for given VMs.
If no - will abort.
If $null, or '' is provided will reset PossibleOwner to defaults for given VM. Will query Cluster for possible nodes
Before Possible Owner can be set, VM must be on given node.
First it check if VM is on given node. If not - Migrates. Then verifies again and if all is ok - will set Possible Owner.
.PARAMETER Cluster
Cluster Name
.PARAMETER Credential
Optional PSCredential used to connect to cluster
.PARAMETER VMName
Virtual Machine Name or array of names to process
.PARAMETER PossibleOwner
Possible Owner to set for given VM. If not provided, or null will set to default.
.EXAMPLE
$props = @{
Cluster = 'Cluster1'
VMName = 'VM1'
PossibleOwner = 'Node1','Node2'
}
Set-ClusterVMPossibleOwner @props -Verbose
Will set possible owners to Node1 and Node2 for VM1 on Cluster1
VERBOSE: Processing with default credentials of user {mczerniawski_admin}
VERBOSE: Provided possible owner {Node1} was found in nodes of cluster {Cluster1}
VERBOSE: Provided possible owner {Node2} was found in nodes of cluster {Cluster1}
VERBOSE: Processing VM {VM1}
VERBOSE: Testing current Possible Owner configuration for VM {VM1}
VERBOSE: Current possible owner {Node1,Node2,Node3,Node4,Node5,Node6} for VM {VM1} it not in expected state: {Node1,Node2}
VERBOSE: VM {VM1} on matching Node {Node1,Node2}. Currently on node {Node1}. Processing with Setting Possible Owner
VERBOSE: Setting Possible Owner for VM {VM1} to {Node1,Node2}
Cluster VMName CurrentNode OwnerNode
------- ------ ----------- ---------
Cluster1 VM1 Node1 {Node1, Node2}
.EXAMPLE
$props = @{
Cluster = 'Cluster1'
VMName = 'VM1','VM2'
PossibleOwner = $null
Credential = Get-Credential
}
Set-ClusterVMPossibleOwner @props -Verbose
VERBOSE: Processing with provided credentials {constoso\mczerniawski_admin}
VERBOSE: Provided no Possible Owner. Will reset to default setting
VERBOSE: Processing VM {VM1}
VERBOSE: Testing current Possible Owner configuration for VM {VM1}
VERBOSE: Current possible owner {Node1,Node4} for VM {VM1} it not in expected state: {Node1,Node2,Node3,Node4,Node5,Node6}
VERBOSE: VM {VM1} on matching Node {Node1,Node2,Node3,Node4,Node5,Node6}. Currently on node {Node1}. Processing with Setting Possible Owner
VERBOSE: Setting Possible Owner for VM {VM1} to {Node1,Node2,Node3,Node4,Node5,Node6}
VERBOSE: Processing VM {VM2}
VERBOSE: Testing current Possible Owner configuration for VM {VM2}
VERBOSE: Current possible owner for VM {VM2} set correctly to nodes {Node1,Node2,Node3,Node4,Node5,Node6}
Cluster VMName CurrentNode OwnerNode
------- ------ ----------- ---------
Cluster1 VM1 Node1 {Node1, Node2, Node3, Node4...}
Cluster1 VM2 Node1 {Node1, Node2, Node3, Node4...}
#>
[CmdletBinding()]
param(
[Parameter(Mandatory, HelpMessage = 'Provide Cluster Name',
ValueFromPipeline, ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[System.String]
$Cluster,
[Parameter(Mandatory = $false, HelpMessage = 'Provide Credentials for Cluster',
ValueFromPipeline, ValueFromPipelineByPropertyName)]
[System.Management.Automation.PSCredential]
$Credential,
[Parameter(Mandatory, HelpMessage = 'Provide VMName',
ValueFromPipeline, ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[System.String[]]
$VMName,
[Parameter(Mandatory = $false, HelpMessage = 'Provide Possible Owners Nodes to restrict VM to failover to',
ValueFromPipeline, ValueFromPipelineByPropertyName)]
[System.String[]]
$PossibleOwner
)
begin {
#region PSSession parameters
$connectionParams = @{
ComputerName = $Cluster
}
if ($PSBoundParameters.ContainsKey('Credential')) {
$connectionParams.Credential = $Credential
Write-Verbose -Message "Processing with provided credentials {$($Credential.UserName)}"
}
else {
Write-Verbose -Message "Processing with default credentials of user {$($env:USERNAME)}"
}
$ClusterSession = New-PSSession @connectionParams -ErrorAction Stop
#endregion
#region Validate PossibleOwner
$nodesInCluster = Invoke-Command -Session $ClusterSession -ScriptBlock {
Get-ClusterNode | Select-Object -ExpandProperty Name
}
#null or empty string - reset to defaults
if (-not $PossibleOwner) {
Write-Verbose -Message "Provided no Possible Owner. Will reset to default setting"
$PossibleOwner = $nodesInCluster
}
#check if given hosts given in $PreferredOwner are members of $Cluster
else {
switch (Compare-Object -ReferenceObject @($nodesInCluster) -DifferenceObject @($PossibleOwner) -IncludeEqual ) {
{$PSItem.SideIndicator -eq '=>'} {
Write-Error -Message "Provided possible owner {$($PSItem.InputObject)} not found in nodes of cluster {$Cluster}. Aborting" -ErrorAction Stop
break
}
{$PSItem.SideIndicator -eq '=='} {
Write-Verbose -Message "Provided possible owner {$($PSItem.InputObject)} was found in nodes of cluster {$Cluster}"
}
}
}
#endregion
}
process {
foreach ($VM in $VMName) {
Write-Verbose -Message "Processing VM {$VM}"
$ClusterVM = Invoke-Command -Session $ClusterSession -ScriptBlock {
Get-ClusterResource -Name ('Virtual Machine {0}' -f $USING:VM) -ErrorAction SilentlyContinue | Select-Object *
}
if (-not $ClusterVM) {
Write-Error -Message "VM {$VM} not found on cluster {$Cluster}"
}
else {
#region check current configuration for PossibleOwner
Write-Verbose -Message "Testing current Possible Owner configuration for VM {$VM}"
$currentPossibleOwner = Invoke-Command -Session $ClusterSession -ScriptBlock {
Get-ClusterResource -Name ('Virtual Machine {0}' -f $USING:VM) |
Get-ClusterOwnerNode | Select-Object -ExpandProperty OwnerNodes | Select-Object -ExpandProperty Name
}
#region configuration matches expected state
$compareObjects = Compare-Object -ReferenceObject @($PossibleOwner) -DifferenceObject @($currentPossibleOwner) | Measure-Object | Select-Object -ExpandProperty Count
if ($compareObjects -eq 0) {
Write-Verbose -Message " Current possible owner for VM {$VM} set correctly to nodes {$($PossibleOwner -join ',')}"
}
#endregion
#endregion
else {
Write-Verbose -Message " Current possible owner {$($currentPossibleOwner -join ',')} for VM {$VM} it not in expected state: {$($PossibleOwner -join ',')}"
#region check if VM is currently NOT on any of PossibleOwner nodes and migrate if necessary
if ($PossibleOwner -notcontains $ClusterVM.OwnerNode.Name) {
Write-Verbose -Message " VM {$VM} is not on any of PossibleOwner nodes: {$($PossibleOwner -join ',')}. Currently on node {$($ClusterVM.OwnerNode.Name)}."
Write-Verbose -Message " Clearing current possible owner for VM {$VM} to allow migration"
#region Clear current possible owner
Invoke-Command -Session $ClusterSession -ScriptBlock {
$ClusterNodes = Get-ClusterNode | Select-Object -ExpandProperty Name
Get-ClusterResource -Name ('Virtual Machine {0}' -f $USING:VM) -ErrorAction SilentlyContinue |
Set-ClusterOwnerNode -Owners $ClusterNodes
}
#endregion
#region VM State is Offline - quick migrate
if ($ClusterVM.State.Value -eq 'Offline') {
Write-Verbose -Message " VM {$VM} is turned off. Quick Migrating."
#getting rid of any output after quick migration
[void](Invoke-Command -Session $ClusterSession -ScriptBlock {
Move-ClusterVirtualMachineRole -Name $USING:ClusterVM.OwnerGroup.Name -MigrationType Quick -node ($USING:PossibleOwner)[0]
})
}
#endregion
#region VM State is Online - live migrate
elseif ($ClusterVM.State.Value -eq 'Online') {
Write-Verbose -Message " VM {$VM} is turned on. Live Migrating."
#getting rid of any output after live migration
[void](Invoke-Command -Session $ClusterSession -ScriptBlock {
Move-ClusterVirtualMachineRole -Name $USING:ClusterVM.OwnerGroup.Name -MigrationType Live -node ($USING:PossibleOwner)[0]
})
}
#endregion
#region test if vm is migrated on node[0] of $PossibleOwner
$testClusterVM = Invoke-Command -Session $ClusterSession -ScriptBlock {
Get-ClusterResource -Name ('Virtual Machine {0}' -f $USING:VM) -ErrorAction SilentlyContinue | Select-Object *
}
if ($PossibleOwner -contains $testClusterVM.OwnerNode.Name) {
Write-Verbose -Message "VM {$VM} is on node {$($testClusterVM.OwnerNode.Name)}. Processing"
}
else {
Write-Error -Message "Could not migrate VM {$VM} to matching Node {$($PossibleOwner -join ',')}. Currently on node {$($testClusterVM.OwnerNode.Name)}" -ErrorAction Continue
continue
}
#endregion
}
#endregion
else {
Write-Verbose -Message "VM {$VM} on matching Node {$($PossibleOwner -join ',')}. Currently on node {$($ClusterVM.OwnerNode.Name)}. Processing with Setting Possible Owner"
}
#region Set PossibleOwner
Write-Verbose -Message " Setting Possible Owner for VM {$VM} to {$($PossibleOwner -join ',')}"
Invoke-Command -Session $ClusterSession -ScriptBlock {
Get-ClusterResource -Name ('Virtual Machine {0}' -f $USING:VM) -ErrorAction SilentlyContinue |
Set-ClusterOwnerNode -Owners $USING:PossibleOwner
}
#endregion
}
#region LAST VALIDATION Test current status
$finalVMHVNode = Invoke-Command -Session $ClusterSession -ScriptBlock {
Get-ClusterResource -Name ('Virtual Machine {0}' -f $USING:VM) | Select-Object -ExpandProperty OwnerNode
}
$finalOwnerNode = Invoke-Command -Session $ClusterSession -ScriptBlock {
Get-ClusterResource -Name ('Virtual Machine {0}' -f $USING:VM) |
Get-ClusterOwnerNode | Select-Object -ExpandProperty OwnerNodes | Select-Object -ExpandProperty Name
}
$finalCompareObjects = Compare-Object -ReferenceObject @($PossibleOwner) -DifferenceObject @($finalOwnerNode) | Measure-Object | Select-Object -ExpandProperty Count
if ($finalCompareObjects -eq 0) {
#Write-Verbose -Message "Last Validation! VM {$VM} possible owner is set to {$($testCurrentPossibleOwner -join ',')}"
[pscustomobject]@{
Cluster = $Cluster
VMName = $VM
CurrentNode = $finalVMHVNode
OwnerNode = $finalOwnerNode
}
}
else {
Write-Error -Message "Could not set Possible Owners for VM {$VM} to nodes {$($PossibleOwner -join ',')}." -ErrorAction Continue
}
#endregion
}
}
}
end {
$ClusterSession | Remove-PSSession -ErrorAction SilentlyContinue
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment