A Foray into Working with the VMWare Workspace ONE APIs

Every now and then, I get a little bit bored. After enough years, you run out of stuff to do in your MDM environment. We can optimize and do all sorts of crazy/random things to build a utopia of mobility. My latest optimization adventure is leveraging the REST API to the best of our abilities. Let me take you on an exciting journey using PowerShell/Postman to solve some real-world issues plaguing Workspace ONE customers in a shared environment.

The problems caused by Shared SaaS

Shared SaaS environments are always the most cost-effective solution for customers. You pay a fair price, don’t incur tech debt for the most part, and can deliver maximum value to your organization. With this in mind, you do have certain gaps that you have to deal with. A few of these gaps are:

  • Lack of control over environment updates
  • Limited configuration and customization
  • Essentially sharing an environment with several customers
  • Lack of access to the database and stunted creativity when solving problems

How does the REST API Come Into Play?

The REST API offers a number of different options that let you do some interesting things that are not fully available via the GUI like most products. Some examples are:

  • Creating, Deleting, Updating, and Working with Smart Groups
  • Synchronizing and Querying Devices
  • Reassigning Devices to Different Users
  • Creating Users
  • Generating Enrollment Tokens
  • Sending Notifications

We frequently will run into situations where we need to do something quickly and accurately. A great example that comes to mind is when it comes to synchronizing devices. Let’s discuss the problem and then solution.

The Problem

Most people don’t actually understand the difference between the query and sync command in AirWatch/Workspace ONE.

Query: Querying forces the devices to check-in with the console and provided updated information about the device status

Sync: Synchronization forces the device to check-in for new apps/profiles/updates and applies them once the device is in a state where it can do so (e.g. when an iOS device is unlocked)

One of the major problems we face as engineers with Workspace ONE is how a very limited subset of commands can be done in bulk a.k.a. only certain commands can be performed on multiple devices at a given time. When you go beyond 10 devices, it becomes even more limited.

Shared SaaS compounds this issue even further as it will by default only check for new profiles/apps/etc every 6-8 hours, which as you know isn’t particularly useful when deploying new applications or triaging an issue. This was the use case that lead me to start looking at leveraging the API.

Setting up POSTMAN to use the WS1 API

The setup to run commands in Postman is relatively easy once you understand how it works. We need to setup two parts (the admin account and the API key):

Under Authorization, you set the admin account with basic auth:

Under headers, you set your API key under aw-tenant-code and set the Accept header to use the v2 API (you will just disable this key if you want to use v1).

You will learn quickly that most times you will end up using the v1 API mostly because there’s a number of gaps in v2. I tend to avoid mixing and matching v1 and v2 API commands because sometimes it just doesn’t work. Ideally, you can write each command as its own function if you need to use both v1 and v2 in a function, but I tend to avoid it if possible.

Working with the API and Engineering your Commands

Finding a Result Set to Work With

I start usually by performing some GETs to figure out what I’m trying to do because the API on the whole is poorly documented and not useful most of the time. So, I may start by performing a basic search to see what attributes I can work with:

The base command you start with for searching is: https://asXXX.awmdm.com/api/mdm/devices/search?

You follow this with setting various parameters as seen below. Typically, I use the device type, the org group ID, and page size so I can return the proper count of devices.

The goal when you are building scripts for building utilities and apps is to ensure you are returning the proper values to pipe into commands. Inadequate testing frequently leads to bad mistakes and potential impact. I engineer PowerShell in the same fashion, where we always do a GET before we SET.

Testing your Update Commands

Once you find a result set that works, we will then try the command with a single device to confirm it works.

The command that I use for sync device is: https://asXXX.awmdm.com/api/mdm/devices/{DeviceID}/commands?command=SyncDevice

The GET we did previously, returns an XML formatted result set for each device like this:

We simply, use the ID value and pass that to the DeviceID field. Provided you configured everything correctly, the sync command will return a HTTP OK (200).

I’m sure you are now wondering, why is this helpful? I can do a sync in the console! You can ONLY do a sync device per device and there is no bulk command supported. This is a major issue because people think “Query” does the job and it absolutely does not. Let’s walk through a simple PowerShell script that will help you solve this use case.

Putting the Power in Powershell

To achieve what we just did in Postman inside of PowerShell, we borrow a bit of code from Chris Halstead’s great session at VMWorld 2019 to build a foundation.

First we set the credentials and API key like we did in Postman via some basic read-host:

$Username = Read-Host -Prompt 'Enter the Username'
$Password = Read-Host -Prompt 'Enter the Password' -AsSecureString
$apikey = Read-Host -Prompt 'Enter the API Key'

Then we store it appropriately:

$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)

#Base64 Encode AW Username and Password
$combined = $Username + ":" + $UnsecurePassword
$encoding = [System.Text.Encoding]::ASCII.GetBytes($combined)
$cred = [Convert]::ToBase64String($encoding)

Then we build the header like we did in Postman. Notice that I commented out the v2 header:

$script:header = @{
"Authorization" = "Basic $cred";
"aw-tenant-code" = $apikey;

## "Accept" = "application/json;version=2";
"Content-Type" = "application/json";}

Now we build our array of devices that we want to sync below. A few nice things to keep in mind. I built separate functions for iPads and iPhones as the use cases may vary. I also write in a filter to filter out any devices that aren’t enrolled so the sync command doesn’t fail:

$devicetype = 'iPad'

$devices = Invoke-RestMethod -Method Get -Uri "https://asXXX.awmdm.com/api/mdm/devices/search?lgid=11111&PageSize=5000" -ContentType "application/json" -Header $header

$ipads = $devices.devices.id.value

$devicelist = $devices.devices | where-object -filterscript {$_.enrollmentstatus -eq "Enrolled"}

$ipads = $devicelist.id.value

Now that I have that array to work with, I can use it however I want to do some fun things. The two commands that I focus on are doing a device sync and then a device query. The brilliance of the array is you can now pass it to any list of commands depending on what you are trying to achieve:

foreach ($ipad in $ipads) { invoke-restmethod -Method Post -Uri "https://asXXX.awmdm.com/api/mdm/devices/$ipad/commands?command=SyncDevice" -ContentType "application/json" -Header $header | Out-Null }

foreach ($ipad in $ipads) { invoke-restmethod -Method Post -Uri "https://asXXX.awmdm.com/api/mdm/devices/$ipad/commands?command=DeviceQuery" -ContentType "application/json" -Header $header | Out-Null }

Bringing it all Together

Now that you understand how to use it, its entirely up to you how its used. There are a few good uses for leveraging the API commands via PowerShell:

  • Running certain API commands via windows scheduler
  • Building Utilities/Apps for various teams without needing to give them additional roles/controls
  • Leveraging the API inside of your ITSM or Mobile Flows

The main lesson to learn here is that we can always evolve and continue to do bigger and better things. We don’t need to restrict ourselves to what is available in the GUI. Scripting is an essential skill that will take you places in your career. PowerShell opens so many doors and gives you some great foundational skills.

I strongly recommend playing around and testing the REST API. If you do need help, reach out as I’ve learned a bunch about how to use the REST API for both Workspace ONE Access and Workspace ONE UEM. I cannot stress enough the usefulness of the API and how good it makes you look. Being able to tell teams that you created a new tool or utility makes you look great and solves business problems that cannot be easily solved otherwise.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s