Skip to content

Instantly share code, notes, and snippets.

@karpadiem
Last active November 18, 2024 12:54
Show Gist options
  • Select an option

  • Save karpadiem/133f1ffe6ba62b2a8ca33aff840bd384 to your computer and use it in GitHub Desktop.

Select an option

Save karpadiem/133f1ffe6ba62b2a8ca33aff840bd384 to your computer and use it in GitHub Desktop.
This script is used to audit Mosyle MDM's user and devices license. It queries their API for devices and calculates the amount of licenses an account should be charged for. Using this we found that we were being billed for an extra User Enrollment license for a device and user that no longer showed in our dashboard.
# Author: Jake Garrison
# Date: 2023-03-29
# Description: This script fetches devices from the Mosyle API and processes it to help us in creating our managment fee reports. It can also be used to audit Mosyle licenses to compaire with current billing.
# This script requires the Mosyle API token, Mosyle API URL, Mosyle API User, and Mosyle API Password to be set. It also requires the tabulate module to be installed. You can install it with pip install tabulate (or pip3 install tabulate)
# THis is a simplified version of our script primarly aimed at helping other companies perform a license audit.
import base64
import requests
import json
from sys import exit
from tabulate import tabulate
mosyleApiToken = 'xxxxxxxxxxxxxxxx'
mosyleAPIUrl = 'https://businessapi.mosyle.com/v1' #change this if you are using a different EDU instead of business
mosyleAPIUser = 'email@domain.com' #admin user to authinicate with
mosyleAPIPassword = 'xxxxxxxxxxxx' #password of the admin user above
class Mosyle:
# Create Mosyle instance
def __init__(self, key, url = "https://businessapi.mosyle.com/v1", user = "", password = ""):
# Attribute the variable to the instance
self.url = url
self.request = requests.Session()
self.request.headers["accesstoken"] = key
#base64 encode username and password for basic auth
userpass = user + ':' + password
encoded_u = base64.b64encode(userpass.encode()).decode()
self.request.headers["Authorization"] = "Basic %s" % encoded_u
# Create variables requests
def list(self, os):
print("fetching devices of type:", os)
params = {
"operation": "list",
"options": {
"os": os
}
}
# Concatanate url and send the request
return self.request.post(self.url + "/devices", json = params )
def listTimestamp(self, start, end, os):
params = {
"operation": "list",
"options": {
"os": os,
"enrolldate_start": start,
"enrolldate_end": end
}
}
return self.request.post(self.url + "/devices", json = params )
def listmobile(self):
params = {
"operation": "list",
"options": {
"os": "ios"
}
}
return self.request.post(self.url + "/devices", json = params )
def listuser(self, iduser):
params = {
"operation": "list_users",
}
if iduser is not None:
params["options"] = {
"id": iduser
}
return self.request.post(self.url + "/users", json = params )
def setAssetTag(self, serialnumber, tag):
params = {
"operation": "update_device",
"serialnumber": serialnumber,
"asset_tag": tag
}
return self.request.post(self.url + "/devices", json = params )
# Set the token for the Mosyle Api
mosyle = Mosyle(mosyleApiToken, mosyleAPIUrl, mosyleAPIUser, mosyleAPIPassword)
#device types to get from mosyle. AppleTV devices are not needed for this report as they are free and do not count towards the license count
deviceTypes = ['mac', 'ios']
allUsers = mosyle.listuser(None).json()
allUsers = allUsers['response'][0]['users']
totlaLicenses = {'device' : 0, 'user' : 0, 'total' : 0}
print(tabulate(allUsers))
def checkUserAndReturn(allUsers, userid):
#check all users for 'identifier' key with value of userid
for user in allUsers:
if user['identifier'] == userid:
return user
#if we get here, we didn't find the user, get it from mosyle
userInfo = mosyle.listuser(userid).json()
return userInfo['response'][0]['users'][0]
#list of devices
devices = []
#list of of users set up with user enrollment
UEusers = {}
#loop through the device types and get the devices
for deviceType in deviceTypes:
#get all devices from mosyle
devices_responses = mosyle_response = mosyle.list(deviceType).json()
if 'status' in mosyle_response:
if mosyle_response['status'] != "OK":
print('There was an issue with the Mosyle API. Stopping.', mosyle_response['message'])
exit();
if 'status' in mosyle_response['response'][0]:
print('There was an issue with the Mosyle API. Stopping script.')
print(mosyle_response['response'][0]['info'])
exit()
#clean up the device information and put it in a list
for device_response in devices_responses['response'][0]['devices']:
#if the device does not have a serial number, it is a user enrolled device
if device_response['serial_number'] == None:
#this is a user enrolled device. Check if the UEusers dictionary has a userid key with mac_response['userid']. If not, add them and increase set their mac count to 1, ios count to 0. If they are, increase their mac count by 1
if device_response['userid'] not in UEusers:
userInfo = checkUserAndReturn(allUsers, device_response['userid'])
email = userInfo['email']
#get the domain from the email address
UEusers[device_response['userid']] = {
'userid': device_response['userid'],
'mac_count': 0,
'ios_count': 0
}
#increase the user enrollment license count
totlaLicenses['user'] += 1
#increase the total license count
totlaLicenses['total'] += 1
#if the device is an ios device, increase the ios count by 1
if device_response['os'] == 'ios':
UEusers[device_response['userid']]['ios_count'] += 1
if device_response['os'] == 'mac':
UEusers[device_response['userid']]['mac_count'] += 1
else:
#this is a device enrolled mac. Add it to the macs list
#take the first 3 characters of mac_response['device_name'] and determain what company it belongs to
#check if the response has an userid key, if not, set it to None
if 'userid' not in device_response:
device_response['userid'] = None
devices.append({
'serial': device_response['serial_number'],
'device_type': device_response['os'],
'asset_tag': device_response['asset_tag'],
'name': device_response['device_name'],
'user': device_response['userid']
})
#increase the device license count
totlaLicenses['device'] += 1
#increase the total license count
totlaLicenses['total'] += 1
#print the devices that count towards the device license count
print(tabulate(devices, headers="keys"))
table_data = [[user, data['mac_count'], data['ios_count'],(data['mac_count'] + data['ios_count'])] for user, data in UEusers.items()]
#print the users that count towards the user license count
print(tabulate(table_data, headers=['User ID', 'BYOD Mac', 'BYOB iOS', 'Total Devices']))
#print the total licenses in a table
print(tabulate([['Device', totlaLicenses['device']], ['User', totlaLicenses['user']], ['Total', totlaLicenses['total']]], headers=['License Type', 'Count']))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment