Last active
October 10, 2018 19:07
-
-
Save mczerniawski/1b28453cf890a3b0578bb7b9e38f0083 to your computer and use it in GitHub Desktop.
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
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