Organization/Network/... ID Finder - Helper Script

Greenberet
Head in the Cloud

Organization/Network/... ID Finder - Helper Script

Hello,

 

I guess many of you have a similiar problem as me:

My scripts are often targeting a specific organization/network. The problem here is, that you first have to fine out what the id really is. My previous approach was often like this: Either I've used the developer.cisco.com feature to run the endpoints (e.g. getOrganizations) in the browser or you are just printing every value in the script to get the correct one.

 

To solve that I wrote a script which will print every name/description of an organization, network, device, client or bluetooth client based on a given input pattern powered by regular expressions.

 

 

 

 

usage: id_finder.py [-h] -p PATTERN [-s OPTIONS]
                    [-o ORGANIZATION [ORGANIZATION ...]]
                    [-n NETWORKS [NETWORKS ...]]

This scripts helps to find the id of an organization, network, device or
(bluetooth) client

optional arguments:
  -h, --help            show this help message and exit
  -p PATTERN, --pattern PATTERN
                        the regular expression to search for (default: None)
  -s OPTIONS, --search_options OPTIONS
                        specifies which objects should be looked up:
                        o=organizations, n=networks, d=devices, c=clients,
                        b=bluetooth clients (default: ond)
  -o ORGANIZATION [ORGANIZATION ...], --organization ORGANIZATION [ORGANIZATION ...]
                        The name/id of the organizations under which you want
                        to limit the search. This makes the o option of -s
                        obsolete. (default: None)
  -n NETWORKS [NETWORKS ...], --network NETWORKS [NETWORKS ...]
                        the name/id of the networks under which you want to
                        limit the search. This makes the n option of -s
                        obsolete. (default: None)      

 

 

 

 

By default it will only search in the organization-, network- or device name. To match also clients/bluetooth clients you have to specify the -s parameter

 

example output running id_finder.py -p .* -o Home -s ondcb

Greenberet_0-1606257599893.png

 

Critics and comments are welcome 😃

19 REPLIES 19
PhilipDAth
Kind of a big deal
Kind of a big deal

I tend to use code like the below to allow the org name to be a command-line parameter.

 

	# Search for the org
	orgs = meraki.organizations.get_organizations()
	for org in orgs:
		if org['name'] == orgName:
			orgId=org['id']
			break;

	if orgId == None:
		print("Invalid organization name supplied: "+orgName)			
		exit(-1)

