Powershell: Working with the VI API (Teach a man to Fish)

I have a bunch of one off scripts and modules I’ve written for a VI Migration I performed last week. The task was to migrate a moderate VI farm (15 hosts 100+ vm) from AMD based server to Intel in a ridiculous 20min window. I played with the idea of setting masks in the vmx, but ultimately that itself would require a reboot. In the end I wrote a series of small scripts that handled the whole thing for me. That has become my MO as of late… get a task write a couple quick functions then a small script that uses those functions. I have to get approval from my client to post the scripts (even though there’s nothing in them they were written on their network) so in the mean time I thought I would share how I navigate the VI API, and create new functionality.

We’ll start with something simple; my home lab has a pesky problem. My ESXi hosts always disconnect from vCenter… More of an annoyance really, but still I wanted a quick way to fix it. Where to start, we’ll probably need to get below the VITK, and work with the VI objects directly. To do that we need to start by getting an instance of our target object in this case a VMhost.

Tip 1; Keep it simple, don’t write the total solution take small bites at a problem. As you can see I have two hosts in my farm to avoid complicating things we need only a single instance! Also as you work your way through a problem avoid using variable names like $a. While it may seem faster remember you’ll be copying most of this later into your “script”. Start off right name your variables after the objects they contain. Additionally you really need to run two commands against anything you get from the VI API. You’ll waste a ton of time otherwise, always run the GetType() method, and the Get-Member cmdlet against any objects you get. Be mindful of the methods available and if an instance or a collection was returned!

Here we can see that GetType() has confirmed that we have a single instance of a VMHostImpl object. Unfortunately VMHostImpl is a pointer to the real object.  To get the real Managed Object from the impl use the Get-View cmdlet. Unfortunately, VMHostImpl is an Automation Object, Automation Objects are small light weight objects used to pass key data between cmdlets.  Fortunately, VMHostImpl is an Unsynthesized Automation Object, meaning it corresponds to a full Managed Object!  So how can we transform VMHostImpl to a full .Net object? Enter the Get-View cmdlet, The Get-View cmdlet will take an Unsynthesized object and return the full Managed Object.  This is important because all 300+ methods that enable direct manipulation of vCenter only exist within managed objects.  When you need to extend the VI Toolkit (write your own functions) you’ll need a Managed Object.

A fantastic explanation of VMware’s object model is provided in the VI Toolkit Lab Manual: VMworld Euroup 2009: section9

Enough of that let’s get that Managed Object, as always check the type.  You should get an object back that is derived from VMware.Vim.ManagedEntity (aka a Managed Object).

Ahh, that is much better just look at all the great stuff… A quick scan reveals that there is a native method that handles reconnecting a disconnected VMHost for us.

TIP 2; When dealing with a new method call the method without any parentheses to retrieve any overloads.  An overload is a definition of the methods signature… It’ll tell you what you need where for it to all work!

So whether we perform a reconnect operation asynchronously via the ReconnectHost_Task method or synchronously via the ReconnectHost method… either way we’ll need an instance of a HostConnectSpec. Where does one find such a thing, if there were only a web site that spelled all this out? You will have a love hate relationship with the VI API Developers reference. It doesn’t always translate too well into the .Net representation of the API, but it’s all in there. My Perl counterparts typically will start there and then code, but with PowerShells discoverability I prefer to stay in the console as much as possible. Most of the object in the VI API are derived from DynamicData and are instantiated from VMware.Vim (in a pinch just try that first).

As always, keep your variables simple but descriptive. The developers at VMware probably banged their heads for months naming all this stuff. Where possible Just name your obejcts after the types they represent/contain! This will pay dividends when you start to paste several of these into a larger script. Again check the object for any methods, run it through gettype(), and Get-Member!

So we have our object but what properties need to be set, and with what? At this point if you haven’t already head on over to the VI API Ref. Since we already know our Data Object Type just click the Data Object types on the right side and search for HostConnectSpec. Hit the link and you’ll be brought to the documentation for the HostConnectSpec Data type.

Here you’ll find everything you need to know about this little guy. Every method that uses it, where it extends from and what extends from it. I really do have to take my hat off to VMware here, as an Admin I loathe having to referance developer documentation, but they’ve done a great job. If you read through you’ll discover that the HostConnectSpec is used primarily to Add a host to vCenter. Well since our host is already in vCenter we can skip all that stuff, and go straight to what we do need.

To connect our host all we need is a HostName, and Port number.

TIP 3; At all costs avoid hard coding anything. We could easily just require the user to enter this information. Or we could just set defaults and provide an override for say the port, but in reality either of those would be poor code! Fact, It’s in VIC so all this data is in the SDK somewhere… FIND IT!

For some odd reason I prefer stumbling through an object looking for the desired data. While this isn’t the most efficient method it will enlighten you exactly how much data is in there! For time sake though just go back to the VI API REF, and click the All Properties link at the top of the page. Scroll all the way down until you find PORT. You’ll notice that next to each property it shows what object contains that property. It just so happens the one we need is right there on the top. Port(HostConfigSummary) -> Click it.

Now we need to find this object, and it’s reference to us in the API. We need to make a map of how to get to it programmatically. To do this just walk back along the “Property of” links on the top of the page until you find something familiar. Sometimes it’s necessary to walk all the way to the root managed object reference, and it can be a pain, but it works! HostConfigSummary is a Property of HostListSummmary and host list summary is a Property of HostSystem! Now just walk it back using the HostSystem Object we got earlier.

As you can see the property names don’t match what we found in the SDK Documentation, but the Object Types do so just shift your eye to the left and look for the type you need!

Putting it all together; we should now have everything we need to programmatically correct my disconnected host, but still always prove it in the console before you go, and start writing a script/function.

Task: Fix my host

  1. Get an instance of our VMHost
  2. Get the Managed Object from that instance
  3. Create a new HostConnectSpec using the values already present in vCenter
  4. Call the ReConnectHost method with our new HostConnectSpec

So there you have it now that you have the logic to accomplish a given task writing a Function or Script is really just adding documentation! I would also recommend creating this stuff in pares i.e. if we create a script to reconnect a given host we should also write one to disconnect a host. As I did with my example here:

In action with PoshCode:

So that’s a rough overview how I use the VI Toolkit to automate vCenter.  As always feel free to call me out if you spot a mistake!

Enjoy,
~Glenn

Update: Well it took Carter –lt 10min to call me out on this one… Yes I Could have used Set-VMHost –state, but I was cherry picking the SDK 😀

2 thoughts on “Powershell: Working with the VI API (Teach a man to Fish)”

  1. Great article Glenn.
    Clear, understandable and well written.

    Two minor remarks:
    1) The names of your variables ($VMHost and $VMHostImpl) could be a bit confusing.
    The VITK itself produces objects whose name ends mostly with “Impl”.

    For example, the Get-VMHost cmdlet produces a VMHostImpl object.
    The VI API uses an object called HostSystem.

    Your variable names seem to use the reverse convention. This could perhaps confuse some readers.

    2) Most VI API methods have 2 formats.
    In your script that would be ReconnectHost and ReconnectHost_Task. It is perhaps useful to explain the difference between the two methods.
    The method with _Task at the end returns a MoRef to a Task.
    That allows your script to check the status and result of the method.
    In most of the examples I post in the VITK Community, for example, I tend to include a loop to wait for the completion of the method like this:

    $taskMoRef = $VMHostImpl.ReconnectHost_Task($HostConnectSpec)

    $task = Get-View $taskMoRef
    while($task.info.state -eq “running” -or $task.info.state -eq “queued”){$task = Get-View $taskMoRef}

    You can also use the Task object for:
    – examining the return code and eventual error code
    – calculating the time the method took
    – displaying a progress bar
    – ….

    Again, well done with this article.

  2. Yeah, your spot on with $VMHost and $VMHostImpl… I’m afraid that’s a holdover from before I learned tip 1 myself. You are correct they should be reversed, but that’s what happens when you read your own code.

    (Tip 4; Peer review have someone else read your code before you post it to the internet)

    I didn’t even think about going into why the two different methods and there use case.

    As always, thanks for keeping me straight!
    ~Glenn

Leave a Reply