Using the Automox API: Missing Patches

Today I will be continuing sharing some information on using the Automox API. In this post I will show you how to get a list of the uninstalled patches from your systems using the API.

There are a number of API features to use which can be found here: https://docs.automox.com/api/. In this example we will go over using the software_version API call using python and we will create a graph of missing packages using Plotly. Be sure to log in to the console, navigate to Settings, and you’ll find the API Key at the bottom of the page.

The Software_version API is structured as shown below.

[
 {
 “server_count”: 0,
 “severity_low_count”: 0,
 “severity_medium_count”: 0,
 “severity_high_count”: 0,
 “severity_other_count”: 0,
 “size”: 0,
 “results”: [
 {
 “id”: 0,
 “software_id”: 0,
 “name”: “string”,
 “display_name”: “string”,
 “version”: “string”,
 “os_family”: “string”,
 “severity”: “string”,
 “server_count”: 0,
 “approvals”: [
 {
 “id”: 0,
 “software_version_id”: 0,
 “policy_id”: 0,
 “manual_approval”: true,
 “manual_approval_time”: “2018–06–25T16:32:31.508Z”,
 “auto_approval”: true,
 “server_count”: 0
 }
 ],
 “pending_update”: {},
 “total_count”: 0,
 “total_server_count”: 0,
 “total_severity_low_count”: 0,
 “total_severity_medium_count”: 0,
 “total_severity_high_count”: 0,
 “total_severity_other_count”: 0
 }
 ] }
 ]

While this call gives you a lot of information, we will only look at patches missing from systems and the number of systems missing that patch. This can be caused, for example, because a machine has been turned off for the weekend.

A simple method to get a list would be to just display to the screen as shown below.

for item in pageText[‘results’]:
 serverName=item[‘display_name’] for item2 in item[‘pending_update’]:
 missingCount=item2[‘server_count’] print( serverName + ” ” + str(missingCount))

The output would be:

joes-MacBook-Pro:AMX-API joe$ ./software.py –dump
 2018–05 Cumulative Update for Windows 10 Version 1803 for x64-based Systems (KB4103721) 1
 2018–05 Cumulative Update for Windows 10 Version 1803 for x64-based Systems (KB4103721) 1
 2018–06 Security Monthly Quality Rollup for Windows Server 2008 R2(KB4284826) 1
 Adobe Acrobat Reader DC 1
 Adobe Reader (32-bit) 1
 Command Line Tools (macOS High Sierra version 10.13) for Xcode 1
 Definition Update for Windows Defender Antivirus — KB2267602 1
 Definition Update for Windows Defender Antivirus — KB2267602 1
 Digital Camera RAW Compatibility Update 1
 Firefox 1
 Google Chrome 1
 Google Chrome 1
 iTunes 1
 kernel-tools.x86_64 1
 kernel.x86_64 1
 macOS High Sierra 10.13.3 Update Combo 1
 macOS High Sierra 10.13.5 Update 1
 Microsoft Office 365 — en-us 1
 Remote Desktop Client Update 1
 Safari 1
 Security Update 2018–003 1
 system-release.noarch 1

You may want a CSV or a table as an output. That can be done with just pretty tables and writing a file.

As usual you would want to perform imports of required modules:

import json
 import requests
 from prettytable import PrettyTable
 import argparse
 from datetime import datetime

I am a huge, HUGE fan of using ArgParse to pass in things like your API Key and switches. It is just easier than parsing sysargv options.

parser = argparse.ArgumentParser(description=’Automox API Example’)
 parser.add_argument(‘–limit’, help=”Limit results to X”, type=int)
 parser.add_argument(‘–csv’, help=”Output as CSV”, action=”store_true”)
 parser.add_argument(‘–table’, help=”Output as table”, action=”store_true”)
 parser.add_argument(‘–graph’, help=”Output as table”, action=”store_true”)
 parser.add_argument(‘–dump’, help=”Dump data & exit”,action=”store_true”)
 parser.add_argument(‘apiKey’, help=”API Key “, type=str)
 parser.add_argument(‘orgId’, help=”AMX Org ID “, type=str)
 args=parser.parse_args()