yeah I had similiar scripts (but mostly I've changed the name directly in the code). Especially for networks and co. That's why I've created the script above =D

Oops, I should have looked at who the poster was.  @Greenberet is an expert software developer.  I can highly recommend the code and answers by @Greenberet .

Fabian1
Getting noticed

This is exactly what I was looking for. I will call this script with another to get the IDs, but I have to change the output a little.

Thanks a lot, great work!

"Change the output a little". What exactly do you want to change here?

The result is already a functional dictionary per organization. I could add a --json parameter, if you need something like that.

I'll put in some return statements, because I don't need print outputs. So when I call the script, the only thing I need is; give me the ID or tell me the network/organization etc doesn't exist and give it back to my other script that will so things like adding devices or what ever. 

Or I'll put your script in a class and call the methods there, not sure at the moment. 

sambo
Getting noticed

Hi,

This is looking like exactly what i'm looking for.

Sadly it didn't work and I'm sure I did something pretty silly:

 

Sam.Wharton@ISN-LT-SW MINGW64 ~/code/meraki-code/meraki-python-sdk/meraki_scripts-master/v1/id_finder (master)
$ python id_finder.py -o API Demo - Meraki -p.* -s ondcb
Searching for pattern .*
Script complete!
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x0000023C93913670>
Traceback (most recent call last):
File "C:\Users\Sam.Wharton\AppData\Local\Programs\Python\Python39\lib\asyncio\proactor_events.py", line 116, in __del__
self.close()
File "C:\Users\Sam.Wharton\AppData\Local\Programs\Python\Python39\lib\asyncio\proactor_events.py", line 108, in close
self._loop.call_soon(self._call_connection_lost, None)
File "C:\Users\Sam.Wharton\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 746, in call_soon
self._check_closed()
File "C:\Users\Sam.Wharton\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 510, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

Sam.Wharton@xx MINGW64 ~/code/meraki-code/meraki-python-sdk/meraki_scripts-master/v1/id_finder (master)
$ ls
id_finder.py id_finder_log__2021-03-08_16-37-04.log requirements.txt

Sam.Wharton@ISN-LT-SW MINGW64 ~/code/meraki-code/meraki-python-sdk/meraki_scripts-master/v1/id_finder (master)
$ more id_finder_log__2021-03-08_16-37-04.log
bash: more: command not found

Sam.Wharton@ISN-LT-SW MINGW64 ~/code/meraki-code/meraki-python-sdk/meraki_scripts-master/v1/id_finder (master)
$ cat id_finder_log__2021-03-08_16-37-04.log
2021-03-08 16:37:04 meraki.aio: INFO > Meraki dashboard API session initialized with these parameters: {'version': '1.6.2', 'api_key': '************************************0db3', 'base_url': 'https://api.meraki.com/api/v1', 'single_request_timeout': 60, 'certificate_path': '', 'requests_proxy': '', 'wait_on_rate_limit': True, 'nginx_429_retry_wait_time': 60, 'action_batch_retry_wait_time': 60, 'retry_4xx_error': False, 'retry_4xx_error_wait_time': 60, 'maximum_retries': 5, 'simulate': False, 'maximum_concurrent_requests': 3, 'be_geo_id': None, 'caller': None}
2021-03-08 16:37:04 meraki.aio: DEBUG > {'tags': ['organizations', 'configure'], 'operation': 'getOrganizations', 'method': 'GET', 'url': '/organizations', 'params': None}
2021-03-08 16:37:04 meraki.aio: INFO > GET https://api.meraki.com/api/v1/organizations
2021-03-08 16:37:06 meraki.aio: INFO > organizations, getOrganizations > https://api.meraki.com/api/v1/organizations - 200 OK

 

 

Greenberet
Head in the Cloud

please try python id_finder.py -o "API Demo" - Meraki -p.* -s ondcb

This worked...

PS C:\Users\Sam.xx\code\meraki-code\meraki-python-sdk\meraki_scripts-master\v1\id_finder> python id_finder.py -o "API Demo - Meraki" -p.* -s ondcb
Searching for pattern .*
Organization "API Demo - Meraki" - 634444597505820956
Network "API demo - Sam1" - L_634444597505841288

 

But when I tried with 2 of my 'real' orgs it fails....

Logs show too many requests...

 

2021-03-09 09:33:22 meraki.aio: WARNING > networks, getNetworkClients > https://n57.meraki.com/api/v1/networks/L_xxxxx/clients?perPage=10&startingAfter=k96a54c - 429 Too Many Requests, retrying in 1 seconds

 

So I ran it with just the -on flags and it works a treat!

Thanks

Sam

 

Greenberet
Head in the Cloud

the -o Parameter has to match the organization name exactly for the script to work.

 

you can ignore the 429 warning. The script will create many api call depending on the size of your organization. You just have to be patient for the script to finish.

 

about the exception you are getting at the end: You can ignore them for now. What I've found is that there is an error in one of the dependend libraries.

sambo
Getting noticed

A question.....

This script works well. When I call 'all orgs' with this:

python id_finder.py -p.* -s on

It fails if an ORG does not have API access enabled.

I have 11 orgs available and once it hits one without API access it fails, so I have to run to each org on its own.

I know there will be an easy way to ignore this:

2021-03-09 10:16:57 meraki.aio: ERROR > organizations, getOrganizationNetworks > https://api.meraki.com/api/v1/organizations/595038100766328126/networks - 404 Not Found, {'errors': ['To make requests you must first enable API access via https://n248.meraki.com/o/yvY7Mb5/manage/organization/edit']}

 

Be great to know what this is!

Thanks

Sam

Greenberet
Head in the Cloud

actually there are 2 problems with the disabled api.

 

1) the script didn't handle it correctly. I've fixed that now in the repo

2) the meraki library mistreated the disabled api as a "missing api key" response from the cloud and created an additional exception while creating the Async/APIError object. I've created a PR for this. We just have to wait until it gets merged and published.

Thanks for that. Appreciated.

I downloaded the updated script but it still failed in the same way, I checked I had got the new file and a comparison shows this was added so I think it was ok.

 

Thanks

Sam

 

 

from meraki.exceptions import AsyncAPIError

 

