Script to update VMware VM Virtual Hardware – compatibility level

By | February 13, 2019

Many of us have upgraded our VCenter and ESXi hosts and then stepped back and forgot to upgrade the virtual hardware and VMTools. This can lead to problems with performance and compatibility. Problem is that in order to upgrade the virtual hardware you have to shutdown the machine, right click, upgrade hardware etc, very long winded process. Thankfully Powershell/PowerCli makes life so much easier.

First start by enabling all VMs to upgrade VMTools on reboot. This can be done live and requires no downtime, simply ticks the box to check VMtools on reboot.

$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$vmConfigSpec.Tools = New-Object VMware.Vim.ToolsConfigInfo
$vmConfigSpec.Tools.ToolsUpgradePolicy = "UpgradeAtPowerCycle"

Get-View -ViewType VirtualMachine | %{
   $_.ReconfigVM($vmConfigSpec)
} 

Once that is complete every time a VM reboots it will check and upgrade the VMTools making life easier.

Now create the following script

Connect-VIServer -Server YOURvCenter

#email setup
$PSEmailServer = "smtp.yourmailserver.com"
$fromemail = "powershell@yourmailserver.com"
$toemail = "you@yourmailserver.com"
$emailSubject = "VM Hardware and tools update"
$emailBody = ""

#This gets VMs that do not match vmx-14 (esxi 6.7) hardware and also excludes some machines based on name that you may want to leave
$toUpdate = Get-VM | Where-Object {$_.HardwareVersion -notlike "vmx-14" -and $_.Name -notmatch "AVappliance*|Appliance*|YOURvCenter" -and $_.PowerState -ne "Poweredoff"}

#this section goes through each machine in turn, shuts it down, upgrades, and then powers on sending an email when complete
$toUpdate | ForEach-Object {
    $emailBody = "Updating ",$_.name,"`n Current HW version",$_.HardwareVersion,"`n"
    #New-Snapshot -vm $_.Name -Memory:$false -Name "Before virtual HW upgrade"
    Shutdown-VMGuest -VM $_.Name -Confirm:$false
#simple do while loop making sure VM is in powered off state before continuing
    Do {
        $temp = get-vm -Name $_.Name
        Start-Sleep -Seconds 20
    } While ($temp.PowerState -ne  "PoweredOff")
    Start-Sleep -Seconds 20
#this sets the new hardwareversion, change vmx-14 to required level
    Set-VM -VM $_.name -HardwareVersion vmx-14 -Confirm:$false
    Start-Sleep -Seconds 20
    Start-VM -VM $_.name -Confirm:$false
    $temp = get-vm -Name $_.Name
    $emailBody += "Now HW version",$temp.HardwareVersion,"`n",$temp|fl
    Send-MailMessage -from $fromemail -to $toemail -Subject $emailSubject -Body ( $emailBody | Out-String)
}
Start-Sleep -Seconds 20
Send-MailMessage -from $fromemail -to $toemail -Subject "VM Upgrade complete" -Body "Script complete"

Once complete save the script, you can either run it now or much more likely create a schedule task on a windows machine to run it out of hours as each machine must shutdown.

Simply load up task scheduler in Windows 10 when logged on as an admin user that also has admin rights to VCenter. Create a new basic task to run a program “powershell.exe” with argument of the script i.e. C:\Users\admin\Powershell Scripts\vm-hardwareupgrade.ps1. Schedule a time and allow it to run as an domain account that has admin rights to VCenter. Go to bed and let it do its thing.

Timing wise is hard to advise, the actual time it takes to upgrade the hardware is minimal under 30 seconds but the shutting down of the VM and restarting obviously is the time consuming part. I ran this against 42 VMs majority Windows Server and it took just shy of 2 hrs.