Gather all Clients across an organization in Python

Solved
Scriptguru1701
Conversationalist

Gather all Clients across an organization in Python

I should preface this with the fact that I am new to both Python (not coding, I know PowerShell enough to get by), and the Meraki API.  I have also tried using Postman, but to no great effect to the same thing.

 

I'm having some issues trying to gather up a list of all our clients that are connected to our network over the past 30 days.  I have been trying to get this: https://community.meraki.com/t5/Dashboard-Administration/Meraki-Dashboard-Reporting-How-can-I-get-a-... code to work (between "Begin Code" and "End Code" in that post), however I keep running into some Python errors, the latest one that gets the most info yet is this:MAC Error.PNG

The odd part is, it gets through most of the organization before this becomes an issue, we have roughly 140 networks to iterate through and I don't even know where to begin trouble shooting this. 

 

If there is another easier way, maybe through PowerShell I am all ears.

1 Accepted Solution
BrechtSchamp
Kind of a big deal

I gave it a test and for me the error pops up if the script is trying to get the clients of an MV camera. That call spits out an error because MV's have no clients of course.

 

I edited the script a bit to ignore those cases. It goes as follows:

 

 

# Import "meraki" to allow Meraki function calls
import meraki

# Import "datetime" to get current date and time
import datetime

# ///////// Start Definition of Script Constants ////////////////
# api_key = Unique API key generated on a per Meraki User basis
# org_id = Unique organization ID of organization you want to query

api_key = '#################'
org_id = '#############'


# Get the current list of networks from your Organization
current_networks = meraki.getnetworklist(api_key, org_id)


# Establish when "now" is, used to create the file name for output
now = datetime.datetime.now()

# Create/Name the output file with year, month, day and hour minutes
filename = now.strftime("%Y-%m-%d %H.%M") + ".txt"

# Open the file for output
f = open(filename,"w+")

# "i" will be used to increment through each "network" in the Organization
i = 0

for i in range(len(current_networks)):

    # Output to console the Name and ID of the current network
    print("Network Name:" + current_networks[i]['name'])
    print("Network ID:" + current_networks[i]['id'])

    curr_net_id = current_networks[i]['id']
    curr_net_devices = meraki.getnetworkdevices(api_key,curr_net_id)

    # Write to the output file the 'name' of the network and add a comma
    f.write(current_networks[i]['name'])
    f.write(",")

    # Checks for Meraki devices on this network, if there are no devices output to file "No Devices Present"
    if len(curr_net_devices) == 0:
        f.write("No devices Present")
        f.write("\n")

    # "j" will be used to increment through each "device" on this network
    j = 0

    for j in range(len(curr_net_devices)):
        # Output to console the serial number of the device
        print ("Device Serial:" +curr_net_devices[j]['serial'])
        curr_clients = meraki.getclients(api_key,curr_net_devices[j]['serial'])


        # Checks for clients attached to this device, if no clients present output the name, model and serial of the
        # device as well as the message "No Clients". Also catch the error that comes up in case this is a device for
        # which clients are not relevant, e.g. MV camera's.
        if len(curr_clients) == 0 or curr_clients[0] == "Invalid device type":
            # Output to console "No Clients" message
            print ("No clients")

            # Output to file "name", "model", "serial" of the device as well as "No Clients" message
            f.write(current_networks[i]['name'])
            f.write(',')
            f.write(curr_net_devices[j]['model'])
            f.write(',')
            f.write(curr_net_devices[j]['serial'])
            f.write(",")
            f.write("No Clients")
            f.write("\n")

        # Only list the clients if there are any.
        else:
            # "k" will be used to increment the number of clients on each device
            k = 0

            for k in range(len(curr_clients)):
                # Output to console "description" and "mac" of the client
                print (curr_clients[k]['description'],',',curr_clients[k]['mac'])

                # Output to file "name", "model", "serial" of the device as well as the "description" and "mac"
                # of the client
                f.write(current_networks[i]['name'])
                f.write(',')
                f.write(curr_net_devices[j]['model'])
                f.write(',')
                f.write(str(curr_net_devices[j]['name']))
                f.write(',')
                f.write(curr_net_devices[j]['serial'])
                f.write(',')
                f.write(str(curr_clients[k]['description']))
                f.write(',')
                f.write(curr_clients[k]['mac'])
                f.write("\n")

                # Increment "k" to move onto next client on current device
                k = k + 1

        # Increment "j" to move onto next device on current Network
        j = j + 1
    # Increment "i" to move onto next network in Organization
    i = i + 1