$ cat id_finder_log__2021-03-09_15-56-03.log
2021-03-09 15:56:03 meraki.aio: INFO > Meraki dashboard API session initialized with these parameters: {'version': '1.6.2', 'api_key': '************************************0db3', 'base_url': 'https://api.meraki.com/api/v1', 'single_request_timeout': 60, 'certificate_path': '', 'requests_proxy': '', 'wait_on_rate_limit': True, 'nginx_429_retry_wait_time': 60, 'action_batch_retry_wait_time': 60, 'retry_4xx_error': False, 'retry_4xx_error_wait_time': 60, 'maximum_retries': 5, 'simulate': False, 'maximum_concurrent_requests': 3, 'be_geo_id': None, 'caller': None}
2021-03-09 15:56:03 meraki.aio: DEBUG > {'tags': ['organizations', 'configure'], 'operation': 'getOrganizations', 'method': 'GET', 'url': '/organizations', 'params': None}
2021-03-09 15:56:03 meraki.aio: INFO > GET https://api.meraki.com/api/v1/organizations
2021-03-09 15:56:03 meraki.aio: INFO > organizations, getOrganizations > https://api.meraki.com/api/v1/organizations - 200 OK
2021-03-09 15:56:03 meraki.aio: DEBUG > {'tags': ['organizations', 'configure', 'networks'], 'operation': 'getOrganizationNetworks', 'page': 1}
2021-03-09 15:56:03 meraki.aio: INFO > GET https://api.meraki.com/api/v1/organizations/349467/networks
2021-03-09 15:56:03 meraki.aio: DEBUG > {'tags': ['organizations', 'configure', 'networks'], 'operation': 'getOrganizationNetworks', 'page': 1}
2021-03-09 15:56:03 meraki.aio: INFO > GET https://api.meraki.com/api/v1/organizations/595038100766328178/networks
2021-03-09 15:56:03 meraki.aio: DEBUG > {'tags': ['organizations', 'configure', 'networks'], 'operation': 'getOrganizationNetworks', 'page': 1}
2021-03-09 15:56:03 meraki.aio: INFO > GET https://api.meraki.com/api/v1/organizations/702561541869797743/networks
2021-03-09 15:56:03 meraki.aio: INFO > organizations, getOrganizationNetworks; page 1 > https://api.meraki.com/api/v1/organizations/349467/networks - 200 OK
2021-03-09 15:56:03 meraki.aio: DEBUG > {'tags': ['organizations', 'configure', 'networks'], 'operation': 'getOrganizationNetworks', 'page': 1}
2021-03-09 15:56:03 meraki.aio: INFO > GET https://api.meraki.com/api/v1/organizations/639537/networks
2021-03-09 15:56:03 meraki.aio: ERROR > organizations, getOrganizationNetworks > https://api.meraki.com/api/v1/organizations/595038100766328178/networks - 403 Forbidden, {'errors': ["Meraki API services are available for licensed Meraki devices only. Please contact Meraki support. To renew your licenses, go to 'https://n248.meraki.com/o/Lu31Jb5/manage/dashboard/license_info'"]}
2021-03-09 15:56:03 meraki.aio: DEBUG > {'tags': ['organizations', 'configure', 'networks'], 'operation': 'getOrganizationNetworks', 'page': 1}
2021-03-09 15:56:03 meraki.aio: INFO > GET https://api.meraki.com/api/v1/organizations/851711/networks
2021-03-09 15:56:03 meraki.aio: INFO > organizations, getOrganizationNetworks; page 1 > https://api.meraki.com/api/v1/organizations/702561541869797743/networks - 200 OK
2021-03-09 15:56:03 meraki.aio: DEBUG > {'tags': ['organizations', 'configure', 'networks'], 'operation': 'getOrganizationNetworks', 'page': 1}
2021-03-09 15:56:03 meraki.aio: INFO > GET https://api.meraki.com/api/v1/organizations/999212/networks
2021-03-09 15:56:03 meraki.aio: ERROR > organizations, getOrganizationNetworks > https://api.meraki.com/api/v1/organizations/639537/networks - 404 Not Found, {'errors': ['To make requests you must first enable API access via https://n248.meraki.com/o/baCOaa/manage/organization/edit']}
2021-03-09 15:56:03 meraki.aio: DEBUG > {'tags': ['organizations', 'configure', 'networks'], 'operation': 'getOrganizationNetworks', 'page': 1}
2021-03-09 15:56:03 meraki.aio: INFO > GET https://api.meraki.com/api/v1/organizations/595038100766327444/networks

