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
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
[sourcecode language=”powershell”]
$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|% {$_.id.split(‘/’)[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 $myvmtomove.id).RelocateVM_Task($spec, "defaultPriority")
[/sourcecode]
Moving VMX to location of Disk1 datastore in case there is only 1 hard disk in vm:
[sourcecode language=”powershell”]
#Script:
#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")
#check
$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"}
[/sourcecode]
And i wrote recently this example , function to move VMX to destination DS of a particular disk name.
[sourcecode language=”powershell”]
Function Move-VMX{
param([Parameter(Mandatory=$True,Position=1)][string]$VMname,[Parameter(Mandatory=$True,Position=2)][string]$disk)
#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)
$i=0
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
$i++
}
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 ” ‘}
}
[/sourcecode]
