Storage vmotion to different datastores for different vm hard disks

I’ve spent some time today figuring out how to do storage vmotion so that 1 disk could go to datastoreA, and 2nd disk could go to datastoreB, and forexample to choose if i want to move the configuration vm files to different datastore. After playing 20 minutes with onyx and reading api guide for 30 minutes i have finally made it 😉
RelocateSpec is most important thing in writing the relocatevm_task
relocateVM_task description

You can omit the $spec.datastore object when you do not want to move vm config files.
This is example if you would have 3 disks inside vm, and would like to send disk 1 to ds1, disk 2 do ds3, and disk3 to ds3.This example also moves configuration files of vm to datastore selected in $vmxds

$ds1=(Get-Datastore your_1_destination_datastore|get-view).moref.value
$ds2=(Get-Datastore your_2_destination_datastore|get-view).moref.value
$ds3=(Get-Datastore your_3_destination_datastore|get-view).moref.value
$vmxds= (Get-Datastore your_vmx_destination_datastore|get-view).moref.value
$myvmtomove=get-vm 'some_vm'
$disks=$myvmtomove|Get-harddisk|% {$'/')[1]}  #-> 3 disk ids should be here
$spec = New-Object VMware.Vim.VirtualMachineRelocateSpec

$spec.datastore = New-Object VMware.Vim.ManagedObjectReference
$spec.datastore.type = "Datastore"
$spec.datastore.Value = $vmxds

$spec.disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator[] (3)
$spec.disk[0] = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$spec.disk[0].diskId = $disks[0]
$spec.disk[0].datastore = New-Object VMware.Vim.ManagedObjectReference
$spec.disk[0].datastore.type = "Datastore"
$spec.disk[0].datastore.Value =  $ds1
$spec.disk[1] = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$spec.disk[1].diskId = $disks[1]
$spec.disk[1].datastore = New-Object VMware.Vim.ManagedObjectReference
$spec.disk[1].datastore.type = "Datastore"
$spec.disk[1].datastore.Value =  $ds2
$spec.disk[2] = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$spec.disk[2].diskId = $disks[2]
$spec.disk[2].datastore = New-Object VMware.Vim.ManagedObjectReference
$spec.disk[2].datastore.type = "Datastore"
$spec.disk[2].datastore.Value = $ds3

(Get-View -Id $$spec, "defaultPriority")

Moving VMX to location of Disk1 datastore in case there is only 1 hard disk in vm:

#Get our VMa
$VMname = 'VMa'
$vm = Get-View  -viewtype virtualmachine -Filter @{'name'=$VMname}
#you need to make sure you get only 1 vm, normally that's the case...

#VMa vmx path
$VMXpath = ($vm.LayoutEx.File |?{$_.Type -eq 'Config'}).Name
Write-Host "VMx lays here: $VMXpath"

#don't do anything if you have more than 1 disk
if (@($vm.LayoutEx.Disk.Key).length -eq 1){

#don't do anything if you will spot snapshots
if (@($vm.LayoutEx.File |?{$_.Type -eq 'diskDescriptor'}).length -eq 1) {

#Disk1 path
$Disk1path = ($vm.LayoutEx.File |?{$_.Type -eq 'diskDescriptor'}).Name
Write-Host "Disk 1 lays here: $Disk1path"

$Disk1ID = $vm.LayoutEx.Disk.Key
$Disk1Device = $vm.Config.Hardware.device | ?{$_.Key -eq $Disk1ID}
$Disk1DeviceDatastoreMoref = $Disk1Device.Backing.Datastore
#Writing spec
#Move VMX to Disk1 datastore spec

$spec = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.datastore = New-Object VMware.Vim.ManagedObjectReference
$spec.datastore.type = "Datastore"
$spec.datastore.Value = $Disk1DeviceDatastoreMoref.Value

#Disk1 stays where it is, if you dont add this , you will move the Disk to the vmx DS
$spec.disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator[] (1)
$spec.disk[0] = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$spec.disk[0].diskId = $Disk1ID
$spec.disk[0].datastore = New-Object VMware.Vim.ManagedObjectReference
$spec.disk[0].datastore.type = "Datastore"
$spec.disk[0].datastore.Value = $Disk1DeviceDatastoreMoref.Value

$vm.RelocateVM_Task($spec, "defaultPriority")

$vm = Get-View  -viewtype virtualmachine -Filter @{'name'=$VMname}
$VMXpath = ($vm.LayoutEx.File |?{$_.Type -eq 'Config'}).Name
Write-Host "VMx lays here: $VMXpath"
$Disk1path = ($vm.LayoutEx.File |?{$_.Type -eq 'diskDescriptor'}).Name
Write-Host "Disk 1 lays here: $Disk1path"


}else {Write-Error "Amount of disks is not equal to 1"}

And i wrote recently this example , function to move VMX to destination DS of a particular disk name.

Function Move-VMX{

#Get our VM
#disk is 'Hard disk 1' , or 'Hard disk 2', same as you see in vsphere client

$vm = Get-View -viewtype virtualmachine -Filter @{‘name’=$VMname}

if(($vm.Config.Hardware.Device |?{$_ -is [vmware.vim.virtualdisk]}) | ?{$_.DeviceInfo.Label -eq $disk})

$disks = $vm.Config.Hardware.Device |?{$_ -is [vmware.vim.virtualdisk]}
$VMXDestinationDisk = ($vm.Config.Hardware.Device |?{$_ -is [vmware.vim.virtualdisk]}) | ?{$_.DeviceInfo.Label -eq $disk}

$VMXDestinationDatastoreMorefValue = $VMXDestinationDisk.Backing.Datastore.Value

$numberOfDisks = @($disks).Length

#VM vmx path
$VMXpath = ($vm.LayoutEx.File |?{$_.Type -eq ‘Config’}).Name
Write-Host “VMx lays here: "$VMXpath

#DEstination disk path
Write-Host “Disk $disk lays here: "$VMXDestinationDisk.Backing.FileName

foreach ($dsk in $disks){
Write-Host "Disk "$dsk.DeviceInfo.Label" Lays in: " $dsk.Backing.FileName

#Writing spec
#Move VMX to Disk destination

$spec = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.datastore = New-Object VMware.Vim.ManagedObjectReference
$spec.datastore.type = “Datastore”
$spec.datastore.Value = $VMXDestinationDatastoreMorefValue

#Specs to make our disks stay where they are
$spec.disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator[] ($numberOfDisks)
Foreach($dsk in $disks) {
$spec.disk[$i] = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$spec.disk[$i].diskId = $dsk.Key
$spec.disk[$i].datastore = New-Object VMware.Vim.ManagedObjectReference
$spec.disk[$i].datastore.type = “Datastore”
$spec.disk[$i].datastore.Value = $dsk.Backing.Datastore.Value

Write-Host 'Started task for moving now VMX '$VMXpath' to '$disk' location'
$task = $vm.RelocateVM_Task($spec, “defaultPriority”)

} else {Write-Error 'Could not find the disk, example: ''Hard disk 1 '' '}

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
…… ….. ……………..

Find out if host has a portgroup with vlan X

Situation : Your portgroup names doesn’t make any sense, and it’s not easy to tell tell vlan id from the name. If you want quickly to discover if you have some portgroup on vswitch that handles vlan X this could be handy:

Get-VMHost your_host| Get-VirtualPortGroup | ? {$_.Vlanid -eq 777} | select name,vlanid

This will check if we have any portgroup defined for ‘your_host’ vswitch.