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 CSVDemo;
>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()