This tool exports every hardware asset from an Cisco device with a serial number. You can export the list as table or CSV.
Download: https://gist.github.com/lanbugs/4dbed5e0e8a7d5b6d29c4ea9b9e93bb2
>python cisco_inventory.py -h usage: cisco_inventory.py [-h] -H HOST -v SNMP_VERSION [-C SNMP_COMMUNITY] [-u SNMP_USER] [-A SNMP_AUTH] [-a SNMP_AUTH_METHOD] [-X SNMP_PRIVACY] [-x SNMP_PRIVACY_METHOD] [-L SNMP_SECURITY] [--csv] Cisco inventory grabber Version 0.1 Written by Maximilian Thoma 2018 optional arguments: -h, --help show this help message and exit -H HOST WLC IP address -v SNMP_VERSION SNMP version, valid are 2 or 3 -C SNMP_COMMUNITY SNMP Community (only v2) -u SNMP_USER SNMP user (v3) -A SNMP_AUTH SNMP auth password (v3) -a SNMP_AUTH_METHOD SNMP auth method, valid are MD5 or SHA (v3) -X SNMP_PRIVACY SNMP privacy password (v3) -x SNMP_PRIVACY_METHOD SNMP privacy method, valid are AES or DES (v3) -L SNMP_SECURITY SNMP security level, valid are no_auth_or_privacy, auth_without_privacy or auth_with_privacy (v3) --csv Result should be CSV
Demo;
>python cisco_inventory.py -H 10.10.10.33 -v 3 -u snmpuser -A snmpauth -a MD5 -X snmpencr -x DES -L auth_with_privacy | Description | Class | Name | HWRev | FWRev | SWRev | Serial | Manufactor | Model | FRU? | |--------------------------------------------------------+-------------+----------------------------------------+---------+-------------+------------+------------------+---------------------+----------------+--------| | 1000BaseSX | - | GigabitEthernet1/4/12 | V01 | | | FNS11111111 | CISCO | GLC-SX-MMD | true | | 1000BaseSX | - | GigabitEthernet1/4/11 | V01 | | | FNS11111111 | CISCO | GLC-SX-MMD | true | | 1000BaseSX | - | GigabitEthernet1/4/10 | V01 | | | FNS11111111 | CISCO | GLC-SX-MMD | true | | 1000BaseSX | - | GigabitEthernet1/4/11 | V01 | | | FNS11111111 | CISCO | GLC-SX-MMD | true | | 1000BaseSX | - | GigabitEthernet1/3/8 | V01 | | | FNS11111111 | CISCO | GLC-SX-MMD | true | | 1000BaseSX | - | GigabitEthernet1/3/9 | V01 | | | FNS11111111 | CISCO | GLC-SX-MMD | true | | 1000BaseSX | - | GigabitEthernet1/3/6 | V01 | | | FNS11111111 | CISCO | GLC-SX-MMD | true | | 1000BaseSX | - | GigabitEthernet1/3/7 | V01 | | | FNS11111111 | CISCO | GLC-SX-MMD | true | | 1000BaseSX | - | GigabitEthernet2/3/10 | V01 | | | FNS11111111 | CISCO | GLC-SX-MMD | true | | 1000BaseX (SFP) with 12 SFP Ports Jumbo Frame Support | module | Switch1 Linecard 4 (virtual slot 4) | V02 | | | FNS11111111 | Cisco | WS-X4612-SFP-E | true | | 1000BaseX (SFP) with 12 SFP Ports Jumbo Frame Support | module | Switch1 Linecard 3 (virtual slot 3) | V02 | | | FNS11111111 | Cisco | WS-X4612-SFP-E | true | | Cisco Systems, Inc. WS-C4506-E 6 slot switch | chassis | Switch1 System | V03 | | | FNS11111111 | Cisco | WS-C4506-E | false | | FanTray | fan | Switch2 FanTray 1 | V04 | | | FNS11111111 | Cisco | WS-X4596-E | true | | Power Supply ( AC 1400W ) | powerSupply | Switch2 Power Supply 1 | V04 | | | FNS11111111 | Cisco Systems, Inc. | PWR-C45-1400AC | true | | Power Supply ( AC 1400W ) | powerSupply | Switch2 Power Supply 2 | V04 | | | FNS11111111 | Cisco Systems, Inc. | PWR-C45-1400AC | true | | SFP-10Gbase-SR | - | TenGigabitEthernet1/1/1 | V03 | | | FNS11111111 | CISCO-FINISAR | SFP-10G-SR | true | | SFP-10Gbase-SR | - | TenGigabitEthernet1/1/2 | V03 | | | FNS11111111 | CISCO-FINISAR | SFP-10G-SR | true | | Sup 7L-E 10GE (SFP+), 1000BaseX (SFP) with 4 SFP Ports | module | Switch1 Supervisor 1 (virtual slot 1) | V01 | 15.0(1r)SG3 | 03.06.03.E | FNS11111111 | Cisco | WS-X45-SUP7L-E | true |
Script:
#!/usr/bin/env python # Need following pip packages # - easysnmp # - tabulate # Checkout blog article to tool # https://lanbugs.de/netzwerktechnik/hersteller/cisco/commandline-tool-for-exporting-cisco-hardware-inventory-via-snmp/ from easysnmp import Session import argparse from tabulate import tabulate from operator import itemgetter from pprint import pprint def main(): #### # ARGS #### description = """ Cisco inventory grabber\nVersion 0.1\nWritten by Maximilian Thoma 2018 """ aparser = argparse.ArgumentParser(description=description) aparser.add_argument('-H', dest='host', help='WLC IP address', required=True) aparser.add_argument('-v', dest='snmp_version', help='SNMP version, valid are 2 or 3', required=True) aparser.add_argument('-C', dest='snmp_community', help='SNMP Community (only v2)') aparser.add_argument('-u', dest='snmp_user', help='SNMP user (v3)') aparser.add_argument('-A', dest='snmp_auth', help='SNMP auth password (v3)') aparser.add_argument('-a', dest='snmp_auth_method', help='SNMP auth method, valid are MD5 or SHA (v3)') aparser.add_argument('-X', dest='snmp_privacy', help='SNMP privacy password (v3)') aparser.add_argument('-x', dest='snmp_privacy_method', help='SNMP privacy method, valid are AES or DES (v3)') aparser.add_argument('-L', dest='snmp_security', help='SNMP security level, valid are no_auth_or_privacy, auth_without_privacy or auth_with_privacy (v3)') aparser.add_argument('--csv', dest='csv', help='Result should be CSV', action='store_true') args = aparser.parse_args() #### # Setup SNMP connection #### if args.snmp_version == "2": try: snmp = Session(hostname=args.host, version=2, use_numeric=True) except Exception as e: print e if args.snmp_version == "3": try: snmp = Session( hostname=args.host, version=3, security_level=args.snmp_security, security_username=args.snmp_user, auth_protocol=args.snmp_auth_method, auth_password=args.snmp_auth, privacy_protocol=args.snmp_privacy_method, privacy_password=args.snmp_privacy, use_numeric=True ) except Exception as e: print e #### # Init Data Buffer #### inventory = {} inv_print = [] #### # SNMP Walk inventory #### port = { 0: "-", 1: "other", 2: "unknown", 3: "chassis", 4: "backplane", 5: "container", 6: "powerSupply", 7: "fan", 8: "sensor", 9: "module", 10: "port", 11: "stack", 12: "cpu" } ## Get inventory result_ids = snmp.walk(".1.3.6.1.2.1.47.1.1.1.1") def stripper(string): if "NoneType" not in str(type(string)): return string.strip() else: return string for r in result_ids: if r.oid_index in inventory: element_id = r.oid.replace(".1.3.6.1.2.1.47.1.1.1.1.","") if element_id == "16": # fru fru = "true" if "1" in r.value else "false" inventory[r.oid_index][element_id] = fru elif element_id == "5": # class classx = port[int(r.value)] if len(r.value) is 1 else port[0] inventory[r.oid_index][element_id] = classx else: # everything else inventory[r.oid_index][element_id] = r.value else: element_id = r.oid.replace(".1.3.6.1.2.1.47.1.1.1.1.","") inventory[r.oid_index] = {} inventory[r.oid_index][element_id] = r.value for elements, values in inventory.iteritems(): if len(values['11']) >= 1: #print elements #2 entPhysicalDescr #3 entPhysicalVendorType #4 entPhysicalContainedIn #5 entPhysicalClass #6 entPhysicalParentRelPos #7 entPhysicalName #8 entPhysicalHardwareRev #9 entPhysicalFirmwareRev #10 entPhysicalSoftwareRev #11 entPhysicalSerialNum #12 entPhysicalMfgName #13 entPhysicalModelName #14 entPhysicalAlias #15 entPhysicalAssetID #16 entPhysicalIsFRU inv_print.append([stripper(values.get('2')), stripper(values.get('5')), stripper(values.get('7')), stripper(values.get('8')), stripper(values.get('9')), stripper(values.get('10')), stripper(values.get('11')), stripper(values.get('12')), stripper(values.get('13')), stripper(values.get('16'))]) #### # Sort table #### inv = sorted(inv_print, key=itemgetter(0)) #### # Result #### if args.csv is True: print 'Description;Class;Name;HWRev;FWRev;SWRev;Serial;Manufactor;Model;FRU?' for line in inv: print ';'.join(str(l) for l in line) else: print tabulate(inv, headers=['Description', 'Class', 'Name', 'HWRev', 'FWRev', 'SWRev', 'Serial', 'Manufactor', 'Model', 'FRU?'], tablefmt="orgtbl") if __name__ == "__main__": main()