This post will be about how to update the vCenter Server Appliance through the rest API using the PowerCLI.
First we need check online or the CD for the new update. So let’s take a look at the API again: https://vmware.github.io/vsphere-automation-sdk-rest/vsphere/index.html

The general purpose of my posts is more to show you how to do it and not to do the work for you. In the spirit of: “If I teach you how to fish you have fish for the rest of your life instead of me giving you a fish and you only have a fish for a day.” Therefore I will not go through all possible operations but I think it will be straight forward to apply the principle of the operations I will highlight. So let’s get to work. The list operation is the one that will check for the new updates, this is the one that we start with.

So we see here there are two parameters the query takes, source_type and url. Both of type string. url being optional, source_type mandatory. Source_type can be “LAST_CHECK”, LOCAL or LOCAL_AND_ONLINE. Before we can run anything we need to connect first. If you have read my previous post on the rest API you already know what to do.
#Connect to our VCSA first.
$cisConnection = Connect-CisServer -server vcenter.txusa.cloud
## Get the object. This is pretty much always the same we, translate the name from the API.
$getService = Get-CisService -Name "com.vmware.appliance.update.pending"
## Ignoring the optional parameter URL and only providing parameter to check CD and online.
$getService.list("LOCAL_AND_ONLINE")
Now here is the thing. The request can potentially fail. I see it fail when there simply was no new update with following error.
A server error occurred: ‘com.vmware.vapi.std.errors.internal_server_error’: Error in method invocation [Errno 2] No such file or directory:
‘/storage/core/software-update/updates’ (Server error id: ‘vapi.method.invoke.exception’). Check $Error[0].Exception.ServerError for more details.
So we must use a try and catch. This means we try to run the operation and if it fails we will catch the error or do what ever when it fails.
$getService = Get-CisService -Name "com.vmware.appliance.update.pending"
try
{
$checkResult = $getService.list("LOCAL_AND_ONLINE");
}
catch
{
#We catch the error and search for the known error
if(Error[0].Exception -like "*com.vmware.vapi.std.errors.internal_server_error*")
{
write-host "No such file or directory"
}
else
{
#An unknown error message
write-host "Something went wrong."
}
}
#If up to date and there is no error $checkResult will be empty.
if($checkResult)
{
#For this example we are only interested in the version
$patchVersion = $checkResult.version
}
The entire $checkResult would look like this but we are only interested in the version because we need it later.
Help : @{Documentation=The {@name Summary} {@term structure} contains the essential information about the update; version=; description=; priority=; severity=;
update_type=; release_date=; reboot_required=; size=}
severity : CRITICAL
update_type : FIX
size : 1833
reboot_required : True
release_date : 1/17/2019 12:00:00 AM
description : @{Help=; args=System.Collections.Generic.List`1[System.String]; default_message=Patch for vCenter Server Appliance 6.7.0; id=com.applmgmt.plain_message}
priority : LOW
version : 6.7.0.21000
Next is stage_and_install. This one is a little but more complicated. Parameter is version and a user_data object. We got the version from the previous call but now we also need to create the user_data object. This gave me a lot of headache, lots of try and error. We assume we are already connected.

#We know this part
$getService = Get-CisService -Name "com.vmware.appliance.update.pending"
#This is how you create a user_data object
$user_data = $getService.help.stage_and_install.user_data.Create()
#Then you need to add the user. I was not sure what to put here but I found out
#that it did not matter at all as long as the structure is right.
#Add two elements to the array.
$user_data.add("whatever","whatever")
#Now do the stage and install. Provide the version that we got from the
#previous step and the $user_data array.
$getService.stage_and_install($patchVersion,$user_data)
We can now check for the status but during installation you will very quickly get kicked off the server. You will have to log in after the reboot. So let’s look at the API again. Notice, there is no .pending. And we see there are no parameters. So this is as simple as it gets.

#We know this part, now without pending
$getService = Get-CisService -Name "com.vmware.appliance.update.pending"
#Get the status.
$getService.get()
The result would be like this. The interesting part would be the state. According to the API the state could have following values.
UP_TO_DATE: The appliance is up to date.
UPDATES_PENDING: A new update is available.
STAGE_IN_PROGRESS: The appliance update is in progress of downloading an update.
INSTALL_IN_PROGRESS: The appliance update is in progress of installing an update.
INSTALL_FAILED: The appliance update failed and cannot recover.
ROLLBACK_IN_PROGRESS: The appliance update failed and recovery is in progress.
When the update started it will have “INSTALL_IN_PROGRESS”. Again, you will be quickly get kicked off the system and have to log in again. After reboot it should say “UP_TO_DATE”
$getUpdate = Get-CisService -Name “com.vmware.appliance.update”;
$getUpdate.get();
Help : @{Documentation=The {@name Info} {@term structure} describes the state of the appliance update.; state=; task=; version=; latest_query_time=}
latest_query_time : 3/24/2019 9:30:00 PM
task : @{Help=; parent=; cancelable=False; subtasks=System.Collections.Generic.Dictionary2[System.String,System.Management.Automation.PSObject]; end_time=4/2/2019
7:08:30 PM; description=; subtask_order=System.Collections.Generic.List
1[System.String]; error=; target=; start_time=4/2/2019 7:07:53 PM;
service=applmgmt/update; progress=; operation=stage_and_install; user=; status=RUNNING}
state : INSTALL_IN_PROGRESS
version : 6.7.0.21000
I was stuck with the “user_data” fields as well, I was however using Invoke-RestMethod, but switching to Get-CisService made everything much simpler. I now have a script that will handle automated VCSA updates, thank you so much!
Awesome! I am glad my post could help you.
I was exploring a similar solution using the Invoke-RestMethod cmdlet, but ran into the same issue with the “user_data” fields when trying to install the update, I was able to stage it no problem, but couldn’t figure out how to pass user_data to apply it.
Switching to Get-CisService made everything work like a charm, thank you for this! I now have a script to automate VCSA patching.
Awesome! I am glad my post could help you.