VMware Cloud Community
Mozana
Contributor
Contributor

How to kick off Multiple SVMotions Instances at a time via PowerCLI

Hello All,

I am in the middle of migrating our current VMware Environment to a new Array and I need some help with a script I am running.    Please pardon my scripting skills below as I am no expert with powershell.  Usually i can frankenstein something together and make it work.   Essentially what I am trying to do is run multiple Storage Vmotion jobs at a time via powershell.    If I have 4 VMs within the CSV File being imported it will perform these steps 1 VM at time.   In order for me to get multiple jobs to run at once I have to create multiple powershell scripts pointing to multiple CSV files.   I would like the ability to kick off 1 script and have mutiple SVMotion jobs run at once.   Can some provide some info on how i can accomplish this or a better way to perform these SVMotions.

Thanks

Below are the contents of the powershell script i am running

$VIServer = Connect-VIServer vcenter01.domain.local

$vms = Import-CSV G:\temp\scripts\SVMotion1.csv
       
#VMOTION VM TO DELL SWING HOST
foreach ($vm in $vms){
Get-VM $vm.Name | Move-VM -Destination $vm.Destination
}

#SVMOTION TO SWING LUN
foreach ($vm in $vms){
Get-VM $vm.Name | Move-VM -Datastore $vm.TargetDS
}

#VMOTION TO UCS SWING HOST
foreach ($vm in $vms){
Get-VM $vm.Name | Move-VM -Destination $vm.DestinationFinal
}

#SVMOTION TO NEW DG LUN
foreach ($vm in $vms){
Get-VM $vm.Name | Move-VM -Datastore $vm.TargetDSFinal
}

0 Kudos
7 Replies
LucD
Leadership
Leadership

You can launch multiple svMotions in the background by using the -RunAsync parameter on the Move-VM cmdlet.

Note that your ESX(i) itself has a limitation on the number of parallel svMotions you can run.

But that is not really a problem for the script, the svMotions over the limit will just wait.

Since you seem to do four sets of motions in the script, you will have to take care that a phase doesn't start before the previous one is finished.

For that you can use something like the script in my About Async tasks, the Get-Task cmdlet and a hash table post.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Mozana
Contributor
Contributor

Lucd.........Thanks for the fast response.    I took your advice and attempted to create edit my powershell script to utliize hash tables.   The problem is I cant seem to get it working.    I created a new powershell script use for testing the hash table method before using in production.  This script simply vmotions a few Test VMs specified within the CSV file around to different hosts.   When I run this script I recieve the following error message.  Any help is appreciated.

Thanks

Index operation failed; the array index evaluated to null.
At C:\Users\morae420\AppData\Local\Temp\2c182f5e-8fb6-404a-9da8-6c6ce5d6596f.ps
1:6 char:11
+     $taskTab[ <<<< (Get-VM $vm.name | Move-VM -Destination $vm.DestinationFin
al -RunAsync).Id] = $vm
    + CategoryInfo          : InvalidOperation: (System.Collections.Hashtable:
   Hashtable) [], RuntimeException
    + FullyQualifiedErrorId : NullArrayIndex

____________________________________________________________

SCRIPT

$VIServer = Connect-VIServer vcenter01.domain.local

$vms = Import-CSV G:\temp\scripts\old\test1.csv

$taskTab = @{}

foreach($vm in $vms){

    $taskTab[(Get-VM $vm.name | Move-VM -Destination $vm.DestinationFinal -RunAsync).Id] = $vm

}

# Start each VM that is completed

$runningTasks = $taskTab.Count

while($runningTasks -gt 0){

    Get-Task | % {

        if($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success"){

            Get-VM $taskTab[$_.Id] | Move-VM -Destination $vm.DestinationFinal2

            $taskTab.Remove($_.Id)

            $runningTasks--

        }

        {

        if($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success"){

            Get-VM $taskTab[$_.Id] | Move-VM -Destination $vm.DestinationFinal3

            $taskTab.Remove($_.Id)

            $runningTasks--

        }

        elseif($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error"){

            $taskTab.Remove($_.Id)

            $runningTasks--

        }

    }

    Start-Sleep -Seconds 15

}

}

