Today I will continue to share information about using the Automox API. This post will show you how to get a list of uninstalled patches from your systems using the API.
There are a number of API features to use which can be found here. 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 was 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 easily with 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. Note that 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:
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.
About Automox
Facing growing threats and a rapidly expanding attack surface, understaffed and alert-fatigued organizations need more efficient ways to eliminate their exposure to vulnerabilities. Automox is a modern cyber hygiene platform that closes the aperture of attack by more than 80% with just half the effort of traditional solutions.
Cloud-native and globally available, Automox enforces OS & third-party patch management, security configurations, and custom scripting across Windows, Mac, and Linux from a single intuitive console. IT and SecOps can quickly gain control and share visibility of on-prem, remote and virtual endpoints without the need to deploy costly infrastructure.
Experience modern, cloud-native patch management today with a 15-day free trial of Automox and start recapturing more than half the time you're currently spending on managing your attack surface. Automox dramatically reduces corporate risk while raising operational efficiency to deliver best-in-class security outcomes, faster and with fewer resources.