How to Establish a Session and Authenticate with the vSphere 6.5 RESTful API

I recently delivered a webinar that covered the basics of RESTful APIs which is available on demand here. It’s mostly focused on introducing folks to APIs – why they are important, what they do, and how to get started using them. It’s fairly demo heavy and marketing light, so I think you’ll enjoy it.

A few folks reached out asking for more details on the PowerShell code I wrote to work with VMware vSphere 6.5’s RESTful API to create a session, pull down a token, and authenticate subsequent calls. In this post, I’ll walk through that and share a few sample snipets. This is likely elsewhere on the web, but I find that learning the quirks of an API’s authentication process is typically the hardest to find because those closest to the API already know the process. The curse of knowledge. ­čÖé

Now, before we all get too focused on the fact that I used PowerShell, it’s just the language I know best. PowerCLI has some superb functionality for creating a session and William Lam has written tons of content on that here. This post is really more about using the API outside of any other specific framework – such as writing calls in Go, Python, or pulling data for something like Grafana – than it is about PowerShell specifically.

With that out of the way, let’s get started!

Creating a Session

The first step is to set up a basic auth key-value pair. This is fairly universal across everyone’s RESTful API. For this sample, I’m letting you manually enter the value of $Credential through a modal input, and then deconstructing the username and password into the required format for basic auth. For more on this topic, check out my post entitled┬áTackling Basic RESTful Authentication with PowerShell.

$Credential = Get-Credential
$auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Credential.UserName+':'+$Credential.GetNetworkCredential().Password))
$head = @{
  'Authorization' = "Basic $auth"
}

At this point, the $head variable contains user information. The next step is to┬áconstruct a call to the /vmware/cis/session┬áendpoint and build a new session resource. In my case, the VCSA 6.5 appliance’s address is hard coded into the sample code, but you’d want to abstract that with a variable in most cases. I also favor using Invoke-WebRequest so that I can capture the status code, but Invoke-RestMethod would also be fine and would eliminate the need to convert the content away from JSON and into a hashtable. Your choice. ­čÖé

Note: If you hit an error with self signed certificates you can leverage this function here.

$r = Invoke-WebRequest -Uri http://172.17.48.24/rest/com/vmware/cis/session -Method Post -Headers $head
$token = (ConvertFrom-Json $r.Content).value
$session = @{'vmware-api-session-id' = $token}

The $token string is stored into the $session variable, which builds a new key-value pair that is required for authentication against secured API calls. Typically the key would be “bearer” but VMware has decided to use vmware-api-session-id. Just be aware of this as it’s sort of unique.

Calling the API

Now that a session is established and the required token details are ready, you can start calling other endpoints. In the case of my webinar, I make three different sample calls that we’ll review here.

Get VM Inventory Summary

The first call pulls summary information on all the virtual machines in the environment. This is done via the vcenter/vm endpoint. Note the use of $session in the header to authenticate the call.

$r1 = Invoke-WebRequest -Uri http://172.17.48.24/rest/vcenter/vm -Method Get -Headers $session
$vms = (ConvertFrom-Json $r1.Content).value
$vms
$vms.Count

The remaining code just pulls the results from the response content, converts it from JSON to a hashtable, and peels away the “value” wrapper. I then return the value of $vms to the screen and count the number of objects in $vms for demonstration purposes. Nothing special going on there.

memory_size_MiB : 1024
vm : vm-57
name : SE-MABUABED-LINUX
power_state : POWERED_ON
cpu_count : 1

memory_size_MiB : 2048
vm : vm-58
name : SE-GPETROSI-WIN
power_state : POWERED_ON
cpu_count : 1

... snip ...

memory_size_MiB : 2048
vm : vm-59
name : SE-CVANTHOF-WIN
power_state : POWERED_ON
cpu_count : 1

memory_size_MiB : 2048
vm : vm-60
name : SE-MABUABED-WIN
power_state : POWERED_ON
cpu_count : 1

46

Get Detailed VM Information

The next call gets much more detailed information on a virtual machine named “SE-RKOSTERS-LINUX” run by my Dutch colleague and fellow VCDX, Rutger Kosters. I picked on him specifically because I’m attached to Rubrik’s EMEA vCenter Server Appliance and I know he has well oiled workloads operating in the lab! ­čśë

Because the vSphere API uses the managed object reference (moref) to track objects, we’ll first need the moref of Rutger’s VM in order to get details on it. Doing a quick search for his name across the objects in $vms and pulling the key named “vm” gives us the moref value. I then store it in $moref and ask vcenter/vm/$moref┬áfor details.

Note: Another method would be using the “filter.names” filter┬áto find the resource by name in the previous call, in which the API would return only objects that match that name. Such as /vcenter/vm?filter.names=SE-RKOSTERS-LINUX.

$moref = ($vms | Where-Object {$_.name -eq 'SE-RKOSTERS-LINUX'}).vm
$r2 = Invoke-WebRequest -Uri http://172.17.48.24/rest/vcenter/vm/$moref -Method Get -Headers $session
$thevm = (ConvertFrom-Json $r2.Content).value
$thevm

Again, you could just use Invoke-RestMethod if desired and save yourself from converting the JSON. The results are saved to $thevm and it contains a lot of information on Rutger’s server.

cdroms : {@{value=; key=3002}}
memory : @{size_MiB=1024; hot_add_enabled=False}
disks : {@{value=; key=2000}}
parallel_ports : {}
sata_adapters : {}
cpu : @{hot_remove_enabled=False; count=2; hot_add_enabled=False; cores_per_socket=2}
scsi_adapters : {@{value=; key=1000}}
power_state : POWERED_ON
floppies : {}
name : SE-RKOSTERS-LINUX
nics : {@{value=; key=4000}}
boot : @{delay=0; retry_delay=10000; enter_setup_mode=False; type=BIOS; retry=False}
serial_ports : {}
guest_OS : RHEL_6_64
boot_devices : {}
hardware : @{upgrade_policy=NEVER; upgrade_status=NONE; version=VMX_08}

Change VM Power State

The final call queried and toggled the power state of Rutger’s server. Hope he wasn’t using it at the time! ­čÖé

These three lines of code will query, stop, and start a virtual machine using the vcenter/vm/$moref/power endpoint. Note that  you add /stop to the power off request and /start to the power on request. Makes sense, right?

(Invoke-RestMethod -Uri http://172.17.48.24/rest/vcenter/vm/$moref/power -Method Get -Headers $session).value
Invoke-WebRequest -Uri http://172.17.48.24/rest/vcenter/vm/$moref/power/stop -Method Post -Headers $session
Invoke-WebRequest -Uri http://172.17.48.24/rest/vcenter/vm/$moref/power/start -Method Post -Headers $session

There’s no meaningful results to share for stop and start. You’ll just see a 200 “OK” response with no content in the reply. If the virtual machine is already in the state requested – such as trying to power off a powered off server – you’ll get an error.

Invoke-WebRequest -Uri http://172.17.48.24/rest/vcenter/vm/$moref/power/start -Method Post -Headers $session
Invoke-WebRequest : The remote server returned an error: (400) Bad Request.
At line:1 char:1
+ Invoke-WebRequest -Uri http://172.17.48.24/rest/vcenter/vm/$moref/po ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
 + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

And there you have it!

Thoughts

The vSphere API still has a ways to go from a feature-richness and documentation perspective, but it’s really enjoyable to see the first iteration of the Swagger implementation go live. If you want to see the available endpoints for your server, point to http://{ip/fqdn}/apiexplorer/┬áto browse the Swagger UI. Have fun!