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
Device,Name,Desc,PID,VID,Serial
switch2,"1","ME-C3750-24TE",ME-C3750-24TE-M,V05,CATXXXXXXXX
switch2,"GigabitEthernet1/0/1","1000BaseSX SFP",Unspecified,,AGMXXXXXXX
switch2,"GigabitEthernet1/0/2","1000BaseSX SFP",Unspecified,,FNSXXXXXXX

Output is in combined_audit.txt

BASH Script:

#!/bin/bash
# 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
EOF
}

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

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

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

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
             ;;
esac

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

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

fi

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
fi

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
done

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