# Close the output file
f.close()

 

 

 

Note that I'm also using a newer version of the library which makes that for me import meraki is enough.

 

Hope that helps. I'll also post back in the other topic.

View solution in original post

10 Replies 10
BrechtSchamp
Kind of a big deal

I gave it a test and for me the error pops up if the script is trying to get the clients of an MV camera. That call spits out an error because MV's have no clients of course.

 

I edited the script a bit to ignore those cases. It goes as follows:

 

 

# Import "meraki" to allow Meraki function calls
import meraki

# Import "datetime" to get current date and time
import datetime

# ///////// Start Definition of Script Constants ////////////////
# api_key = Unique API key generated on a per Meraki User basis
# org_id = Unique organization ID of organization you want to query

api_key = '#################'
org_id = '#############'


# Get the current list of networks from your Organization
current_networks = meraki.getnetworklist(api_key, org_id)


# Establish when "now" is, used to create the file name for output
now = datetime.datetime.now()

# Create/Name the output file with year, month, day and hour minutes
filename = now.strftime("%Y-%m-%d %H.%M") + ".txt"

# Open the file for output
f = open(filename,"w+")

# "i" will be used to increment through each "network" in the Organization
i = 0

for i in range(len(current_networks)):

    # Output to console the Name and ID of the current network
    print("Network Name:" + current_networks[i]['name'])
    print("Network ID:" + current_networks[i]['id'])

    curr_net_id = current_networks[i]['id']
    curr_net_devices = meraki.getnetworkdevices(api_key,curr_net_id)

    # Write to the output file the 'name' of the network and add a comma
    f.write(current_networks[i]['name'])
    f.write(",")

    # Checks for Meraki devices on this network, if there are no devices output to file "No Devices Present"
    if len(curr_net_devices) == 0:
        f.write("No devices Present")
        f.write("\n")

    # "j" will be used to increment through each "device" on this network
    j = 0

    for j in range(len(curr_net_devices)):
        # Output to console the serial number of the device
        print ("Device Serial:" +curr_net_devices[j]['serial'])
        curr_clients = meraki.getclients(api_key,curr_net_devices[j]['serial'])


        # Checks for clients attached to this device, if no clients present output the name, model and serial of the
        # device as well as the message "No Clients". Also catch the error that comes up in case this is a device for
        # which clients are not relevant, e.g. MV camera's.
        if len(curr_clients) == 0 or curr_clients[0] == "Invalid device type":
            # Output to console "No Clients" message
            print ("No clients")

            # Output to file "name", "model", "serial" of the device as well as "No Clients" message
            f.write(current_networks[i]['name'])
            f.write(',')
            f.write(curr_net_devices[j]['model'])
            f.write(',')
            f.write(curr_net_devices[j]['serial'])
            f.write(",")
            f.write("No Clients")
            f.write("\n")

        # Only list the clients if there are any.
        else:
            # "k" will be used to increment the number of clients on each device
            k = 0

            for k in range(len(curr_clients)):
                # Output to console "description" and "mac" of the client
                print (curr_clients[k]['description'],',',curr_clients[k]['mac'])

                # Output to file "name", "model", "serial" of the device as well as the "description" and "mac"
                # of the client
                f.write(current_networks[i]['name'])
                f.write(',')
                f.write(curr_net_devices[j]['model'])
                f.write(',')
                f.write(str(curr_net_devices[j]['name']))
                f.write(',')
                f.write(curr_net_devices[j]['serial'])
                f.write(',')
                f.write(str(curr_clients[k]['description']))
                f.write(',')
                f.write(curr_clients[k]['mac'])
                f.write("\n")

                # Increment "k" to move onto next client on current device
                k = k + 1

        # Increment "j" to move onto next device on current Network
        j = j + 1
    # Increment "i" to move onto next network in Organization
    i = i + 1