Greenberet
Head in the Cloud

that's the issue with point 2, as soon as this is merged and released it should work fine with the new meraki library.

The errors won't go away (in fact they will get printed in the cli), but the script itself should ignore them and continue with the other organizations.

 

I see.

No, the script stops still once it finds the API issue with point 1.

 

Sam.xx@xx MINGW64 ~/code/meraki-code/meraki-python-sdk/meraki_scripts/v1/id_finder (master)
$ python id_finder.py -p.* -s on
Searching for pattern .*
Organization "xx Limited" - 702561541869797743
Network "ISS-Coventry-Cheylesmore-House" - L_702561541869807028
Network "WEYBRIDGE_POC" - L_702561541869808468
Network "ISS Woking DC SD-WAN Hub" - N_702561541869820672
Network "ISS-Nottingham-City-Link-Post" - L_702561541869807513
Network "ISS-Newport-IPO" - N_702561541869817487
Network "ISS-Slough-O2" - N_702561541869829769
Network "ISS-London-Ernst-Young" - L_702561541869808111
Network "ISS-Nottingham-City-Link" - L_702561541869803884
Network "ISS-Cardiff-Company House" - L_702561541869803882
Network "ISS-Northampton-BEIS" - N_702561541869819561
Network "ISS-NHS-Nightingale-Excel" - N_702561541869835656
Network "ISS-Newcastle-College" - L_702561541869808115
Finished 1 of 11 Organizations
Organization "xx" - 349467
Network "SR_Wirless_New-World" - N_619244948763472398
Network "SR iPhone Estate" - N_619244948763443677
Network "SR WIRELESS MANCHESTER" - N_619244948763473226
Network "SR WIRELESS PARKWAY" - L_619244948763447412
Network "SR WIRELESS GLASGOW" - N_619244948763473227
Network "SR Laptops" - N_619244948763459542
Finished 2 of 11 Organizations
Organization "Allford Hall Monaghan Morris" - 851711
Network "Bristol" - N_662029145223494580
Network "White Collar Factory" - N_662029145223521854
Network "Oklahoma" - N_662029145223467509
Network "Morelands" - N_662029145223531675
Network "Hoddesdon" - N_662029145223468101
Finished 3 of 11 Organizations
There was an error while analyzing Clear Channel.
Message: {'errors': ["Meraki API services are available for licensed Meraki devices only. Please contact Meraki support. To renew your licenses, go to 'https://n248.meraki.com/o/Lu31Jb5/manage/dashboard/license_info'"]}
Finished 4 of 11 Organizations

 

Thanks again

Sam

sambo
Getting noticed

I'd really like to try and get this code to work so any help on the script errors would be appreciated:

PS C:\Users\Sam.xx\Meraki\meraki_scripts\v1\id_finder> python id_finder.py -p.* -s on
Searching for pattern .*
Organization "xxxx" - xxxx
Network "Tunbridge Wells 17" - L_595038100766331968
Network "Winchester 16" - L_595038100766332123
Network "Chichester 15" - L_595038100766332454
Network "Covent Garden 21 CCTV" - N_595038100766415284
Network "Guildford 09" - L_595038100766331970
Network "Bromley 01" - L_595038100766332124
Network "Bath 43" - L_595038100766332496
Network "Mondaine 39" - L_595038100766331981
Network "Brighton 13" - L_595038100766332125
Network "Glasgow 14" - L_595038100766332497
Network "Tottenham Court Road 42" - L_595038100766331983
Network "Harrogate 27" - L_595038100766332126
Network "Canterbury 37" - L_595038100766332504
Network "Mayfair 34" - L_595038100766331984
Network "Chelsea 35" - L_595038100766332236
Network "Birmingham 28" - L_595038100766332897
Network "Regent Street 32" - L_595038100766331985
Network "Brent Cross 08" - L_595038100766332237
Network "Feet Two 46" - L_595038100766332917
Network "Princes Street 22" - L_595038100766332122
Network "Brompton 40" - L_595038100766332239
Network "Kingston 23" - L_595038100766332918
Network "Oxford Circus 48" - L_595038100766331986
Network "Cambridge 10" - L_595038100766332240
Network "Salisbury 30" - L_595038100766332919
Network "Chester 07" - L_595038100766332440
Network "Southampton 33" - L_595038100766331505
Network "Stratford 26" - L_595038100766331987
Network "Covent Garden 21" - L_595038100766332242
Network "Richmond 05" - L_595038100766332920
Network "Test Site 55" - L_595038100766331656
Network "Manchester 25" - L_595038100766331988
Network "Exeter 20" - L_595038100766332243
Network "Marble Arch 45" - L_595038100766332921
Network "Bond Street 31" - L_595038100766331989
Network "High Street Kensington 12" - L_595038100766332244
Network "Oxford 38" - L_595038100766332922
Network "Press Office 80" - L_595038100766331990
Network "Jermyn 41" - L_595038100766332245
Network "Feet Four 49" - L_595038100766332923
Network "Trafford 24" - L_595038100766331991
Network "Newcastle 03" - L_595038100766332246
Network "Bromley_Head_Office" - L_595038100766335279
Network "Westfield 02" - L_595038100766332120
Network "Leeds 29" - L_595038100766332335
Network "Covent Garden 50" - L_595038100766347807
Network "Feet Three 47" - L_595038100766332121
Network "Bluewater 04" - L_595038100766332438
Network "System Manager" - N_595038100766375970
Network "Cheltenham 06" - L_595038100766331855
Finished 1 of 11 Organizations
Traceback (most recent call last):
File "C:\Users\Sam.xx\Meraki\meraki_scripts\v1\id_finder\id_finder.py", line 240, in <module>
asyncio.run(main())
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\runners.py", line 44, in run
return loop.run_until_complete(main)
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 642, in run_until_complete
return future.result()
File "C:\Users\Sam.xx\Meraki\meraki_scripts\v1\id_finder\id_finder.py", line 203, in main
result = await task
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\tasks.py", line 614, in _wait_for_one
return f.result() # May raise f.exception().
File "C:\Users\Sam.xx\Meraki\meraki_scripts\v1\id_finder\id_finder.py", line 91, in find_in_organization
networks = await aiomeraki.organizations.getOrganizationNetworks(
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\site-packages\meraki\aio\rest_session.py", line 242, in get_pages
async with await self.request(metadata, "GET", url, params=params) as response:
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\site-packages\meraki\aio\rest_session.py", line 94, in request
return await self._request(metadata, method, url, allow_redirects=False, **kwargs)
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\site-packages\meraki\aio\rest_session.py", line 223, in _request
raise AsyncAPIError(metadata, response, message)
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\site-packages\meraki\exceptions.py", line 42, in __init__
self.message += 'please wait a minute if the key or org was just newly created.'
TypeError: unsupported operand type(s) for +=: 'dict' and 'str'
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x00000293F922AE50>
Traceback (most recent call last):
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\proactor_events.py", line 116, in __del__
self.close()
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\proactor_events.py", line 108, in close
self._loop.call_soon(self._call_connection_lost, None)
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 746, in call_soon
self._check_closed()
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 510, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x00000293F922AE50>
Traceback (most recent call last):
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\proactor_events.py", line 116, in __del__
self.close()
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\proactor_events.py", line 108, in close
self._loop.call_soon(self._call_connection_lost, None)
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 746, in call_soon
self._check_closed()
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 510, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x00000293F922AE50>
Traceback (most recent call last):
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\proactor_events.py", line 116, in __del__
self.close()
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\proactor_events.py", line 108, in close
self._loop.call_soon(self._call_connection_lost, None)
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 746, in call_soon
self._check_closed()
File "C:\Users\Sam.xx\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 510, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
PS C:\Users\Sam.xx\Meraki\meraki_scripts\v1\id_finder>

PhilipDAth
Kind of a big deal
Kind of a big deal

>TypeError: unsupported operand type(s) for +=: 'dict' and 'str'

 

Take a look at line 42.

 

My guess is you don't have full org admin permission for an org you are trying to query.

Thats actually a bug in the meraki python library.

You can get it fixed by downloading the current source from github or just wait until the next library version will get released.

I just upgraded to version 1.7.1 and it does now work.

Thanks all.

Sam

Get notified when there are additional replies to this discussion.