# This script prints a list of all bluetooth beacons in an organization # to terminal/sdtout or a file (Devices which are part of a network are considered in-use). # The fields printed are separated by a comma (,) and include": # uuid, major, minor, name, address, lat lng # # You need to have Python 3 and the Requests module installed. You # can download the module here: https://github.com/kennethreitz/requests # or install it using pip. # # To run the script, enter: # python getbeacons.py -k -o [-f ] # # If option -f is not defined, the script will print to stdout. # # To make script chaining easier, all lines not containing a # device record start with the character @ # # This file was last modified on 2017-10-26 import sys, getopt, requests, json def printusertext(p_message): # prints a line of text that is meant for the user to read # do not process these lines when chaining scripts print('@ %s' % p_message) def printhelp(): # prints help text printusertext("This is a script that prints a list of an organization's devices to sdtout or a file.") printusertext('') printusertext('Usage:') printusertext('python getbeacons.py -k -o [-f ]') printusertext('') printusertext('Use double quotes ("") in Windows to pass arguments containing spaces. Names are case-sensitive.') def getorgid(p_apikey, p_orgname): # looks up org id for a specific org name # on failure returns 'null' r = requests.get('https://dashboard.meraki.com/api/v0/organizations', headers={'X-Cisco-Meraki-API-Key': p_apikey, 'Content-Type': 'application/json'}) if r.status_code != requests.codes.ok: return 'null' rjson = r.json() for record in rjson: if record['name'] == p_orgname: return record['id'] return ('null') def getshardurl(p_apikey, p_orgid): # Looks up shard URL for a specific org. Use this URL instead of 'dashboard.meraki.com' # when making API calls with API accounts that can access multiple orgs. # On failure returns 'null' r = requests.get('https://dashboard.meraki.com/api/v0/organizations/%s/snmp' % p_orgid, headers={'X-Cisco-Meraki-API-Key': p_apikey, 'Content-Type': 'application/json'}) if r.status_code != requests.codes.ok: return 'null' rjson = r.json() return (rjson['hostname']) def getnwlist(p_apikey, p_shardurl, p_orgid): # returns a list of all networks in an organization # on failure returns a single record with 'null' name and id r = requests.get('https://%s/api/v0/organizations/%s/networks' % (p_shardurl, p_orgid), headers={'X-Cisco-Meraki-API-Key': p_apikey, 'Content-Type': 'application/json'}) returnvalue = [] if r.status_code != requests.codes.ok: returnvalue.append({'name': 'null', 'id': 'null'}) return (returnvalue) return (r.json()) def getdevicelist(p_apikey, p_shardurl, p_nwid): # returns a list of all devices in a network r = requests.get('https://%s/api/v0/networks/%s/devices' % (p_shardurl, p_nwid), headers={'X-Cisco-Meraki-API-Key': p_apikey, 'Content-Type': 'application/json'}) returnvalue = [] if r.status_code != requests.codes.ok: returnvalue.append({'lat': 'null', 'lng': 'null', }) return (returnvalue) return (r.json()) def main(argv): # get command line arguments arg_apikey = 'null' arg_orgname = 'null' arg_filepath = 'null' try: opts, args = getopt.getopt(argv, 'hk:o:f:') except getopt.GetoptError: printhelp() sys.exit(2) for opt, arg in opts: if opt == '-h': printhelp() sys.exit() elif opt == '-k': arg_apikey = arg elif opt == '-o': arg_orgname = arg elif opt == '-f': arg_filepath = arg if arg_apikey == 'null' or arg_orgname == 'null': printhelp() sys.exit(2) # get organization id corresponding to org name provided by user orgid = getorgid(arg_apikey, arg_orgname) if orgid == 'null': printusertext('ERROR: Fetching organization failed') sys.exit(2) # get shard URL where Org is stored shardurl = getshardurl(arg_apikey, orgid) if shardurl == 'null': printusertext('ERROR: Fetching Meraki cloud shard URL failed') sys.exit(2) # get network list for fetched org id nwlist = getnwlist(arg_apikey, shardurl, orgid) if nwlist[0]['id'] == 'null': printusertext('ERROR: Fetching network list failed') sys.exit(2) # if user selected to print in file, set flag & open for writing filemode = False if arg_filepath != 'null': try: f = open(arg_filepath, 'w') except: printusertext('ERROR: Unable to open output file for writing') sys.exit(2) filemode = True devicelist = [] for nwrecord in nwlist: # get devices' list devicelist = getdevicelist(arg_apikey, shardurl, nwrecord['id']) # append list to file or stdout if filemode: for i in range(0, len(devicelist)): if 'beaconIdParams' in devicelist[i]: try: # MODIFY THE LINE BELOW TO CHANGE OUTPUT FORMAT f.write('%s,%d,%d,%s,%s,%d,%d\n' % (devicelist[i]['beaconIdParams']['uuid'], devicelist[i]['beaconIdParams']['major'], devicelist[i]['beaconIdParams']['minor'], devicelist[i]['name'], devicelist[i]['address'], devicelist[i]['lat'], devicelist[i]['lng'])) except: printusertext('ERROR: Unable to write device info to file') sys.exit(2) else: for i in range(0, len(devicelist)): if 'beaconIdParams' in devicelist[i]: # MODIFY THE LINE BELOW TO CHANGE OUTPUT FORMAT print('%s,%d,%d,%s,%s,%d,%d' % (devicelist[i]['beaconIdParams']['uuid'], devicelist[i]['beaconIdParams']['major'], devicelist[i]['beaconIdParams']['minor'], devicelist[i]['name'], devicelist[i]['address'], devicelist[i]['lat'], devicelist[i]['lng'])) if __name__ == '__main__': main(sys.argv[1:])