VMware Cloud Community
Vlad_Belo
Enthusiast
Enthusiast
Jump to solution

Migrate VM to another host if exists

Hi

I want to do a check on a nested env, for if there are more than 1 host - move VM to another random
if there are only 1 host on a nested env, just shut them off so later can set the host to maintenance mode.

I got only the part of the moving, need help to check if there are more than 1 host exists on the env

if($vms){
    foreach ($vm in $vms) {
         if($vm.PowerState -ne "PoweredOn"){
             $randhosts = Get-VMHost -Location $clusterName | Get-Random
             Move-VM -VM $vm -Destination $randhosts -Datastore $ds
         }
    }
}

 
I'm looking to add to that part, the check "if there are only 1 Host = Shut down VMs. if there are more than 1 Host, do that script above"

Thanks in advance for the help!

0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

Something like this?

if ($vms) {
    foreach ($vm in $vms) {
        $esx = Get-VMHost -Location $clusterName
        if ($esx.Count -eq 1) {
            Shutdown-VMGuest -VM $vm -Confirm:$false
        } else {
            if ($vm.PowerState -eq "PoweredOn") {
                $randhosts = Get-Random -InputObject $esx -Count 1
                Move-VM -VM $vm -Destination $randhosts -Datastore $ds
            }
        }
    }
}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

44 Replies
LucD
Leadership
Leadership
Jump to solution

Something like this?

if ($vms) {
    foreach ($vm in $vms) {
        $esx = Get-VMHost -Location $clusterName
        if ($esx.Count -eq 1) {
            Shutdown-VMGuest -VM $vm -Confirm:$false
        } else {
            if ($vm.PowerState -eq "PoweredOn") {
                $randhosts = Get-Random -InputObject $esx -Count 1
                Move-VM -VM $vm -Destination $randhosts -Datastore $ds
            }
        }
    }
}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Vlad_Belo
Enthusiast
Enthusiast
Jump to solution

yes sir thats it! forgot about simple count

another unrelated to the post question. but its relevant to the same automation I'm creating
so let me know if you need me to open a new post for that instead of posting in here...

anyway my next question is this (perhaps will be a bit complex one) :

so after the esxi upgrade is done, and im rebooting the nested host 

whats the best way to - wait until the host is connected back on (from 'Not Responding' ) exit it from 'Maintenance' mode
and assign a license to the host

what I do is this: 

$hostUpgrade = $hosts | Install-VMHostPatch -HostPath $dsPath 
if($hostUpgrade -ne $null){     
                if($version -like "8.0*"){
                    $hosts | Set-VMHost -LicenseKey $license8
                }
                else {
                    $hosts | Set-VMHost -LicenseKey $license7
                }

                if($hosts.state -ne "Connected") {
                    do {
                        $hosts | Set-VMHost -State Connected -Confirm:$false 
                    }
                    while($hosts.state -eq "Connected")
                }
                [System.Windows.MessageBox]::Show("The Host Successfully Upgraded!")

}

 

should I change if ($hostUpgrade -ne $null) to -ne $error  perhaps?

and is that the correct way to do "wait until the host is back on" ?
because when I just go with 'while' its keep "Set VM Host" even when its already connected and not in maintenance mode.

 

Thanks in advance for the help

0 Kudos
LucD
Leadership
Leadership
Jump to solution

The Install-VMHostPatch cmdlet can result in 2 outcomes afaik.
If all went well, a VMHostPatchResult object is returned.
In that case your -ne $null would be ok.
I personally would check if there actually was an Install-VMHostPatch object returned.

 

