API use case: Fetching application versions for all devices
Here's an example use case that's requested frequently from the mambo EMM team, the ability to view Android application versions across all deployed devices.
Due to local network or device conditions, applications can't always be updated when a new version is released. But how do you monitor a major version deployment?
Pulling application version through the API
In this use case, we are looking to understand what version of Google Chrome is deployed to our active devices.
- We want to validate Google Chrome version 100 has been deployed to devices
- We want a CSV generated for ease of data manipulation later
- In the CSV, we're labelling the app
Google Chrome
, but for other apps, this can be adjusted as desired - We have a very simple validator offering a Yes or No for version match, to make CSV manipulation easier later
- We have fetched our Team ID and Access token already, and have input it where
XXXXX
currently sits againstTEAM_ID
andACCESS_TOKEN
in the below script respectively.
The environment we're working with is JavaScript, and we'll use the following script, executed through Node.js. When complete, the script will output a CSV file named app-version-check.csv
in the folder the script was executed from.
Set up node
- nodeJS should be installed as described for your OS, the relevant page is here (opens new window)
- Install CSV-Stringify, which we need for the CSV portion of the below script, and axios as a dependency, with
npm install csv-stringify axios
Run the script
- Save the below to a local destination on your PC as a
.js
file. - Run the script:
node ./scriptname.js
- The CSV will be output to the same directory the script is run from
The script
const fs = require('fs');
// Run `npm install csv-stringify axios` before running this script
const { stringify: csvStringify } = require('csv-stringify');
/**
* Below are the options you can define before running the script
*/
// This requires an access token with "view policies, enrolment tokens, and devices" permissions
const ACCESS_TOKEN = 'XXXXX';
// Define the team ID to fethch for
const TEAM_ID = 'XXXXX';
// Define the package to filter for
const PACKAGE_NAME = 'com.android.chrome';
// Define the package label for CSV
const PACKAGE_LABEL = 'Google Chrome';
// Define version match
const PACKAGE_VERSION_MATCH = '100';
// Define where to write the CSV file
const FILE_PATH = `${__dirname}/app-version-check.csv`;
/**
* Below is the executable code of the script
*/
// Define CSV headers as a map of the `deviceFilter()` object to readable label
const csvHeaders = {
imei: 'IMEI',
deployedVersion: `${PACKAGE_LABEL} Deployed Version`,
versionMatch: `Meets ${PACKAGE_LABEL} Version Match`
};
/** Request setup */
// Define auth headers
const headers = new Headers();
headers.append('Authorization', `Bearer ${ACCESS_TOKEN}`);
headers.append('Accept', 'application/json');
// Setup request
const requestOpts = {
method: 'GET',
headers
};
const BASE_URL = `https://dashboard.mambomobility.com/api/platform/0/v1/teams/${TEAM_ID}/devices?includes[]=policy&limit=50&q[]=details:not:null`;
// Define a request state to process devices in chunks
const state = {
page: 0,
fetched: 0,
hasMore: true
};
/** Define CSV flow */
// Initiate CSV stream
const csvStream = csvStringify({
header: true,
columns: csvHeaders
});
// Append to CSV file when receiving data
csvStream.on('data', (row) => fs.appendFile(FILE_PATH, row, () => void 0));
// Log CSV errors
csvStream.on('error', (err) => {
console.error(`CSV stream error occured:`, err);
});
// Define the device filtering logic
function deviceFilter(device) {
// Find app from device app reports
const app = device?.details?.applicationReports?.find(
(report) => report.packageName === PACKAGE_NAME
);
// Map device to package version match
return {
imei: device.imei,
deployedVersion: app?.versionName ?? 'N/A',
versionMatch: app?.versionName?.startsWith(PACKAGE_VERSION_MATCH)
? 'Yes'
: 'No'
};
}
// Define the request flow
async function run() {
// Empty file to begin writing
await new Promise((resolve) => fs.writeFile(FILE_PATH, '', resolve));
// Loop until all devices are processed
while (state.hasMore) {
// Fetch devices
const request = new Request(`${BASE_URL}&page=${++state.page}`);
const res = await fetch(request, requestOpts);
// Parse response to JSON
const data = await res.json();
// Log response
console.log('RECEIVED QUERY RESPONSE:', data);
// Process devices
data.data.forEach((device) => {
// Map device to CSV data
const formattedData = deviceFilter(device);
// Write to CSV
csvStream.write(formattedData);
});
// Update state
state.fetched += data.data.length;
if (data.total <= state.fetched) {
state.hasMore = false;
}
}
// End the CSV stream
csvStream.end();
}
// Run the script
run();
Notes
- The script can be run as often as desired, and will always overwrite the output CSV file unless
${__dirname}/app-version-check.csv
is updated.