Finding vms with vmware tools that need to be upgraded. vmware tools status and version

Right, this is not some rocket science here but still i thought some people may be looking for that.

get-cluster your_cluster |Get-VM|?{$_.Extensiondata.Summary.Guest.ToolsVersionStatus -like 'guestToolsNeedUpgrade'} | select name,@{N='tools vers';E={$_.ExtensionData.Config.Tools.ToolsVersion}},@{N='Tools Status';E={$_.Extensiondata.Summary.Guest.ToolsVersionStatus}}

So i wanted to take cluster ‘your_cluster’ and get all vms in this cluster that have tools status of ‘guestToolsNeedUpgrade’. Well basically that’s pretty much it but i noticed that on large inventory it takes quite time to receive this list. So what might be interesting for people who have bigger vInfrastructure 😉
This query takes
Seconds : 41
So i spend few more minutes to get the same list but using get-view. It took:
Seconds : 1
Milliseconds : 174

And the line:

get-view -ViewType virtualmachine -SearchRoot (get-cluster your_cluster).id -Filter @{'Summary.Guest.ToolsVersionStatus'='guestToolsNeedUpgrade'} | Select Name,@{N='tools ver';E={$_.Config.Tools.ToolsVersion}},@{N='Tools Status';E={$_.Summary.Guest.ToolsVersionStatus}}

So difference is 40 seconds 😉 Output is formatted like this
Name tools ver Tools Status
—- ———- ————
myvm1 8300 guestToolsNeedUpgrade
myvm2 8300 guestToolsNeedUpgrade
…… ….. ……………..

Checking vmware tools upgrade policy using powercli, setting vmware tools upgrade policy

If you want to check what is the policy regarding upgrading vmware tools for vms in cluster, here it is 😉

get-view -ViewType virtualmachine -SearchRoot (get-Cluster 'your-cluster').id | select name,@{N='ToolsUpgradePolicy';E={$_.Config.Tools.ToolsUpgradePolicy } }

If you want to query all vms in VC

get-view -ViewType virtualmachine | select name,@{N='ToolsUpgradePolicy';E={$_.Config.Tools.ToolsUpgradePolicy } }

Ok nice, we know what tools upgrade policy settings have our vms. Now we want to change this settings for example to ‘upgradeAtPowerCycle’. I am assuming that we want to change this setting only for vms that have ‘manual’ settings selected for toolsupgradepolicy. There is no need to force it on all vms.

get-view -ViewType virtualmachine -SearchRoot (get-Cluster 'your_Cluster').id -Filter @{'Config.Tools.ToolsUpgradePolicy' = 'manual' } | select name,@
{N='ToolsUpgradePolicy';E={$_.Config.Tools.ToolsUpgradePolicy } }

If you want to limit the vms for which we will be changing this setting, don’t forget that you still can filter them
|? {$_.guest.guestFamily -eq ‘windowsGuest’}
|? {$_.guest.guestFamily -eq ‘linuxGuest’}
|? {$_.guest.guestFullName -eq ‘Microsoft Windows Server 2008 R2 (64-bit)’}
And so on and on…
for example to apply this only for windows 2k8 r2 64bit, you would select them applying proper filter:

get-view -ViewType virtualmachine -SearchRoot (get-Cluster 'your_Cluster').id -Filter @{'Config.Tools.ToolsUpgradePolicy' = 'manual' } |? {$_.guest.guestFullName -eq 'Microsoft Windows Server 2008 R2 (64-bit)'} |select name,@ {N='ToolsUpgradePolicy';E={$_.Config.Tools.ToolsUpgradePolicy } }

As you can see by running get-view for vms using filter ‘Config.Tools.ToolsUpgradePolicy’ = ‘manual’ , we will select only those which have manual. Alright, now the upgrade part.
Right, so i could not find any cmdlet within powercli to do this. Still let’s not give up on this one yet 😉 What to do in this case ?
Download/extract onyx from While running onyx, select option to run using vSphere client. Make sure that onyx is recording from this moment

So we received vsphere api code that our vSphere client executed.

# ------- ReconfigVM_Task -------

