I had a task laid down before me the other day.

“I am thy Boss!  Thou shalt seeketh out and Query the Lan for all Cisco Phones!  Thou shalt telleth me the MacAddress and primary Extension of each phoneth so that we might know what each user useth!”

Ok, it wasn’t quite like THAT, but it was a task we needed to do.

Now before you go this far, if you HAVE access to a Cisco SME, there is a way to pull this DIRECTLY from the Call Manager.  But I found out about this afterwards.   So why spoil our fun? Smile

So if you didn’t know, every Cisco IP phone has a built in web page.    That page reports most of the useful information about your phone, including Port speed, MAC address, Serial Number, location on Switch….

Sounds like some useful information doesn’t it?

So my first challenge, get all the IP’s of our Cisco phones.    That was actually easy.   Unless they are configured to using a Static IP (Bleeeaaaaccchhh!!!) they’re probably sitting in your DHCP pool.   For me, since I use a Microsoft DHCP server I grabbed a Script from “The Admin Guy” for pulling DHCP Server data into an HTML report.   It’s a solution I love since it leverages a legacy system (NETSH) and uses Powershell to produce better output.

I tweaked his script initially to just dump the data and give me the Mac addresses.  It was a messy dump since I initially goofed up (Did I mention we had to pull this answer quickly?) but I had a list of IP addresses and hostnames to start with.

If you’re looking for the Cisco IP Phones in the DHCP pool, just seek the systems starting with SEP and the rest is usually the phone Mac address.

Now the fun part. digging through the web page in the phone.

For this task I had Powershell 3 to play with so I saved some time in fiddling with browsers by using the new INVOKE-WEBQUEST Cmdlet

$Phone=(INVOKE-WEBREQUEST ‘http://192.168.45.54/CGI/Java/Serviceability?adapter=device.statistics.device’

Now I had something to play with.   Since I don’t play with HTML much, I tried examining the “RawContent” property to see if it had what I was looking for.  In my first attempt I was querying the Webpage on the phone which displayed the MAC Address.   It actually displays the word “MAC Address” on the display so I figured I would have a shot of it displaying the data in some reasonable pattern…. hopefully.

To do this initially I dumped the data to a file and cheated using “Notepad.exe” to see if the data was there.   No, I am NOT a master of Regex (and wish I was)

$Phone.RawContent | out-file c:powershelltest.txt

NOTEPAD C:Powershelltest.txt

Sure enough I found the data was stored in a consistent pattern in the HTML document.   It was always after the word “MAC Address” followed by some HTML data.   I used this as my Search parameter for a SELECT-STRING

$locationmac=$phone.RawContent | Select-String -Pattern ‘MAC Address</B></TD><td width=20></TD><TD><B>’

Now with a consistent way to find the Mac address and the Index to where it could be pulled from a web page, a simple For loop to pull out the 12 Digits of the MAC address.

$startmac=$locationMac.Matches.Index+$LocationMac.Matches[0].Length

for ($x=0;$x -lt 12; $x++) {

$MacAddress=$MacAddress+$Phone.Rawcontent[$Startmac+$x]

}

Querying the rest was a matter of finding which web page exposed the data and a similar pattern which would be nothing more than

Use SELECT-STRING to find data header location.

Pull data out for For loop

Now the rest of the data wasn’t as nice as the Mac Address, not all phones had the same number of digits for the serial number, not all extensions had the same number of digits.   For that I ran a DO Until loop to query data until it hit the first part of new HTML (Which in this case consistently started with a “<”)

Now the fun bit.   RETURNING that Object.   In Powershell Version 3 there is a really cool feature June Rogers showed me at Teched called ‘[pscustomobject]’ which lets you simply define a New Powershell custom object in one simple line.

In my case I just wanted to return my data so I was able to do this as one simple line in Version 3

return [pscustomobject]@{PhoneDN=$PhoneDN;MacAddress=$MacAddress;Serialnumber=$SerialNumber;SwitchSpeed=$Switchspeed;SwitchPosition=$SwitchPosition}

This would return an Object with 5 pieces of data I had queried as one Powershell Object with 5 properties.

The end result was a script looking like this.   I haven’t dropped in any error checking but it worked ok the first time with a CSV file of IP Addresses being piped to this script.

Enjoy and FEEL the Power of Shell – It’s in YOU

Sean
The Energized Tech

param(
[string]$IPAddress=’192.168.45.54′
)

#Data to be pulled from Phone

$MacAddress=$NULL
$SerialNumber=$NULL
$PortLocation=$NULL
$PortSpeed=$NULL
$SwitchPosition=$NULL
$SwitchSpeed=$NULL
$PhoneDN=$NULL

#URL on Cisco Phone with Page containing MAC address

$PhoneRequest=’http://’+$IPAddress+’/CGI/Java/Serviceability?adapter=device.statistics.device’

$phone=Invoke-WebRequest $PhoneRequest

#Find where the MAC address header is in the HTML document

$locationmac=$phone.RawContent | Select-String -Pattern ‘MAC Address</B></TD><td width=20></TD><TD><B>’

# Use the Index of the data within the document

$startmac=$locationMac.Matches.Index+$LocationMac.Matches[0].Length

# Mac address is 12 digits, grab them all into a string

for ($x=0;$x -lt 12; $x++) {

$MacAddress=$MacAddress+$Phone.Rawcontent[$Startmac+$x]

}

#Serial number is on the same page as the MAC Address

$locationserial=$phone.RawContent | Select-String -Pattern ‘Serial Number</B></TD><td width=20></TD><TD><B>’
$startserial=$locationserial.Matches.Index+$Locationserial.Matches[0].Length

#Reset counter

$x=0

# This is different, pull everything until you hit new HTML data
# Look for a “<”

do { $SerialNumber=$SerialNumber+$Phone.Rawcontent[$StartSerial+$x]; $x++; } while ($Phone.Rawcontent[$StartSerial+$x] -ne ‘<‘)

$locationDN=$phone.RawContent | Select-String -Pattern ‘Phone DN</B></TD><td width=20></TD><TD><B>’
$startDN=$locationDN.Matches.Index+$LocationDN.Matches[0].Length

#Reset counter

$x=0

# Same process, but find the phone DN (Primary Extension)

do { $PhoneDN=$PhoneDN+$Phone.Rawcontent[$StartDN+$x]; $x++; } while ($Phone.Rawcontent[$StartDN+$x] -ne ‘<‘)

# Now we look for the Port Speed and the Switch it sits on

$PortRequest=’http://’+$IPAddress+’
/CGI/Java/Serviceability?adapter=device.statistics.port.network’

$portdata=Invoke-WebRequest $PortRequest

$locationswitch=$portdata.RawContent | Select-String -Pattern ‘CDP Neighbor Port</B></TD><td width=20></TD><TD><B>’

$startswitch=$locationswitch.Matches.Index+$Locationswitch.Matches[0].Length

$x=0

do { $SwitchPosition=$SwitchPosition+$PortData.Rawcontent[$StartSwitch+$x]; $x++; } while ($portdata.Rawcontent[$StartSwitch+$x] -ne ‘<‘)

$locationspeed=$portdata.RawContent | Select-String -Pattern ‘Port Information</B></TD><td width=20></TD><TD><B>’

$startspeed=$locationspeed.Matches.Index+$Locationspeed.Matches[0].Length

$x=0

do { $SwitchSpeed=$SwitchSpeed+$PortData.Rawcontent[$Startspeed+$x]; $x++; } while ($portdata.Rawcontent[$StartSpeed+$x] -ne ‘<‘)

# Return all data as a Powershell v3 Custom Object

return [pscustomobject]@{PhoneDN=$PhoneDN;MacAddress=$MacAddress;Serialnumber=$SerialNumber;SwitchSpeed=$Switchspeed;SwitchPosition=$SwitchPosition}