Hi all,
We are in this big migration of moving 1000+ vms over 100+ datastores in total 1500 TB
And i'm automating it with PowerCLI.
So, we have a lot of vms and with multiple disks and not all of them needed to be moved.
I split the migration up in two, move the config files and move the disk.
This because it can happen that the config file and the disks are not on the same datastore for some reason.
I found this really cool script from LucD
$spec = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.datastore = (Get-Datastore -Name $Des_datastore).Extensiondata.MoRef
$comp_disks | %{
$disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$disk.diskId = $_.Extensiondata.Key
$disk.datastore = $_.Extensiondata.Backing.Datastore
$spec.disk += $disk
}
$ vm.Extensiondata.RelocateVM_Task($spec, "defaultPriority")
But apparently i'm doing something wrong because it's moving the vm entirely instead of only the config file.
Can anyone help me ?
Hi Luc,
Thanks for the script, but also not what i'm looking for.
But it gave me inspiration, and now I have fixed it!
The vmx file and disks are moved separately, so for the vms how has a vmx file on a different datastore then the disks, it will leave it that way.
When I start the script I use the start-transscript cmdlet for the logging, that's why there is so random a 'date' in the script.
This works perfect!
# Variables
$source_datastore = Get-Datastore -Name lsi07
$destination_datastore = Get-Datastore -Name lsi06
$source_datastore_name = "lsi07"
$vms = Get-Datastore -Name $source_datastore | get-vm | where {$_.name -like "test*"}
# Loop for the script
date
Foreach ($vm in $vms){
# Locate the vmx file, if on source datastore move to another datastore
if ($vm.ExtensionData.Config.Files.VmPathName -like "*$source_datastore_name*"){
Write-Host "vm $vm has config file on $source_datastore, move config file"
$spec = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.datastore = $destination_datastore.Extensiondata.MoRef
Get-HardDisk -VM $vm | %{
if($_.Name -ne 'Hard disk *'){
$disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$disk.diskId = $_.Extensiondata.Key
$disk.datastore = $_.Extensiondata.Backing.Datastore
$spec.disk += $disk
}
}
$vm.Extensiondata.RelocateVM_Task($spec, "defaultPriority") | out-null
Write-host "Config file moved"
}
else {write-host "vm $vm has no config file on $source_datastore"}
# move the disk(s) off the source datastore to the destination datastore
$count = (get-vm -Name $vm |Get-HardDisk | Where {$_.filename -like "*$source_datastore_name*" }).count
if ($count -gt 0){
$comp_disks = get-vm -Name $vm |Get-HardDisk | Where {$_.filename -like "*$source_datastore_name*" }
Write-Host "Move $count disks off $source_datastore for vm $vm"
Move-hardDisk -HardDisk $comp_disks -Datastore $destination_datastore -Confirm:$false |Out-Null
Write-Host "Disks are moved to $destination_datastore"
}
else {write-host "There are no disks on $source_datastore "
}
sleep 5
$view_vm= get-view –viewtype VirtualMachine –filter @{“Name”="$vm”}
$view_vm.Config.Files.VmPathName
$view_vm.Layout.Disk.Diskfile
Write-Host "VM $vm done"
sleep 10
}
You're missing the creation of the content of the $comp_disks variable.
The following will move all VM files, except the harddisks, to a target datastore.
$vmName = 'MyVM'
$destDatastore = 'MyDS'
$vm = Get-VM -Name $vmName
$hd = Get-HardDisk -VM $vm
$destDS = Get-Datastore -Name $destDatastore
$spec = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.datastore = $destDS.Extensiondata.MoRef
$hd | %{
$disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$disk.diskId = $_.Extensiondata.Key
$disk.datastore = $_.Extensiondata.Backing.Datastore
$spec.disk += $disk
}
$vm.Extensiondata.RelocateVM_Task($spec, "defaultPriority")
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi Luc,
Thanks for your quick reaction!
This is the complete script I used :
# Variables
$source_datastore = Get-Datastore -Name lsi06
$destination_datastore =Get-Datastore -Name lsi02
$vms = Get-Datastore -Name $source_datastore | get-vm | where {$_.name -like "test*"}
$date = date
# functions
Function Get-VMConfigFile {
[CmdletBinding()]
param (
[Parameter(
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[String[]]$VMName
)
Get-VM $VMName | select Name,@{E={$_.ExtensionData.Config.Files.VmPathName};L="VMPath"}
}
# Loop for the script
Foreach ($vm in $vms){
# main
# Count disks and decide of the vm will be moved in total or only disks or config file
$comp_disks = get-vm -Name $vm |Get-HardDisk | Where {$_.filename -like "*lsi06*" }
$count = (get-vm -Name $vm |Get-HardDisk | Where {$_.filename -like "*lsi06*" }).count
date
# Loctae the vmx file, if on compellent move to another datastore
$vm_conf = Get-VMConfigFile $vm
if ($vm_conf.VMPath -like "*lsi06*"){
Write-host "vm $vm has config file on $source_datastore, move config file"
$spec = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.datastore = (Get-Datastore -Name $destination_datastore).Extensiondata.MoRef
$comp_disks | foreach {
$disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$disk.diskId = $_.Extensiondata.Key
$disk.datastore = $_.Extensiondata.Backing.Datastore
$spec.disk += $disk
}
$vm.Extensiondata.RelocateVM_Task($spec, "defaultPriority") #| out-null
Write-host "Config file moved"
}
else {write-host "vm $vm has no config file on $source_datastore"}
# move the disk(s) off the compellent to the destination datastore
Write-Host "Move $count disks off compellent for vm $vm"
Move-hardDisk -HardDisk $comp_disks -Datastore $destination_datastore -Confirm:$false
Write-Host "VM $vm done"
It depends what exactly you want to move:
The script you have seems to
Is that what you want to do?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi Luc,
I only want to move : all the VM's files except for all the harddisks
and later on move the harddisk with the move-harddisk cmdlet
My 1st answer moves the VM without moving the harddisks.
Not sure what you are missing?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
well, when I run the full script I have posted, the vm is moved completely.
We have vms like :
Config (vmx) files : datastore a
disk 1 : datastore a
disk 2 : datastore b
disk 3 : datastore c
I only want to move the config file (vmx and other files) and disk 1 of datastore a
The other disks of the vm need to left on the other datastores
I have run the script in parts and every part is doing it right except the part that moved only the config file (vmx )
I guess I'm doing something wrong there
Try with this, it will move all the VM's config files and Hard disk 1 to the destination datastore.
All other harddisks should stay where they are.
# Variables
$source_datastore = Get-Datastore -Name lsi06
$destination_datastore = Get-Datastore -Name lsi02
$vms = Get-VM -Datastore | where {$_.name -like "test*"}
$date = Get-Date
# Loop for the script
Foreach ($vm in $vms){
# Locate the vmx file, if on compellent move to another datastore
if ($vm.ExtensionData.Config.Files.VmPathName -like "*lsi06*"){
Write-Host "vm $vm has config file on $source_datastore, move config file"
$spec = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.datastore = $destination_datastore.Extensiondata.MoRef
Get-HardDisk -VM $vm | %{
if($_.Name -ne 'Hard disk 1'){
$disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$disk.diskId = $_.Extensiondata.Key
$disk.datastore = $_.Extensiondata.Backing.Datastore
$spec.disk += $disk
}
}
$vm.Extensiondata.RelocateVM_Task($spec, "defaultPriority") #| out-null
Write-host "Config file moved"
}
else {write-host "vm $vm has no config file on $source_datastore"}
Write-Host "VM $vm done"
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi Luc,
Thanks for the script, but also not what i'm looking for.
But it gave me inspiration, and now I have fixed it!
The vmx file and disks are moved separately, so for the vms how has a vmx file on a different datastore then the disks, it will leave it that way.
When I start the script I use the start-transscript cmdlet for the logging, that's why there is so random a 'date' in the script.
This works perfect!
# Variables
$source_datastore = Get-Datastore -Name lsi07
$destination_datastore = Get-Datastore -Name lsi06
$source_datastore_name = "lsi07"
$vms = Get-Datastore -Name $source_datastore | get-vm | where {$_.name -like "test*"}
# Loop for the script
date
Foreach ($vm in $vms){
# Locate the vmx file, if on source datastore move to another datastore
if ($vm.ExtensionData.Config.Files.VmPathName -like "*$source_datastore_name*"){
Write-Host "vm $vm has config file on $source_datastore, move config file"
$spec = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.datastore = $destination_datastore.Extensiondata.MoRef
Get-HardDisk -VM $vm | %{
if($_.Name -ne 'Hard disk *'){
$disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$disk.diskId = $_.Extensiondata.Key
$disk.datastore = $_.Extensiondata.Backing.Datastore
$spec.disk += $disk
}
}
$vm.Extensiondata.RelocateVM_Task($spec, "defaultPriority") | out-null
Write-host "Config file moved"
}
else {write-host "vm $vm has no config file on $source_datastore"}
# move the disk(s) off the source datastore to the destination datastore
$count = (get-vm -Name $vm |Get-HardDisk | Where {$_.filename -like "*$source_datastore_name*" }).count
if ($count -gt 0){
$comp_disks = get-vm -Name $vm |Get-HardDisk | Where {$_.filename -like "*$source_datastore_name*" }
Write-Host "Move $count disks off $source_datastore for vm $vm"
Move-hardDisk -HardDisk $comp_disks -Datastore $destination_datastore -Confirm:$false |Out-Null
Write-Host "Disks are moved to $destination_datastore"
}
else {write-host "There are no disks on $source_datastore "
}
sleep 5
$view_vm= get-view –viewtype VirtualMachine –filter @{“Name”="$vm”}
$view_vm.Config.Files.VmPathName
$view_vm.Layout.Disk.Diskfile
Write-Host "VM $vm done"
sleep 10
}