$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.changeVersion = "2012-08-01T08:26:54.934341Z"
$ = New-Object VMware.Vim.ToolsConfigInfo
$ = "manual"

$_this = Get-View -Id 'VirtualMachine-vm-754'

We need to apply this part of code to our vms that have wrong upgradetoolspolicy.
Let’s take our query part here first:

get-view -ViewType virtualmachine -SearchRoot (get-Cluster 'your_Cluster').id -Filter @{'Config.Tools.ToolsUpgradePolicy' = 'manual' }

Those will be our vms
Let’s make a loop for them

Foreach($vmview in get-view -ViewType virtualmachine -SearchRoot (get-Cluster 'your_cluster').id -Filter @{'Config.Tools.ToolsUpgradePolicy' = 'manual' } ) {

Ok, loop with your get-view from vms is ready.

Now let’s take closer look at the configuration spec

$spec = New-Object VMware.Vim.VirtualMachineConfigSpec 
$spec.changeVersion = "2012-08-01T08:26:54.934341Z" 
$ = New-Object VMware.Vim.ToolsConfigInfo 
$ = "manual" 


If you want to read about those objects and their specification in vmware api use the above links. One thing that could be not so simple to understand is the ChangeVersion. The rest should be self explanatory i believe.
1. Create configuration specification object
2. Populate changeversion
3. In order to set the toolsUpgradePolicy property , we have to initialize ToolsConfigInfo object first.
4. Execute method on vsphere api vm object called ReconfigVM_task which takes as a parameter the specification object which we have just created.

ad.2 To be honest it will work even without giving this parameter. It is not necessary. Let’s say we are going to configure this settings, but meanwhile some evil evil evil administrator has changed some other settings in some particular vm on which we are running our loop. Now, as we do not know what has he changed(this evil evil administrator) then we might ask, do we still want to make our change ? IF we do not care about this, i guess there is no point in filling the changeversion at all. If we do, we have first assign to some variable current changeversion number, and then while reconfiguring our vm, give the changeversion on which we wanted to work. If meanwhile (evil evil evil) administrator did some reconfiguration of this machine, the changeversion number will be not equal to our number. Guess what will happen ?

Our change will not proceed as the number does not match. When that evil…il..l… administrator has reconfigured our vm, the changeversion number has changed to some 9999 for example…, but when we started our script, and wrote to variable the current change number it was 7777, so we are trying to do a spec with $spec.changeVersion = “xxxxxx7777” , and it fails because it’s not 7777 anymore but 9999.
Back to our loop 😉

$spec = New-Object VMware.Vim.VirtualMachineConfigSpec 
$ = New-Object VMware.Vim.ToolsConfigInfo 
$ = "upgradeAtPowerCycle" 
Foreach($vmview in get-view -ViewType virtualmachine -SearchRoot (get-Cluster 'my_cluster').id -Filter @{'Config.Tools.ToolsUpgradePolicy' = 'manual' } ) {

And this is it 😉
Lines: 1-3 : We create specification object , we are putting information bout the toolsUpgradePolicy
Lines: 4-6 : In our loop where we query for vms that have manual option for toolsUpgradePolicy, we invoke method ReconfigVM_Task and giving it our $spec specification object
Like i mentioned earlier you could use here the changeversion if you want to be really sure. Where i work i have no evil evil evil admins 😉 No need to set it here ! but… if you have them , do it like this 😉

$spec = New-Object VMware.Vim.VirtualMachineConfigSpec 
$ = New-Object VMware.Vim.ToolsConfigInfo 
$ = "upgradeAtPowerCycle" 
Foreach($vmview in get-view -ViewType virtualmachine -SearchRoot (get-Cluster 'my_cluster').id -Filter @{'Config.Tools.ToolsUpgradePolicy' = 'manual' } ) {

One more example, few seconds ago i had to update this only on vms that were in text file so in order to do that:

$spec = New-Object VMware.Vim.VirtualMachineConfigSpec 
$ = New-Object VMware.Vim.ToolsConfigInfo 
$ = "upgradeAtPowerCycle" 
foreach ($vm in gc c:\vmlist.txt) {
$vmview = get-view -viewtype virtualmachine -Filter @{'name'=$vm}