# Close the output file
f.close()

 

 

 

Note that I'm also using a newer version of the library which makes that for me import meraki is enough.

 

Hope that helps. I'll also post back in the other topic.

Scriptguru1701
Conversationalist

@BrechtSchampThank you for the assistance.  I just attempted to run the script and or some reason at line #90-91

 

 

f.write(str(curr_net_devices[j]['name']))
f.write(',')

 

I get this error, after it got though a handful of our networks.  My best guess is that we have a device that isn't named properly.ERROR 1 - Meraki API Gather Clients V2.PNG

 

 

 
NOTE:
 
 
 
 
 
 
 
 
 
 
 
When I comment out these two lines it continued and completed without any further issues.
MarkB2
Here to help

This works great! Wondering if there is an easy way to include the client IP address in the output?

 

Guessing I would need to add something to this section?

                # Output to file "name", "model", "serial" of the device as well as the "description" and "mac"
# of the client
f.write(current_networks[i]['name'])
f.write(',')
f.write(curr_net_devices[j]['model'])
f.write(',')
# f.write(str(curr_net_devices[j]['name']))
# f.write(',')
f.write(curr_net_devices[j]['serial'])
f.write(',')
f.write(str(curr_clients[k]['description']))
f.write(',')
f.write(curr_clients[k]['mac'])
f.write("\n")

 

BrechtSchamp
Kind of a big deal

Yeah. Just replace this:

f.write(",")

 

With this at the bottom:

f.write(",")
f.write(curr_clients[k]['ip'])
f.write("\n")

Let me know if that doesn't work. 

MarkB2
Here to help

works for clients with IP, but I get a traceback when it encounters a client with no IP:

 

Traceback (most recent call last):
File "ClientsInOrg.py", line 98, in <module>
f.write(curr_clients[k]['ip'])
TypeError: write() argument must be str, not None

BrechtSchamp
Kind of a big deal

All right, just cast it to string and you should be fine:

f.write(str(curr_clients[k]['ip']))

Rusalka
Here to help

@BrechtSchamp 

 

I really could you user assistance since I am new to this (Postman/python).  I saw in another post of yours where you mentioned the "status" field.  I tried adding it to the python script my Rep send me a link to on github but I get an error 08: unable to write file.

 

Let me backup and tell you what our needs are.  We need to find out how many concurrent wireless users are online so we can know how to scale a new Cisco ISE deployment and order the correct license count.

 

I don't care if I can get the info from Postman or running a python script, I just need a way of determining how many users are on wireless.

 

Oh, and to give you an idea of our size, we have two Orgs and over 250 Networks.

BrechtSchamp
Kind of a big deal

@Rusalka Have you tried running above script? It outputs more than you need, but when you open the generated .txt file in Excel you should be able to filter out the columns that have "MR" in the third column. That'll give you the number of wireless clients (at that point in time!).

Rusalka
Here to help

@BrechtSchamp no, I have been running the script from the other discussion. It didn't look like the above script included 'vlan'.  We have multiple SSIDs and just need to filter on the employee vlan.  Can vlan and status be included in the script above? and if so, whats the wording?

BrechtSchamp
Kind of a big deal

Yes you can include the VLAN.

 

Just change this:

                f.write(curr_clients[k]['mac'])
                f.write("\n")

 

To this:

                f.write(curr_clients[k]['mac'])
                f.write(',')
                f.write(str(curr_clients[k]['vlan']))
                f.write("\n")

 

Get notified when there are additional replies to this discussion.