0 Kudos
CKloseFUM
Enthusiast
Enthusiast

Hi,

how can i pimp up this script to use different datastores?

From my source csv my Virtual Machines reside in different datastores and i want them also to be placed again in different datastores.

Source/destination


[vm],[disk1],[disk2],[disk3]

vm-name,datastore1,datastore2,datastore3

regards

Christian

0 Kudos
LucD
Leadership
Leadership

My script in Using multiple datastores, can't migrate the vmx file to a datastore could give an idea how to do this.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
CAGUNlabs
Contributor
Contributor

Mozana - I have the same issue using Move-VM with the $tasktab hash table.  I used LucD's New-VM example in the Async/Hashtab thread, and that works, so the syntax looks good.  I'm wondering if it is a problem is within the Move-VM commandlet, and that it may not be returning a value to the name assignment.  Perhaps it is the Move-VM pop-up.

Have you figured a way around it?

Thanks!

curtis.gunderson@cagun.com
0 Kudos
CAGUNlabs
Contributor
Contributor

Forgot about this post - i was able to solve the issue I was having with Move-VM by saving the Move-VM parameter to a varible - the result was Null - and illegal to the hash table.  It is no longer a one-liner, but otherwise identical process.  This error started for me when I when my vCenter was upgraded to VC5 - although, I do not see any reason why it should have.

curtis.gunderson@cagun.com
0 Kudos
DaveVtech
Contributor
Contributor

This is the best way I have found to do this so far with the fastest return time.  It will load balance the moves across the hosts in the destination cluster and send them to the largest available datastore.

I have tried numerous iterations of this script using invoke-command, -runasync, start-job, etc... This really is the only practical and efficient way to start multiple jobs at one time and not get stuck by the Move-Vm limitation (2 svmotions).  Because the start-job or invoke-command -asjob, runs each job in its own global scope.

If anyone can make any improvements to this, I am all ears.  Been working on this for days.

$startDTM = (Get-Date)
$vcenter = Read-Host "Which Vcenter are we using?:"
$servers = gc "c:\Servers2.txt"
####################Return Names of Possible Destination Clusters
get-cluster | ?{$_.name -like "*UCS*"}
$DestCluster = Read-Host "Which Cluster Are We Moving To:"
###################Get ESX Hosts in Destination Cluster / Set Incrementing Variable
$x = 0
$DestHosts = @(Get-Cluster -Name "$DestCluster" | Get-VMHost | select name)
#####################Get Datastore W/ Largest Amount Of Free Space
$datastores = Get-Datastore -VMHost $DestHosts[0].Name | select Name,FreeSpaceMB
$LargestFreeSpace = "0"
$LargestDatastore = $null
foreach ($datastore in $datastores) {
   if ($Datastore.FreeSpaceMB -gt $LargestFreeSpace) {
           $LargestFreeSpace = $Datastore.FreeSpaceMB
           $LargestDatastore = $Datastore.name
           }
       }
write-host "$LargestDatastore is the largest store with $LargestFreeSpace MB Free"
####################Execute Moves
ForEach($server in $servers){
Start-Job -Name "Move-VM-$server" -InitializationScript {Add-PSSnapin vmware.VimAutomation.Core} -ArgumentList ($server),($DestHosts[$x].Name),($LargestDatastore),($Vcenter) -ScriptBlock {
Connect-VIServer $arg[3]
Move-VM -VM $args[0] -Destination $args[1] -Datastore $args[2] -RunAsync
Disconnect-VIServer -Force -Confirm:$false
}
If($x -le $DestHosts.Count){$x++}
If($x -gt $DestHosts.Count){$x=0}
}
#Get End Time
$endDTM = (Get-Date)
#Echo Time elapsed
"Elapsed Time: $(($endDTM-$startDTM).totalseconds) seconds"
0 Kudos