if($hostUpgrade -is [VMware.VimAutomation.ViCore.Types.V1.Host.VMHostPatchResult]){

 


If things go wrong, I would force the cmdlet to end with an Exception.
The best way to handle those would be with a Try-Catch construct.
Something along these lines perhaps

 

$hosts | ForEach-Object {
    try {
        $hostUpgrade = Install-VMHostPatch -VMHost $_ -HostPath $dsPath -ErrorAction Stop
        if ($hostUpgrade -is [VMware.VimAutomation.ViCore.Types.V1.Host.VMHostPatchResult]) {
            # Your other post-patch commands
        }
    } catch {
        Write-Host "Error: $_"
    }
}

 

To check if the ESXi node needs a reconnection you can use the NeedsReconnect property in the VMHostPatchResult object.
If that property equals $true, you will need to do the reconcect.
If not, proceed.
Then leave the Maintenance mode, but I would always first check if the ESXi node is "Connected".


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Vlad_Belo
Enthusiast
Enthusiast
Jump to solution

just tried this 

if($hostUpgrade -is [VMware.VimAutomation.ViCore.Types.V1.Host.VMHostPatchResult]){

and it did not work. none of the commands inside 

the 

if($hostUpgrade -ne $null){

is working fine, I just trying to do the best of this part:

if($version -like "8.0*"){
   $hosts | Set-VMHost -LicenseKey $license8
}
else {
   $hosts | Set-VMHost -LicenseKey $license7
}
if($hosts.state -ne "Connected") {
   do {
      $hosts | Set-VMHost -State Connected -Confirm:$false 
   }
   while($hosts.state -eq "Connected")
}
[System.Windows.MessageBox]::Show("The Host Successfully Upgraded!")

 

will that be the correct or best way to do the following as the script indicates:

If the selected version to upgrade is to 8 = assign the license8 to the host, otherwise assign license7

and second part, after the upgrade done, the *Nested* host required reboot so While its rebooting, as in 'Not Responding' wait for it and dont exit script, and then when its on and back in 'Maintenance' mode exit the maintenance mode and connect the host back.

and then finish the upgrade script

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Did you check what is in $hostUpgrade?
Is it a single object?
And what is the type

$hostUpgrade.Count
$hostUpgrade.GetType()


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Vlad_Belo
Enthusiast
Enthusiast
Jump to solution

the count print back '209'

and the get type prints back lot of info, which one am looking for?

the name is Object[]

the MemberType is TypeInfo

and there are alot more info

0 Kudos
LucD
Leadership
Leadership
Jump to solution

That is what I suspected, the result is from multiple ESXi nodes.
That is why a had a loop over $hosts in the snippet I posted earlier.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Vlad_Belo
Enthusiast
Enthusiast
Jump to solution

I see. I can stay with -ne $null its fine for me since its getting the results 

Edit: actually I am selecting each time only 1 esx, why does it still get multiple esx nodes?

 

I only struggle a bit with the other part I posted, the waiting for host to connect etc

if you could help me with that please?

Tags (1)
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Since $hostUpdate is an array with 2309 (?) elements, your comparison with $null will not really work.
You will not detect that perhaps one or more patches failed.
See the PossibleIncorrectComparisonWithNull article for some background.

On the ESXi node connected issue, does $hosts contain more than 1 ESXi node?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Vlad_Belo
Enthusiast
Enthusiast
Jump to solution

the $hostUpdate is an array with 209 elements looks like yes. atleast for the .count

I'm selecting every time only 1 ESXi host like this - 

$HostIP = "ip"

$hosts = Get-VMHost | ?{$_.Name -like $HostIP}

so it will only get one esxi, which ever one I input

I just named the variable $hosts (plural) for my convenient. it might as well be just $host or $esxi or what ever singular variable name will be more convenient 

 

0 Kudos
LucD
Leadership
Leadership
Jump to solution

On the patching concept.
When you do an Install-VMHostPatch, the returned object(s) each contain 2 properties: NeedsReconnect and NeedRestart.

Depending on the values in those properties, your script needs to take action.
I would do something along these lines (but I haven't tested that code).

try {
    $hostUpgrade = Install-VMHostPatch -VMHost $hosts -HostPath $dsPath -ErrorAction Stop
    if ($hostUpgrade -ne $null) {
        # Make sure is ESXi node connected (state is Connected or Maintenance)
        if($hostUpgrade.NeedsReconnect -contains $true){
            $esx = Set-VMHost -VMHost $hosts -State Connected -Confirm:$false
            while($esx.State -notin "Connected","Maintenance"){
                Start-Sleep -Seconds 5
                $esx = Get-VMHost -VMHost $esx
            }
        }
        # If needed restart the ESXi node
        if ($hostUpgrade.NeedsRestart -contains $true){
            Restart-VMHost -VMHost $hosts -Confirm:$false
        }
        # Wait till ESXi node is rebooting
        $esx = Set-VMHost -VMHost $hosts -State Connected -Confirm:$false
        while($esx.State -ne "NotResponding"){
            Start-Sleep -Seconds 5
            $esx = Get-VMHost -VMHost $esx
        }
        # Now wait till ESXi node is back online
        $esx = Set-VMHost -VMHost $hosts -State Connected -Confirm:$false
        while($esx.State -notin "Connected","Maintenance"){
            Start-Sleep -Seconds 5
            $esx = Get-VMHost -VMHost $esx
        }
        # Leave maintenance mode (if required)
        if($esx.Stat -eq "Maintenance"){
            $esx = Set-VMHost -VMHost $hosts -State Connected -Confirm:$false
        }
    }
} catch {
    Write-Host "Error: $_"
}


 


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Vlad_Belo
Enthusiast
Enthusiast
Jump to solution

the catch got error 

Error: A parameter cannot be found that matches parameter name 'VMHost'.

maybe instead $esx.State and $esx = Set-VMHost should change to the original $hosts ?
like so:

 

if ($hostUpgrade -ne $null) {
                    if($hostUpgrade.NeedsReconnect -contains $true){
                        $hosts | Set-VMHost -State Connected -Confirm:$false
                        while($hosts.State -notin "Connected","Maintenance"){
                            Start-Sleep -Seconds 5
                            $hosts = Get-VMHost -VMHost $hosts
                        }
                    }
                    if ($hostUpgrade.NeedsRestart -contains $true){
                        $hosts | Restart-VMHost -Confirm:$false
                    }
                    $hosts | Set-VMHost -State Connected -Confirm:$false
                    while($hosts.State -ne "NotResponding"){
                        Start-Sleep -Seconds 5
                        $hosts = Get-VMHost -VMHost $hosts
                    }
                    $hosts | Set-VMHost -State Connected -Confirm:$false
                    while($hosts.State -notin "Connected","Maintenance"){
                        Start-Sleep -Seconds 5
                        $hosts = Get-VMHost -VMHost $hosts
                    }
                    if($hosts.Stat -eq "Maintenance"){
                        $hosts | Set-VMHost -State Connected -Confirm:$false
                    }
                }

 

0 Kudos
LucD
Leadership
Leadership
Jump to solution

In which line?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Vlad_Belo
Enthusiast
Enthusiast
Jump to solution

since its try and catch with write-host it doesn't say the error line

but looks like its on every line in 'while'  $esx= Get-VMHost -VMHost $hosts

i tried to change all to $esx and to $hosts. still same error

0 Kudos
LucD
Leadership
Leadership
Jump to solution

My bad, I just noticed that I used

Get-VMHost -VMHost $esx

that should of course be

Get-VMHost -Name $esx.Name


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Vlad_Belo
Enthusiast
Enthusiast
Jump to solution

now its just stuck and not doing anything (after the install patch)

its just exit maintenance mode and thats it.

the ESXi host showing (Reboot Required)

but the script does nothing with it

maybe the statement is wrong should be -is instead of -contains ?
this is what I have now: 

if($hostUpgrade -ne $null){
    # Make sure is ESXi node connected (state is Connected or Maintenance)
    if($hostUpgrade.NeedsReconnect -contains $true){
        $esx = Set-VMHost -VMHost $hosts -State Connected -Confirm:$false
        while($esx.State -notin "Connected","Maintenance"){
            Start-Sleep -Seconds 5
            $esx = Get-VMHost -Name $esx.Name
        }
    }
    # If needed restart the ESXi node
    if ($hostUpgrade.NeedsRestart -contains $true){
        Restart-VMHost -VMHost $hosts -Confirm:$false
    }
    # Wait till ESXi node is rebooting
    $esx = Set-VMHost -VMHost $hosts -State Connected -Confirm:$false
    while($esx.State -ne "NotResponding"){
        Start-Sleep -Seconds 5
        $esx = Get-VMHost -Name $esx.Name
    }
    # Now wait till ESXi node is back online
    $esx = Set-VMHost -VMHost $hosts -State Connected -Confirm:$false
    while($esx.State -notin "Connected","Maintenance"){
        Start-Sleep -Seconds 5
        $esx = Get-VMHost -Name $esx.Name
    }
    # Leave maintenance mode (if required)
    if($esx.Stat -eq "Maintenance"){
        $esx = Set-VMHost -VMHost $hosts -State Connected -Confirm:$false
    }
}

 

Maybe I'm missing something?

0 Kudos
LucD
Leadership
Leadership
Jump to solution

 I assume that $hostUpgrade is an array with an entry for each patch,

I want to test if there is at least one element in that array that says True, hence the -contains


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Vlad_Belo
Enthusiast
Enthusiast
Jump to solution

ok so the state of the script now is that it stuck and do nothing after the install patch is done

exit maintenance mode and stuck doing nothing forward.

no errors no break 

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Now would be a good time to use a debugger like the one in Visual Studio Code, and run the script line by line to see what goes wrong where.
At this point, I have no idea why it happens without actually running the code in your environment I'm afraid.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos