I wrote this a while ago.
#!/usr/bin/env python3
#
# meraki-list-whitelist-clients lists all the clients that have been "whitelist"
# (now called "allow list").
#
# Installation:
# meraki-list-whitelist-clients uses dotenv to safely store your credentials. Create a file
# called .meraki.env in your home directory. For Linux this is typically /home/username. For
# Windows this is typically
# c:\users\<username>.
# Into .meraki.env put this line:
# MERAKI_DASHBOARD_API_KEY=<your API key>
# If you don't have an API key yet then follow the instructions on this page:
# https://documentation.meraki.com/zGeneral_Administration/Other_Topics/The_Cisco_Meraki_Dashboard_API
#
# Prior to running this script you'll need Python 3.x installed and you'll need to run the below
# commands to install the extra components required.
# pip3 install -U meraki
# pip3 install -U python-dotenv
# pip3 install -U throttler
#
# If you are using the script on Linux I would suggest marking it executable to make running
# it simpler.
# chmod +x mfw.py
#
# Usage:
# meraki-list-whitelist-clients.py -o "Your org name"
#
# History:
# When: Who: What:
# 19/05/2023 PID Completed original.
import os,argparse,asyncio,meraki.aio,throttler
# Load global and local Meraki settings such as MERAKI_DASHBOARD_API_KEY
from dotenv import load_dotenv
load_dotenv()
load_dotenv(dotenv_path=os.path.join(os.path.expanduser("~"),".meraki.env"))
# This function retrieves the netId
def getNetId(orgName,netName):
orgId=None
netId=None
# Search for the org
for org in dashboard.organizations.getOrganizations():
if org['name'] == orgName:
orgId=org['id']
break;
if orgId == None:
print("Invalid organization name supplied: "+orgName)
exit(-1)
# Search for the network
for net in dashboard.organizations.getOrganizationNetworks(orgId):
if net['name'] == netName:
netId=net['id']
break;
# If no network, search for a template
if netId == None:
for net in dashboard.organizations.getOrganizationConfigTemplates(orgId):
if net['name'] == netName:
netId=net['id']
break;
# Nothing found matching at all
if netId == None:
print("Invalid network name supplied: "+netName)
exit(-1)
return netId
# Check the policies for a client
async def checkPolicy(dashboard,netId,client):
policies=await dashboard.networks.getNetworkClientPolicy(netId,client['id'])
if policies['devicePolicy'] == 'Whitelisted':
print(f"{client['mac']},{client['ip']},{client['description']}")
elif policies['devicePolicy'] == 'Different policies by SSID':
print(f"{client['mac']},{client['ip']},{client['description']},{policies['ssids']}")
# Search the org for potential whitelisted clients
async def searchOrg(dashboard,orgName):
orgId=None
netId=None
# Search for the org
for org in await dashboard.organizations.getOrganizations():
if org['name'] == orgName:
orgId=org['id']
break;
if orgId == None:
print("Invalid organization name supplied: "+orgName)
exit(-1)
# Loop through all the networks
for net in await dashboard.organizations.getOrganizationNetworks(orgId):
print(f"Processing {net['name']}")
if 'systemsManager' in net['productTypes']:
print(' * Skipping - systems manager')
continue
clientTasks = [checkPolicy(dashboard,net['id'],client) for client in await dashboard.networks.getNetworkClients(net['id'],total_pages='all',perPage=500,timespan=30*86400)]
for task in asyncio.as_completed(clientTasks):
await task
async def main():
# Meraki parameters
orgName=None
text="""
meraki-list-whitelist-clients.py ...
In your home diretory you should have a .meraki.env file containing MERAKI_DASHBOARD_API_KEY=<your API key>
"""
parser = argparse.ArgumentParser(description = text)
parser.add_argument("-o", "--orgName", help="Meraki org name")
args=parser.parse_args()
orgName=os.getenv("orgName")
if args.orgName: orgName=args.orgName
if not os.getenv("MERAKI_DASHBOARD_API_KEY"):
print("MERAKI_DASHBOARD_API_KEY must be defined in .meraki.env in your home directory or in .env in the current directory")
exit(-1)
if not orgName:
print("orgName must be defined on the command line, in .meraki.env in your home directory or in .env in the current directory")
exit(-1)
async with meraki.aio.AsyncDashboardAPI(
output_log=False,
print_console=False,
maximum_retries=100,
wait_on_rate_limit=True
) as dashboard:
dashboard._session._concurrent_requests_semaphore = throttler.Throttler(rate_limit=4, period=1.0)
await searchOrg(dashboard,orgName)
if __name__ == "__main__":
asyncio.run(main())