Shutdown/Start VM from Hyper-v Cluster remotely with PS script

%3CLINGO-SUB%20id%3D%22lingo-sub-2233666%22%20slang%3D%22en-US%22%3EShutdown%2FStart%20VM%20from%20Hyper-v%20Cluster%20remotely%20with%20PS%20script%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2233666%22%20slang%3D%22en-US%22%3E%3CP%3EHello%2C%20this%20is%20my%20first%20script%20that%20I%20manage%20to%20create%20from%20start%20to%20finish.%3C%2FP%3E%3CP%3EWhat%20it%20does%20it%20connects%20to%20a%20Hyper-V%20Cluster%2C%20looks%20for%20a%20specific%20VM%20in%20that%20cluster%20and%20retains%20the%20node%20that%20it%20resides%20on%2C%20then%20connects%20to%20the%20node%20to%20shutdown%2Fstart%20the%20VM.%3C%2FP%3E%3CP%3EI%20made%20it%20like%20this%20because%20using%20the%20specific%20cluster%20Hyper-V%20commands%20(%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fpowershell%2Fmodule%2Ffailoverclusters%2Fstop-clusterresource%3Fview%3Dwindowsserver2019-ps%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EStop-ClusterResource%3C%2FA%3E)%20doesn't%20do%20a%20complete%20shutdown%2C%20it%20just%20puts%20the%20VM%20on%20a%20sleep%2Fpause%20state.%3C%2FP%3E%3CP%3EIf%20you%20have%20any%20advice%20on%20how%20to%20improve%20this%20I%20would%20be%20grateful.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%23%20password%20saved%20in%20.txt%3CBR%20%2F%3E%23(Get-Credential).Password%20%7C%20ConvertFrom-SecureString%20%7C%20Out-File%20-PSPath%20C%3A%5CScripts%5CpassCLU.txt%3C%2FP%3E%3CP%3E%24path%20%3D%20%22E%3A%5CScripts%5CpassCLU.txt%22%3CBR%20%2F%3E%24CLUIP%20%3D%20%22--.22%22%3CBR%20%2F%3E%24LogID%20%3D%20%22-%22%3CBR%20%2F%3E%24Node1IP%20%3D%20%22--.20%22%3CBR%20%2F%3E%24Node2IP%20%3D%20%22--.21%22%3CBR%20%2F%3E%24Node3IP%20%3D%20%22--.24%22%3CBR%20%2F%3E%24Node4IP%20%3D%20%22--.25%22%3CBR%20%2F%3E%24VM%20%3D%22-%22%20%23couldn%20t%20pass%20this%20variable%20through%20invoke-command%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ESet-Item%20WSMan%3A%5Clocalhost%5CClient%5CTrustedHosts%20-Value%20%22--.22%2C--.20%2C--.21%2C--.24%2C--.25%22%20-Force%3C%2FP%3E%3CP%3E%23retrieves%20the%20password%20and%20creates%20the%20credentials%3C%2FP%3E%3CP%3Efunction%20InitPassword(%24path%2C%20%24LogID)%20%7B%3CBR%20%2F%3E%3CBR%20%2F%3E%24global%3Apassword%20%3D%20Get-Content%20-Path%20%24path%20%7C%20ConvertTo-SecureString%3CBR%20%2F%3E%24global%3Acred%20%3D%20New-Object%20System.Management.Automation.PSCredential%20(%24LogID%2C%20%24global%3Apassword)%3CBR%20%2F%3E%7D%3C%2FP%3E%3CP%3E%3CBR%20%2F%3E%3CBR%20%2F%3Efunction%20Connect(%24NodeIP)%7B%3CBR%20%2F%3E%3CBR%20%2F%3E%24global%3Asession%20%3D%20New-PSSession%20-ComputerName%20%24NodeIP%20-Credential%20%24global%3Acred%3C%2FP%3E%3CP%3E%7D%3C%2FP%3E%3CP%3E%3CBR%20%2F%3EInitPassword%20%24path%20%24LogID%3C%2FP%3E%3CP%3E%3CBR%20%2F%3EConnect%20%24CLUIP%3C%2FP%3E%3CP%3E%23searches%20on%20the%20cluster%20for%20the%20node%20owner%20of%20the%20specific%20VM%3CBR%20%2F%3E%3CBR%20%2F%3E%24OwnerInf%20%3D%20Invoke-Command%20-Session%20%24global%3Asession%20-ScriptBlock%20%7B%3CBR%20%2F%3E%24grClu%20%3D%20Get-ClusterGroup%20%7C%20where%20%7B%24_.Name%20-eq%20%22-%22%20%7D%3CBR%20%2F%3E%24OwnerNode%20%3D%20%24grClu.OwnerNode%3CBR%20%2F%3E%3CBR%20%2F%3Ereturn%20%24OwnerNode%3CBR%20%2F%3E%7D%3C%2FP%3E%3CP%3EGet-PSSession%20%7C%20Remove-PSSession%3C%2FP%3E%3CP%3E%3CBR%20%2F%3E%24NodeName%3D%24OwnerInf.NodeName%3C%2FP%3E%3CP%3E%3CBR%20%2F%3Eif(%24NodeName%20-eq%20%22NODE1%22)%7B%3CBR%20%2F%3EConnect%20%24Node1IP%7D%3CBR%20%2F%3E%3CBR%20%2F%3Eif(%24NodeName%20-eq%20%22NODE2%22)%7B%3CBR%20%2F%3EConnect%20%24Node2IP%7D%3C%2FP%3E%3CP%3Eif(%24NodeName%20-eq%20%22NODE3%22)%7B%3CBR%20%2F%3EConnect%20%24Node3IP%7D%3C%2FP%3E%3CP%3Eif(%24NodeName%20-eq%20%22NODE4%22)%7B%3CBR%20%2F%3EConnect%20%24Node4IP%7D%3C%2FP%3E%3CP%3E%3CBR%20%2F%3Eif(%24args%5B0%5D%20-eq%20%22stop%22)%7B%3CBR%20%2F%3EInvoke-Command%20-Session%20%24global%3Asession%20-ScriptBlock%20%7BStop-VM%20-VMName%20%22-%22%20-force%20%7D%7D%3CBR%20%2F%3Eelse%7B%3CBR%20%2F%3EInvoke-Command%20-Session%20%24global%3Asession%20-ScriptBlock%20%7BStart-vm%20-VMName%20%22-%22%20%7D%7D%3C%2FP%3E%3CP%3E%3CBR%20%2F%3EGet-PSSession%20%7C%20Remove-PSSession%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-LABS%20id%3D%22lingo-labs-2233666%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3EWindows%20Server%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2256362%22%20slang%3D%22en-US%22%3ERe%3A%20Shutdown%2FStart%20VM%20from%20Hyper-v%20Cluster%20remotely%20with%20PS%20script%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2256362%22%20slang%3D%22en-US%22%3EHi%2C%3CBR%20%2F%3ESo%20what%20you%20are%20looking%20for%20is%20to%20completely%20shut%20down%20the%20VM%2C%20instead%20of%20placing%20it%20on%20hold%3F%20yes%3F%3C%2FLINGO-BODY%3E
Occasional Visitor

