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
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|% {$_.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")

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

#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"}

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

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 '' '}
}
Advertisements

11 thoughts on “Storage vmotion to different datastores for different vm hard disks

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

      • unfortunately my work location will not allow access to that webchat. I will wait later for a posting here. No worries and thank you.

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

    • 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

  3. 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’.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s