Monitoring Tasks with PowerCLI

I’m posting this here more so I don’t forget it (Besides, every time I learn something new, it pushes some old stuff out of my brain. Remember when I took that home winemaking course, and I forgot how to drive?), but I think some of you will also find it useful if you don’t know about it already.

There are many times when we delve under the hood of the PowerCLI interface and go straight to the .NET Toolkit, and while things like Onyx will go a looooong way towards simplifying this, it won’t necessarily show you some of the tricks Carter and team have built into PowerCLI to help us with stuff, such as forcing a loop to wait for the task in each iteration to complete before moving to the next iteration.

It’s probably easier to do this with an example. So lets say for example, you have a situation where you want to reconnect all hosts in your inventory. To do so, you could use the following code (after first connecting to your target vCenter server):


# Get a Managed Object Reference to all ESX hosts managed by the VC
$esxMoRefs = Get-VMHost | % {Get-View $_.Id}
# Loop through each host
foreach($esxMoRef in $esxMoRefs)
{
# If the host is not already disconnected (ie status is gray)
# disconnect it first
if ($esxMoRef.OverallStatus.ToString() -notcontains "gray")
{
# disconnect host
$esxMoRef.DisconnectHost_Task()
}

Write-Host "Reconnecting host :" $esxMoRef.Name
# Build HostConnectSpec to force reconnect
# if host is already managed by another VC
$hostConnSpec = New-Object VMware.Vim.HostConnectSpec
$hostConnSpec.force = $True
# Now reconnect the host
$esxMoRef.ReconnectHost_Task($hostConnSpec)
}

Now that all looks well and good, however there are 2 problems.

The first problem is that if we fire DisconnectHost_Task(), the script will continue straight to the Reconnect stage before the DisconnectHost task has actually completed, and therefore when ReconnectHost_task() is invoked VC will ignore it because the host is still connected. But the DisconnectHost task will still be running, and when it actually does complete the host will not be reconnected by the script because the loop has moved onto the next iteration (in fact, with no waiting the script will probably have blown through your entire inventory before the first DisconnectHost task has completed).

The second problem is that after we fire ReconnectHost_task() the loop will go straight to the next iteration. If there were 50 disconnected hosts in your inventory, VC will effectively try to reconnect them all at once (ie each ReconnectHost_task() will be invoked very quickly after the previous one). This may or may not be a bad thing, but personally I would rather have this kind of operation run in a serial manner where each task completes before the next task is created.

Thankfully, Carter and the team have given us 2 cmdlets in PowerCLI to take care of business – Get-VIObjectByVIView and Wait-Task.

Get-VIObjectByVIView is used to convert an “under the hood” object reference to one that can be used with the standard PowerCLI cmdlets. Anytime you get an object reference using the Get-View cmdlet, you can pretty much use it only with .NET Toolkit operations – you can’t use them with the standard PowerCLI cmdlets because it operates at a higher level of abstraction and doesn’t understand these more native type objects (OK, there are some cmdlets that will let you use them, but I’m conveniently going to ignore those for the sake of clarity).

Wait-Task does what it says on the tin – there are plenty of standard PowerCLI cmdlets that invoke a task, sometimes they wait for the task to complete by default (as is the case with New-VM and Move-VM) and other times they don’t. Wait-Task is obviously for those ones that don’t wait, in situations where you want to wait rather than have a whole bunch of stuff run in parallel.

So, combining these 2 cmdlets, we can modify our original script to run in a serial manner as follows:

$esxMoRefs = Get-VMHost | % {Get-View $_.Id}
foreach($esxMoRef in $esxMoRefs)
{
if ($esxMoRef.OverallStatus.ToString() -notcontains "gray")
{
#
# Put disconnect task into a variable
#

$discoTask = $esxMoRef.DisconnectHost_Task()

#
# Monitor disconnect task
#

Get-VIObjectByVIView $discoTask | Wait-Task | out-null
}
Write-Host "Reconnecting host :" $esxMoRef.Name
$hostConnSpec = New-Object VMware.Vim.HostConnectSpec
$hostConnSpec.force = $True
#
# Similarly, put reconnect task into a variable
#

$reconTask = $esxMoRef.ReconnectHost_Task($hostConnSpec)

#
# Monitor reconnect task
#

Get-VIObjectByVIView $reconTask | Wait-Task | out-null
}

Pretty nice eh? I’ve used this in many different scripts over the years (I can’t believe it’s years since PowerCLI’s inception!), hopefully you’ll find it useful too.

Advertisements

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


%d bloggers like this: