PowerCLI's RunAsync Parameter Rocks!

I've recently been playing around with the -RunAsync parameter in some of my PowerCLI scripts, and I'm super impressed!  I'm also super late to the party; I mean, LucD was writing about it back in 2010, but still!  So, what's it do?  It speeds up tasks that don't need to be run sequentially, that's what it does.

For example, if I have a list of VMs that all need to move into a new folder, I could do it like this:

$folder = get-folder "New Folder"
$vmNames = get-content MyList.txt
foreach ($vmname in $vmNames){
    get-vm $vmname | move-vm -destination $folder
}

And that would move one VM, then the next, then the next, etc.  Depending on the number of VMs, it could take a real long time.  This process could take a while because, the way this script is written, the system will wait for each "move" to complete before initiating the next.  That's where -RunAsync comes in.

$folder = get-folder "New Folder"
$vmNames = get-content MyList.txt
foreach ($vmname in $vmNames){
    get-vm $vmname | move-vm -destination $folder -runAsync
}

This version will run faster, as the system is no longer waiting for each move to complete before proceeding to the next one.  As soon as the task is submitted to vCenter, the script will move on to processing the next one.  That begs the question though, how do we know when all of those tasks are done?

Well, that's what get-task is for.  That cmdlet will show you all of the running tasks in the environment, as well as their status.  And that works great if you're using PowerCLI interactively, but how do you use it in a script?  Well, the wait-task cmdlet is made for exactly that scenario; take a look at this example:

$folder = get-folder "New Folder"
$vmNames = get-content MyList.txt
$tasks = @
foreach ($vmname in $vmNames){
    $tasks += get-vm $vmname | move-vm -destination $folder -runAsync
}
$tasks | wait-task

That example will store each of the move-vm tasks and then, once they've all been initiated, will wait until they've all completed before proceeding!

While that's a useful syntax for using -runAsync and wait-task (particularly for more complex operations inside of loops), it's a bit overkill in this simple example.  I think that, in newer versions of PowerCLI, cmdlets that support -runAsync and accept an array of objects as their input will actually default to that behavior (so, no need to even specify -runAsync, it just happens), but in older versions you definitely need to specify the switch in order to get that behavior.  That means that those half-dozen lines above can actually be efficiently consolidated down to this pair:

$folder = get-folder "New Folder"
get-vm (get-content MyList.txt) | move-vm -destination $folder -runAsync | wait-task

And there you have it!  -runAsync and wait-task are a really easy way to add some parallelism to a PowerCLI script without the overhead associated with opening new PowerShell instances for jobs or workflows!

Comments

Popular posts from this blog

Deleting Orphaned (AKA Zombie) VMDK Files

Clone a Standard vSwitch from one ESXi Host to Another

vCenter Server Appliance Crash due to Full /Storage/SEAT Partition