Send a syncDevice from bash to an iOS device enrolled in Microsoft Intune
One thing that can be quite problematic with Microsoft Intune, is that it syncs with the device every 8 hours (every 15mn the first hour). It is usually fine, but in some scenarios you’ll want to trigger a sync programmatically.
This post will walk you through how to use Microsoft Intune’s API to trigger a syncDevice from bash, using curl. I’ll show you how to configure an application on Azure Portal to get the credentials, then how to test using Paw, and finally how to make a rudimentary script.
A word of caution: this method works for me, and it is provided “as is”, without warranty of any kind, express or implied. But feel free to add a comment below to improve the post.
Create an app on the Azure portal
First thing we need to do is to create an App on the Azure portal. We’ll choose “Client secrets” to make it easy, but you can use certificates instead (I won’t cover it).
Resources:
Quickstart: Configure a client application to access web APIs
Microsoft identity platform and OAuth 2.0 authorization code flow
Getting Access Token for Microsoft Graph Using OAuth REST API
So, connect to the Azure portal which is tied to your Microsoft Intune, and select the right tenant.
Create an App Registration
Go to Azure Active Directory
Click on “App registrations”
Click on “New Registration”
Choose a nice name
Select “Accounts in this organizational directory only (XXX only - Single tenant)”
Don’t fill the Redirect URI
Create a client secret
Go to “Certificates & secrets”
Click on “New client secret”
Choose a description and save the token value (you’ll see this only once)
Configure API Permissions
Go to API permissions, then add the following permissions, under “Microsoft Graph”:
DeviceManagementManagedDevices.Read.All (Delegated)
DeviceManagementManagedDevices.PrivilegedOperations.All (Delegated)
Then click on “Grant admin consent for XXX”.
Write down required information
You will need the following information:
Client ID (aka Application ID): find it on the “Overview” tab of the App registration you just created
Client Secret: you wrote it down earlier when you created a new client secret. If you haven’t, go back, delete your client secret and create a new one.
Tenant domain: If you go back to “Azure Active Directory” then “Custom domain names”, you’ll see it written (e.g. M365x208777.onmicrosoft.com)
Configure the API browser application
I use Paw, but virtually everyone I know uses Postman. If you choose Postman, have a look at the following resources from Microsoft:
Get the Access Token
Microsoft Graph uses OAuth 2.0. Here we want to get a Bearer token which we will use for subsequent calls to the API.
To move forward, create a new request, and enter the following information:
POST https://login.microsoftonline.com/[TENANT-DOMAIN]/oauth2/token
Body > Form URL-Encoded
client_id: the Client ID from “App Registration > Overview” (see earlier)
client_secret: the Client Secret you generated earlier
Resource: https://graph.microsoft.com
grant_type: client_credentials
Then hit CMD+R and the token will be on the right, under “access_token”. Right-click on it and click on “Copy Value”. Don’t do it by double-clicking on the field then CMD+C, otherwise you’ll get an error like “CompactToken parsing failed with error code: 80049217” later on.
Get the Device ID, from the list of devices
Create a new Request, with the following information:
GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices
Headers
Authorization: “Bearer [access_token]”
Hit “CMD+R” and you should see a list of devices on the right. What interests us is “value.id”. You may want to filter the view by “value.serialNumber” to get the device you want.
Post a “syncDevice” to the device
Now that you have the device ID, you can create another Request with it:
POST https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/[DEVICEID]/syncDevice (make sure you replace [DEVICEID] with the id you found earlier (like 9666-…)
Headers
Authorization: “Bearer [access_token]”
Hit “CMD+R” and if all goes well, you should get a “204 No Content”.
Verify the device had a sync
Resource: https://docs.microsoft.com/en-us/graph/api/intune-devices-manageddevice-get?view=graph-rest-1.0
We can do a very similar call to get managedDevices, but this time specify the device ID to get a single device instead of an array of all devices. Configure the request this way:
GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/[DEVICEID] (make sure you replace [DEVICEID] with the id you found earlier (like 9666-…)
Headers
Authorization: “Bearer [access_token]”
Hit “CMD+R”. We’re interested by “lastSyncDateTime” which should be very close to now (provided the device is on and replied to the push notification). Note that this value is in GMT, so translate to your timezone.
Putting it all together with curl
Install jq
jq is a very powerful JSON parser command line tool. We want to use it to better parse the response from the server. Install it in /opt/local/bin:
Go to https://stedolan.github.io/jq/download/ and download jq 1.6 binary for 64-bit. You can also install it with Homebrew or MacPorts if you prefer.
mkdir -p /opt/local/bin
mv ~/Downloads/jq-osx-amd64 /opt/local/bin/jq
chmod +x /opt/local/bin/jq
Get curl commands from Paw
Paw has a very handy feature that can generate code in many different languages and commands, including curl. to do so, click on the drop down menu top right of the console, and select “cURL” (sic). You can then paste it in your editor of choice.
Search for a specific serial number
Microsoft Graph have query parameters, that will allow you to filter a query with certain parameters. Here, we would like to return all the managedDevices with a specific serial number. To do so, we can use the URL Parameter $filter=startswith(serialNumber, ‘SERIALNUMBER’). You should still get an array, but with a single managedDevice.
Putting it all together
We want to assemble the following:
Get the access token (“.access_token”)
Get a managedDevice from a serial number (“.value[0] .id”)
send the syncDevice command
As a starter, I’ve done the following script. I leave you the task to work on the error control and make it reliable. If you can share it, all the better!
#!/bin/bash serialNumber="FA1QHC21GRY1" ## 1. Get the Access Token (".access_token") tokenResult=$(curl -sf -X "POST" "https://login.microsoftonline.com/M365x208777.onmicrosoft.com/oauth2/token" \ -H 'Content-Type: application/x-www-form-urlencoded; charset=utf-8' \ --data-urlencode "client_id=ae49b634-5140-48c1-9647-4158754110be" \ --data-urlencode "client_secret=_SbdfLpAVD-BiLMoqJcQEVN]3AQne470" \ --data-urlencode "Resource=https://graph.microsoft.com/" \ --data-urlencode "grant_type=client_credentials") accessToken=$(echo "${tokenResult}" | /opt/local/bin/jq -r '.access_token') ## Get a managedDevice, from a serial number (".value[0] .id") managedDeviceResult=$(curl -sf "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?\$filter=serialNumber%20eq%20%27${serialNumber}%27" \ -H "Authorization: Bearer ${accessToken}" \ -H 'Content-Type: application/x-www-form-urlencoded; charset=utf-8') deviceID=$(echo "${managedDeviceResult}" | /opt/local/bin/jq -r '.value[0] .id') ## send the syncDevice command syncDeviceResult=$(curl -sf -X "POST" "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/${deviceID}/syncDevice" \ -H "Authorization: Bearer ${accessToken}" \ -H 'Content-Type: application/x-www-form-urlencoded; charset=utf-8' -d "") if [ -z "${syncDeviceResult}" ]; then echo "syncDevice sent to ${serialNumber}" fi