Upgrade virtual machine hardware using powercli

Now, i know that there are some examples in internet about this but they were not working for me for some reason(still don’t know why).
UpgradeVM_Task SDK ref
So in order to upgrade vmware hardware version you have to execute method called UpgradeVM_Task from virtual machine object.

$myvmid=(get-vm 'myvm').id
(get-view -id $myvmid).UpgradeVM_Task('vmx-08') 

If you want to upgrade to version 7, then you have to use ‘vmx-07’. I am running this against vsphere 5 and it works very well. Now, reading manual it says:
Regarding the ‘Version’ parameter:
“If specified, upgrade to that specified version. If not specified, upgrade to the most current virtual hardware supported on the host.”
But if you will give $null or “” , or nothing, it will just not work. I hope i will get some more information why it behaves like this.
UPDATE 😉

$id=(get-vm 'myvm').id
$vmview=get-view -id $id
$param = @($null)
$vmview.gettype().GetMethod("UpgradeVM_Task").Invoke($vmview,$param)

This will run upgrade_VM_Task method without specifying the version string. It took me some time to figure this out 😉
$vmview.gettype().GetMethod(“UpgradeVM_Task”).GetParameters()

ParameterType : System.String
Name : version
DefaultValue :
RawDefaultValue :
Position : 0
Attributes : None
Member : VMware.Vim.ManagedObjectReference UpgradeVM_Task(System.String) -> 1 parameter

the parameter should be an array of 1 null here
$param=@($null)
as per
Invoke(System.Object obj, System.Object[] parameters)

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 ?
Onyx!
Download/extract onyx from vmware.com. 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"
$spec.tools = New-Object VMware.Vim.ToolsConfigInfo
$spec.tools.toolsUpgradePolicy = "manual"

$_this = Get-View -Id 'VirtualMachine-vm-754'
$_this.ReconfigVM_Task($spec)
#-------------------

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' } ) {
$vmview.name
}

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" 
$spec.tools = New-Object VMware.Vim.ToolsConfigInfo 
$spec.tools.toolsUpgradePolicy = "manual" 

vim.vm.ConfigSpec
changeVersion
vim.vm.ToolsConfigInfo
toolsUpgradePolicy

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 
$spec.tools = New-Object VMware.Vim.ToolsConfigInfo 
$spec.tools.toolsUpgradePolicy = "upgradeAtPowerCycle" 
Foreach($vmview in get-view -ViewType virtualmachine -SearchRoot (get-Cluster 'my_cluster').id -Filter @{'Config.Tools.ToolsUpgradePolicy' = 'manual' } ) {
$vmview.ReconfigVM_task($spec)
}

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 
$spec.tools = New-Object VMware.Vim.ToolsConfigInfo 
$spec.tools.toolsUpgradePolicy = "upgradeAtPowerCycle" 
Foreach($vmview in get-view -ViewType virtualmachine -SearchRoot (get-Cluster 'my_cluster').id -Filter @{'Config.Tools.ToolsUpgradePolicy' = 'manual' } ) {
$spec.changeVersion=$vmview.Config.changeversion
$vmview.ReconfigVM_task($spec)
}

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 
$spec.tools = New-Object VMware.Vim.ToolsConfigInfo 
$spec.tools.toolsUpgradePolicy = "upgradeAtPowerCycle" 
foreach ($vm in gc c:\vmlist.txt) {
$vmview = get-view -viewtype virtualmachine -Filter @{'name'=$vm} 
$vmview.ReconfigVM_task($spec)
}

Change the syslog server for esxi5 box using powercli

Let’s say that we would like to change the syslog server to which our esxi5 boxes is sending logs in some particular cluster.

$changedValue = New-Object VMware.Vim.OptionValue[] (1)
$changedValue[0] = New-Object VMware.Vim.OptionValue
 $changedValue[0].key = "Syslog.global.logHost"
 $changedValue[0].value = "tcp:/your-syslog-ip:514"

Get-View -ViewType HostSystem -Searchroot (Get-Cluster "your-cluster-name").Id | %{
  $optMgr = Get-View $_.ConfigManager.AdvancedOption
  $optMgr.UpdateOptions($changedValue)
}

Now check if we have updated values

get-view -viewtype HostSystem -SearchRoot (get-cluster "our-cluster").id | % { get-view $_.ConfigManager.AdvancedOption | select -ExpandProperty Setting |?{$_.Key -like "Syslog.global.logHost"} }

Many thanks to LucD for pointing me out a better way to go with updating this value!