Then you would request the JSON using requests and loop through the data. You’ll note I am creating a table or writing a CSV based on the user arg.

if args.csv:
 filename=datetime.now().strftime(‘%Y-%m-%d %H:%M:%S’) + “-noncomp.csv”
 fh=open(filename, “w+”)

table=PrettyTable([“Package”, “Machines to be Upgraded”])
 for item in pageText[‘results’]:
 packageName=item[‘display_name’] for item2 in item[‘pending_update’]:
 missingCount=item2[‘server_count’] if args.table:
 table.add_row([packageName, missingCount])
 if args.csv:
 fh.write(“\”{}\” , {}”.format(packageName, missingCount))
 if args.graph:
 xData.append(packageName)
 yData.append(missingCount)

if args.limit:
 if i >= args.limit:
 break
 i+=1

This will create a table or CSV which you can open in Excel, etc.

If you wanted to carry this further and create graph from this data you would import Plotly and graph using just a few lines of code.

if args.graph:
 plotly.offline.plot({
 “data”:[plotly.graph_objs.Bar(x=xData, y=yData)],
 “layout”:plotly.graph_objs.Layout(title=”Missing Package Count”,
 xaxis=dict(title=”Package Name”),
 yaxis=dict(title=”Count”))})

The graph would look like the one below, which is not terribly interesting as I am only missing one patch each on a single system.

And the script start to finish looks like this:

#!/usr/bin/env python3
 import json
 import requests
 from prettytable import PrettyTable
 import argparse
 from datetime import datetime
 parser = argparse.ArgumentParser(description=’Automox API Example’)
 parser.add_argument(‘–limit’, help=”Limit results to X”, type=int)
 parser.add_argument(‘–csv’, help=”Output as CSV”, action=”store_true”)
 parser.add_argument(‘–table’, help=”Output as table”, action=”store_true”)
 parser.add_argument(‘–graph’, help=”Output as table”, action=”store_true”)
 parser.add_argument(‘–dump’, help=”Dump data & exit”, action=”store_true”)
 parser.add_argument(‘apiKey’, help=”API Key “, type=str)
 parser.add_argument(‘orgId’, help=”AMX Org ID “, type=str)
 args=parser.parse_args()

baseUrl=”https://console.automox.com/api/software_version?api_key=”
 url=baseUrl + args.apiKey + “&o=” + args.orgId + “&pendingUpdate=1”

i=0
 pageText=requests.get(url).json()

if args.graph:
 try:
 import plotly
 import plotly.graph_objs as go
 xData=[] yData=[] except:
 print(“ERROR: Plotly not installed, try pip3 install plotly”)
 quit()

if args.dump:
 print(pageText)
 for item in pageText[‘results’]:
 serverName=item[‘display_name’] for item2 in item[‘pending_update’]:
 missingCount=item2[‘server_count’] print( serverName + ” ” + str(missingCount))
 quit()

if args.csv:
 filename=datetime.now().strftime(‘%Y-%m-%d %H:%M:%S’) + “-noncomp.csv”
 fh=open(filename, “w+”)

table=PrettyTable([“Package”, “Machines to be Upgraded”])
 for item in pageText[‘results’]:
 packageName=item[‘display_name’] for item2 in item[‘pending_update’]:
 missingCount=item2[‘server_count’] if args.table:
 table.add_row([packageName, missingCount])
 if args.csv:
 fh.write(“\”{}\” , {}”.format(packageName, missingCount))
 if args.graph:
 xData.append(packageName)
 yData.append(missingCount)

if args.limit:
 if i >= args.limit:
 break
 i+=1

if args.table:
 print(table)
 if args.csv:
 fh.close()
 if args.graph:
 plotly.offline.plot({
 “data”:[plotly.graph_objs.Bar(x=xData, y=yData)],
 “layout”:plotly.graph_objs.Layout(title=”Missing Package Count”,
 xaxis=dict(title=”Package Name”),
 yaxis=dict(title=”Count”))})

Now that you have begun to dive deeper in to the Automox API you can continue to automate features of your patch management. If you have any questions, feel free to contact support@automox.com.

As previously published on Automox.com