Using PowerShell and REST-API to create a VM in vCenter

VMware vSphere 6.5 comes with a RESTful API implementation and there’s some great documentation out there- starting with the API Explorer ( ). Here’s a quick piece on how to use this API to create a VM from the PowerShell command line. This is intentionally not using PowerCLI,  just the native PowerShell cmdlets- partly as a REST learning experience for me, and partly so the API code can be transferred to another language at a later date.

Step 1- Authenticate with the Server.

This 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 trusted certificates on my homelab. is the IP of my VCSA, so if you’re reusing this anywhere remember to replace that hard coded value where it appears.

#Step 1- Authenticate with the Server
#Ignore Server Certs- This is on my not-very-well-certified home lab.
if (-not ([System.Management.Automation.PSTypeName]'ServerCertificateValidationCallback').Type)
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
public class ServerCertificateValidationCallback
public static void Ignore()
if(ServicePointManager.ServerCertificateValidationCallback ==null)
ServicePointManager.ServerCertificateValidationCallback +=
Object obj,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors errors
return true;
Add-Type $certCallback

#Get Some Credentials and Determine Authorisation Methods
$Credential = Get-Credential
$auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Credential.UserName+':'+$Credential.GetNetworkCredential().Password))
$head = @{
'Authorization' = "Basic $auth"

#Authenticate against vCenter
$r = Invoke-WebRequest -Uri -Method Post -Headers $head
$token = (ConvertFrom-Json $r.Content).value
$session = @{'vmware-api-session-id' = $token}

Now we have the Session ($session) we can test this by retrieving a list of VMs.

#Get a List of VMs
$r1 = Invoke-WebRequest -Uri -Method Get -Headers $session
$vms = (ConvertFrom-Json $r1.Content).value

Step 2- Construct the JSON specification

To create a new VM we need to provide a minimal spec for the machine, in JSON format. We need to tell it the intended Guest OS, what datastore is going to hold the VM, and where the VM will be placed in the resource/folder structure. To complete this we need to establish what options are available- just sticking in the display names of a datastore or folder from the Web Client will not work and will likely generate 404 responses to the API call.

To find these names we can use the API, API explorer gives us the following urls

Datastore:       /rest/vcenter/datastore
Folder:              /rest/vcenter/folder
Resource Pool: /rest/vcenter/resource-pool

So we can use PowerShell to retrieve a list of Datastores using this line of code

(Invoke-RestMethod -Uri -Method Get -Headers $session ).value

which will produce a list of datastores, each looking something like this:

datastore  : datastore-11
name       : Datastore2
type       : VMFS
free_space : 100553195520
capacity   : 249913409536

From this example we want the value of the “datastore” field, e.g “datastore-11”.

Once we have this information we can combine it all to create a JSON spec file. My example looks like this:

"spec": {
"guest_OS": "RHEL_7_64",
"placement" : {
"datastore": "datastore-11",
"folder": "group-v224",
"resource_pool": "resgroup-182"

Step 3- Create the Virtual Machine.

Now we’ve done all this prep work, creating a Virtual Machine comes down to a single line of PowerShell pointing at the data.txt file containing the JSON code from Step 2.

Invoke-WebRequest -Uri -Method Post -Headers $session -ContentType "application/json" -Body (Get-Content data.txt)

Example Output:

StatusCode        : 200
StatusDescription : OK
Content           : {"value":"vm-462"}
RawContent        : HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json
Date: Mon, 27 Mar 2017 09:41:34 GMT

Forms             : {}
Headers           : {[Transfer-Encoding, chunked], [Content-Type, application/json], [Date, Mon, 27 Mar 2017 09:41:34 GMT]}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 18

The VM is created and we can check this from the vSphere Client:

2017-03-27 (10)

So, to summarise. Native PowerShell, with a little bit of JSON, can be used to communicate with the vSphere APIs and create new Virtual Machines. Depending on your use case there may be better ways of implementing automation processes through this API (PowerCLI is a good start) but if you want to drop to the raw RESTful API, possibly as a stepping stone to a larger project, PowerShell provides a handy method to get started down that path.


vHighlights #003

Some highlights from VMware ecosystem and Virtualisation in general from the past 7 days. Announcements, discoveries, and useful bits-and-bobs found on  the internet. Week ending 26th March 2017

  • vSphere 6.0 U3a has been released– this patches the Apache Struts vulnerability which was fixed in 6.5 last week. However- note that it mentions in the release notes that upgrading from vCenter Server 6.0 Update 3 to vCenter Server 6.5 is not supported.
  • AmazonWebservices Logo.svgAlex Galbraith’s talk with the Datanauts podcast crew titled “AWS Warts And All” – definitely worth a listen if you have even the slightest interest in AWS.
  • Step-by-Step instructions on enabling HA on a vSphere 6.5 Infrastructure– I followed these on my HomeLab this week.

Rolling back a failed VCSA HA deployment

The deployment of High Availability in the vCenter Server Appliance 6.5 is very slick and there’s a great step-by-step walkthrough of how to implement it. However, sometimes things go wrong – in my case a misconfiguration in the underlying network meant that the hosts I was trying to deploy to couldn’t reach each other on the new HA network.

The good news is the smooth Installation process is accompanied by a smooth uninstaller when things have gone wrong. It’s nice to see that this part of the application lifecycle process hasn’t been ignored by the development team at VMware. With the right planning and a bit of luck, you’ll never have to see this yourself- but here’s some example screenshots.

The install has failed, the wizard was unable to configure HA, and we are left with a situation looking like this:


The vSphere Web Client is telling me “vCenter HA has an invalid configuration. Click the remove button to destroy the current vCenter HA cluster configuration”. And it is really as simple as that, clicking Remove starts the process- this doesn’t destroy your vCenter environment- just the failed HA attempt – and vCenter reverts back to the model it was using beforehand. We get a nice clear explanation of what is going to be done, details of what manual steps may be necessary, and an option to change our mind.


The task proceeds like any other vCenter operation, showing as Completed in the Recent Tasks bar- in my homelab this removal task took just 11 seconds.


Once done it was just a case of powering down and removing the defunct Passive and Witness VMs, fixing the pre-existing fault that had caused the error in the first place, and then running the install again.It should end up looking something like this:image

It’s always good to see that development effort has been put into helping the user when something unexpected has occurred and this is a good example of that.

vHighlights #002

Some highlights from VMware ecosystem and Virtualisation in general from the past 7 days. Announcements, discoveries, and useful bits-and-bobs found on  the internet. Week ending 19 March 2017




PowerShell Quick Tip- Letter Frequency

With a list of Surnames in a text file I wanted to see how many start with A, how many with B, and so on. This is my PowerShell solution:

(Get-Content .\surnames.txt).Substring(0,1).ToUpper() |
  Sort-Object | Group-Object |Select-Object Name, Count

Example Input (surnames.txt file):


Example Output:

Name Count
---- -----
A      162
B      372
C      365
D      193
E      187
F      198
G      154
H      321