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.
1 2 3 4 5 | $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.
1 2 3 | $r = Invoke-WebRequest -Uri https://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.
1 2 3 4 | $r1 = Invoke-WebRequest -Uri https://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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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
.
1 2 3 4 | $moref = ($vms | Where-Object {$_.name -eq 'SE-RKOSTERS-LINUX'}).vm $r2 = Invoke-WebRequest -Uri https://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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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?
1 2 3 | (Invoke-RestMethod -Uri https://172.17.48.24/rest/vcenter/vm/$moref/power -Method Get -Headers $session).value Invoke-WebRequest -Uri https://172.17.48.24/rest/vcenter/vm/$moref/power/stop -Method Post -Headers $session Invoke-WebRequest -Uri https://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.
1 2 3 4 5 6 7 | Invoke-WebRequest -Uri https://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 https://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 https://{ip/fqdn}/apiexplorer/
 to browse the Swagger UI. Have fun!
[…] step is well documented by Chris Wahl. I’ve borrowed some of his code here, and accompanied it with a section to get around the lack of […]
I found your posts while trying to make sense of the SDK’s that VMWare provides to take advantage of the REST interface. Things seemed to be a little confusing, especially since I’ve never really worked with VMWare before, until I realized that (at least) the Python SDK appears to leverage both the REST interface AND the previous non-REST(?) interface.
Once realizing that, and doing some testing with Postman and Python, I believe I have a better handle on using the REST API with VCSA 6.5… Except for one thing…
With either method, I can successfully login against “/rest/com/vmware/cis/session”. I get the session-id and I can then perform other calls, such as against “/rest/vcenter/datacenter” (status code 200).
However, I am receiving a 403 Forbidden error (not a 401 error!) when accessing any of the appliance URLs, such as “/rest/appliance/system/uptime” or “/rest/appliance/health/system”. I am getting the same 403 error regardless of whether using Postman or Python.
I have tried this with credentials for users with read-only access, as well as full Administrator creds.
I’m sure its something simple that I’m missing… I’m just not sure what it is.
Any thoughts?
Thanks!
I’m not sure this is the proper / best practices solution, but it does appear to be an answer…
The user connecting to the REST API needs to be a member of the SystemConfiguration.Administrators group.
As part of my exploration of the REST API, I was only wanting my script user to have read-only permissions. If this is the proper solution though, it seems they require more than just read-only permissions to access the information that one can obtain from the REST API. :-/
Further use suggests that its just going to be easier if the account used to login is part of the Administrators group. I found that one cannot list vcenter folders if only part of the “SystemConfiguration.Administrators” group.
So even though, at this time, I’m not looking to make modifications to the configuration of the system, just read / list / view details, it appears one is forced to use an account with higher permissions than explicitly needed for many of the calls that simple list or return values.
Great post Chris, do you know the endpoint name so that i can access the vSphere Web API via rest? I want to get stuff like VM disk sizes and drive letters and the automation API doesn’t have that data.
[…] a REST based API, I have seen lots of people do this with the vSphere APIs and examples can be seen here and here. This is generally done using the Invoke-WebRequest or Invoke-RESTMethod […]