Skip to content

Instantly share code, notes, and snippets.

@austind
Created October 20, 2017 16:58
Show Gist options
  • Save austind/359dca1217aacf28c16812663270f364 to your computer and use it in GitHub Desktop.
Save austind/359dca1217aacf28c16812663270f364 to your computer and use it in GitHub Desktop.
Parses CAM table output from a Cisco switch, adding IP address, hostname, and OUI vendor info from a Windows DHCP server (2012 R2+)
# Show all dynamic MACs, excluding the uplink trunk port
# Don't includer any header ouptput, only actual entries
# e.g., show mac address-table dynamic | ex Gi0/24
$ShMacAddrOutput = @"
1 0023.ae57.3df2 DYNAMIC Gi0/7
1 0023.aeaf.77b2 DYNAMIC Gi0/6
1 14b3.1f01.00e4 DYNAMIC Gi0/2
1 28b2.bd8e.5459 DYNAMIC Gi0/3
1 28f1.0e32.a204 DYNAMIC Gi0/1
1 2c76.8ac4.f7e5 DYNAMIC Gi0/3
1 30cd.a73a.a0fe DYNAMIC Gi0/12
1 4c57.ca63.0b5e DYNAMIC Gi0/3
1 8843.e104.1246 DYNAMIC Gi0/3
1 a48d.3b56.b085 DYNAMIC Gi0/3
1 accc.8e49.b7a6 DYNAMIC Gi0/18
1 accc.8e49.b7ac DYNAMIC Gi0/16
1 accc.8e49.b7c0 DYNAMIC Gi0/17
1 accc.8e55.b913 DYNAMIC Gi0/15
1 accc.8e5d.1ab1 DYNAMIC Gi0/19
1 accc.8e76.4716 DYNAMIC Gi0/20
1 b083.fe8f.86a3 DYNAMIC Gi0/11
1 b083.fe9b.5abc DYNAMIC Gi0/13
1 b083.fe9b.5b47 DYNAMIC Gi0/8
1 e4a7.a04f.3689 DYNAMIC Gi0/3
1 f430.b92b.ffc0 DYNAMIC Gi0/14
1 f48e.38dd.6f63 DYNAMIC Gi0/4
5 0010.4948.856d DYNAMIC Gi0/13
5 0010.4948.8576 DYNAMIC Gi0/11
5 0010.4948.85a3 DYNAMIC Gi0/8
5 0010.4949.2777 DYNAMIC Gi0/2
5 0010.4949.2780 DYNAMIC Gi0/4
5 0010.4949.d5ad DYNAMIC Gi0/22
5 0010.4949.d5b1 DYNAMIC Gi0/23
"@
# The command changed column layout. If you're on anything like
# modern gear, leave it on $new. If you have a very old IOS that uses
# show mac-address-table, change this to $old
$ShMacAddrCmd = $new
# show mac-address-table (old style)
$old = @('mac','type','vlan','port')
# show mac address-table (new style)
$new = @('vlan','mac','type','port')
# http://standards.ieee.org/develop/regauth/oui/oui.txt
# this file is huge or else I would pull it with Invoke-WebRequest
$OuiDb = 'oui.txt'
# Takes FastEthernet0/1 and returns Fa0/1
# Currently not used for anything
Function Truncate-PortName {
Param ($FullPortName)
$PortAbbreviation = $FullPortName.Substring(0,2)
$PortID = $FullPortName -replace '[a-zA-Z]', ''
return "${PortAbbreviation}${PortId}"
}
# Takes a MAC in the form of 0011.2233.4455
# Returns 00-11-22-33-44-55
Function Convert-DottedToDashedMac {
Param ($MacAddress)
$MacAddress = $MacAddress.Replace('.', '')
$DashIndices = @(2,5,8,11,14)
ForEach($Index in $DashIndices) {
$MacAddress = $MacAddress.Insert($Index, '-')
}
Return $MacAddress
}
# Split on newline ('\r'), trim leading or trailing whitespace,
# then replace any run of one or more spaces with a comma.
# Finally, convert to an object array with ConvertFrom-Csv
$ParsedCamTable = ($ShMacAddrOutput -split '\r').trim() -replace '[ ]+', ',' | ConvertFrom-Csv -Header $ShMacAddrCmd
# Pull all DHCP scopes on the server
$Scopes = Get-DhcpServerv4Scope
# Resolve scope IDs (which are the subnet IDs) to VLANs
# Requires the scope have "VLAN X" in the description field,
# or else resolving DHCP IP addresses and hostnames will fail.
$ScopeList = @{}
$Scopes | % {
If ($_.Description -like '*vlan*') {
[int]$ScopeVlan = $_.Description -replace '[a-zA-Z]', ''
$ScopeList[$ScopeVlan] += $_.ScopeId.IPAddressToString
}
}
$output = @()
ForEach ($Entry in $ParsedCamTable) {
# Convert MAC from 0011.2233.4455 to 00-11-22-33-44-55, as required for Get-DhcpServerv4Lease
$mac = Convert-DottedToDashedMac $entry.mac
# Obtain lease if we can. If not found, don't worry about it
$Lease = Get-DhcpServerv4Lease -ClientId $mac -ScopeId $ScopeList[[int]$Entry.vlan] -ErrorAction SilentlyContinue
# Yank OUI from MAC
$Oui = $mac.substring(0,8)
# Look up manufacturer from OUI database
# This is pretty slow, probably some low-hanging fruit to optimize
$Mfgr = ((Select-String $oui $ouidb | Select -exp line) -split '\t{2}')[1]
# If we got lease info, add it to output. Otherwise leave blank.
If ($Lease) {
$IpAddress = $Lease.IPAddress.IPAddressToString
$HostName = $Lease.HostName.split('.')[0]
} Else {
$IpAddress = ''
$HostName = ''
}
# Append result object to output array
$output += [PsCustomObject]@{
Port = $Entry.port
Mac = $entry.mac
DhcpAddress = $IpAddress
Vlan = $Entry.vlan
DhcpHostName = $HostName
Mfgr = $Mfgr
}
}
# You can do whatever you want with $output which is an object array, but
# this construct is nice because it sorts output in a neat table,
# ordered by the numeric port value. If you just did $(sort -property Port),
# you'd get Gi0/2 and Gi0/20 next to each other, since it sorts as a [string]
# instead of an [int].
$Output | Sort-Object -Property {[int]($_.port -replace '[a-zA-Z/]', '')},Mac | Format-Table -AutoSize
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment