Quick and Dirty Cisco Hardware Inventory to CSV

I wanted to quickly grab all part numbers and serial numbers of chassis, cards and modules in some Cisco kit but the standard output wasn’t really nice enough to work with very easily.

To this end I knocked up the following script that will give a nice fixed field or comma-separated output that can be dragged into an Excel spreadsheet. Useful for doing support renewals and the like.

This is the first version so it’s a bit rough with error checking and doesn’t like incorrect credentials so type carefully. Tested with a variety of Cisco switches and routers, including Nexus 5K. Requires expect/tcl/tk

If you have ancient hardware that only supports prehistoric ssh key exchange algorithms, this may fail under expect. Good luck fixing it :)

$ ./hwaudit -d switch1
Tacacs user:me
Tacacs pass:
Using command line specified hosts: switch1
Device        Name                  Desc                  PID                 VID      Serial
switch1     "1"                     "WS-C3560-24TS"       WS-C3560-24TS-E     V02      CAT0XXXXXXX
switch1     "GigabitEthernet0/1"    "1000BaseSX SFP"      Unspecified                  AGMXXXXXX3P

$ ./hwaudit -cd switch2
CSV Mode
Tacacs user:me
Tacacs pass:
Using command line specified hosts: switch1
switch2,"GigabitEthernet1/0/1","1000BaseSX SFP",Unspecified,,AGMXXXXXXX
switch2,"GigabitEthernet1/0/2","1000BaseSX SFP",Unspecified,,FNSXXXXXXX

Output is in combined_audit.txt

BASH Script:

# hwaudit v1.1
# Mark M (sol@subnetzero.org)
# Script to go and get part numbers/serial numbers
# from Cisco devices.
# To do: write additional methods for telnet_acs and telnet_pwonly
# Examples:
# ./hwaudit -cd device1    <- CSV delimited output for device1
# ./hwaudit -f list.txt    <- Fixed field output for all in list.txt
# Expect functions to log on to Cisco Devices
ssh_acs() {
/usr/bin/expect << EOF
set timeout $PROMPT_TIMEOUT
spawn ssh $USNAME@$DEVICE
expect {
        "continue connecting (yes/no)?" {send "yes\r" ; exp_continue}
        "assword:" { send "$PASS\r" }
expect -re "(>|#)" {send "term len 0\r"}
expect -re "(>|#)" {send "show inventory\r"}
expect -re "(>$|#$)" {send "exit\r\n"}
close $spawn_id

USAGE="$0 { -f filename } { -c = csv format } { -d devicename }"
FMT="%-13.13s %-32.32s %-38.38s %-22.22s %-8.8s %-12.12s\n"
cat /dev/null > combined_audit.txt

case $1 in
 [a-zA-Z0-9]*) echo "$USAGE\n"
               exit 1;;

optstring=cd:f: #tT
while getopts $optstring opt
   case $opt in
      c) echo "CSV Mode";FMT="%s,%s,%s,%s,%s,%s\n";CSV=1;;
      d) DEVICES=$OPTARG;;
      # t) METHOD=telnet_acs;;
      # T) METHOD=telnet_pwonly;;
      *) echo "$USAGE"

case $METHOD in
   ssh_acs)   printf "Tacacs user:" ; read USNAME; stty -echo
              printf "Tacacs pass:" ; read PASS ; printf "\n"; stty echo
   *)        printf "No connection method set\n"
             exit 1

if [ ! -r $INPUTFILE ]; then
   echo "Input file: $INPUTFILE not readable"
   exit 1

if [ -z "$DEVICES" ]; then
   DEVICES=$( grep -iv "^$|^#" "$INPUTFILE" )
   if [ -z "$DEVICES" ]; then
      echo "No list generated. $INPUTFILE"
      exit 1
else echo "Using command line specified hosts: $DEVICES"


if [ $(tput cols) -lt 128 ] && [ "$CSV" -eq "0" ]; then
   printf "\033[31;1mWARNING - \033[37mTerminal may not be wide enough for clean output in non-csv mode.\033[0m\n"
   sleep 2

for DEVICE in ${DEVICES[@]}; do
   $METHOD | tr -d '\r' > output.$DEVICE.tmp
   sed 's/  \+,/,/g' output.$DEVICE.tmp | \
   awk -F "," 'BEGIN {start=0;printf("'"$FMT"'","Device","Name","Desc","PID","VID","Serial")}
               /show inventory/ { start=1 }
               start==0 { next }
               start==1 && $1 ~ /^NAME:/ {name=substr($1,7)}
               start==1 && $2 ~ /DESCR:/ {desc=substr($2,9)}
               start==1 && $1 ~ /^PID:/  {pid=substr($1,6)}
               start==1 && $2 ~ /VID:/   {vid=substr($2,7)}
               start==1 && $3 ~ /SN:/    {ser=substr($3,6)}
               $1 ~ /^$/ {printf ("'"$FMT"'","'$DEVICE'",name,desc,pid,vid,ser)
               name=NULL;desc=NULL;pid=NULL;vid=NULL;ser=NULL} ' |\
               egrep -v ",,,,," | tee -a combined_audit.txt

echo "Output is in combined_audit.txt"
rm output.*.tmp


We were having odd LAN issues and noticed we a had a bunch of these logs regarding ports on a WS-X6904-40G card.

%CONST_DIAG-3-HM_PORT_TEST_FAIL: Module 2 TestUnusedPortLoopback Port(s)[12] failed. System operation continues.
%HA_EM-6-LOG: Mandatory.go_nondislp.tcl: GOLD EEM TCL policy for TestNonDisruptiveLoopback

The module showed there was a minor error – however all ports remained up. We did see that spanning tree interface details were flapping between “P2P” and “Dispute” for the first 8 interfaces. Shutting these ports and letting traffic flow via secondary links restored normal functionality until we could swap the card. So it seems that despite issues with the ports being detected, the system was not err-disabling them.

Given the issue was across two different 4 port modules I assume the issue was with whatever hardware was driving the first 8 ports. All MAC and ARP entries looked fine but obviously weren’t timing out given the issue was intermittent.

show module snippet:

Mod  Online Diag Status
---- -------------------
  1  Pass
  2  Minor Error
  3  Pass
  4  Pass