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]
13 comments
can this script be modified to just vmotion the vmx file. I have some VMs that were built incorrectly and the VMX and DISK1 are on different datastores. I wanted to storage vmotion just he VMX file to hard disk 1 so they are together again.
Hi Silvio
if i understood you correctly:
VMa
1) VMx is in DS06 datastore
2) Disk1 is in DS01 datastore
Task:
Move VMx to location od Disk1 datastore
#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){
#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”}
Thank you, and this looks great and I will give it a try. But unfortunately, most of the VMs we have are all multiple disks. So I could have VMX, Hard Disk1, Hard Disk2, Hard Disk3, Hard Disk 4, etc. All I need to do is move VMX to wherever Hard Disk 1 is located. As Hard Disk 1 is always the OS drive for our VMs when built.
Ok, i understand now. Either join us on #powercli -> http://webchat.freenode.net/?randomnick=1&channels=powercli&prompt=1 and i can explain this to you. Or i can write later , in a proper function that is flexible , and will work regardless of disk configuration.
unfortunately my work location will not allow access to that webchat. I will wait later for a posting here. No worries and thank you.
i put the script int the blog post, i have added there 1 line, to check if there aren’t any snapshots.
Any updates for my question from yesterday ? All I need to do is move VMX to wherever Hard Disk 1 is located. As Hard Disk 1 is always the OS drive for our VMs when built. I also have the name of the LUN exported for Hard Disk 1 already. So just need to storage vmotion the vmx to the LUN I have defined.
busy at work, etc.. will try to update you tomorrow.
Have a look in the blog post, it’s on the bottom.
Move-VMX -VMname Your_VM -Disk ‘Hard disk 1’
this will move your VM vmx file, to the datastore of your hard disk 1. The ‘hard disk 1’ , is that label which you see in vsphere client for the disk. It has nothing to do with the order but, with the name.
I hope that helps
Great scripts! Thank you so much for putting all this together. I’ve been tearing my hair out trying to figure out how to migrate my multiple disk VMs and this works great.
One minor typo in the first line of the first script, btw: ‘$ds1s’ should be ‘$ds1’.
Cheers Jay!
Have you tried using this approach to Hot vMotion a VM using multiple datastores to another host with different, but still multiple datastores? This example appears to be only for SvMotion.
Hi David, i have not tried it, i mean i can reproduce this example later on when i will have some time, but i don’t see why it would not work. https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.RelocateSpec.html -> just add the $spec.host to it, and inside pass the destination host moref.