Hello, this is my first script that I manage to create from start to finish.

What it does it connects to a Hyper-V Cluster, looks for a specific VM in that cluster and retains the node that it resides on, then connects to the node to shutdown/start the VM.

I made it like this because using the specific cluster Hyper-V commands (Stop-ClusterResource) doesn't do a complete shutdown, it just puts the VM on a sleep/pause state.

If you have any advice on how to improve this I would be grateful.

 

# password saved in .txt
#(Get-Credential).Password | ConvertFrom-SecureString | Out-File -PSPath C:\Scripts\passCLU.txt

$path = "E:\Scripts\passCLU.txt"
$CLUIP = "--.22"
$LogID = "-"
$Node1IP = "--.20"
$Node2IP = "--.21"
$Node3IP = "--.24"
$Node4IP = "--.25"
$VM ="-" #couldn t pass this variable through invoke-command

 

Set-Item WSMan:\localhost\Client\TrustedHosts -Value "--.22,--.20,--.21,--.24,--.25" -Force

#retrieves the password and creates the credentials

function InitPassword($path, $LogID) {

$global:password = Get-Content -Path $path | ConvertTo-SecureString
$global:cred = New-Object System.Management.Automation.PSCredential ($LogID, $global:password)
}



function Connect($NodeIP){

$global:session = New-PSSession -ComputerName $NodeIP -Credential $global:cred

}


InitPassword $path $LogID


Connect $CLUIP

#searches on the cluster for the node owner of the specific VM

$OwnerInf = Invoke-Command -Session $global:session -ScriptBlock {
$grClu = Get-ClusterGroup | where {$_.Name -eq "-" }
$OwnerNode = $grClu.OwnerNode

return $OwnerNode
}

Get-PSSession | Remove-PSSession


$NodeName=$OwnerInf.NodeName


if($NodeName -eq "NODE1"){
Connect $Node1IP}

if($NodeName -eq "NODE2"){
Connect $Node2IP}

if($NodeName -eq "NODE3"){
Connect $Node3IP}

if($NodeName -eq "NODE4"){
Connect $Node4IP}


if($args[0] -eq "stop"){
Invoke-Command -Session $global:session -ScriptBlock {Stop-VM -VMName "-" -force }}
else{
Invoke-Command -Session $global:session -ScriptBlock {Start-vm -VMName "-" }}


Get-PSSession | Remove-PSSession

 

1 Reply
Hi,
So what you are looking for is to completely shut down the VM, instead of placing it on hold? yes?