Collecting IP address, MAC address and host names from all devices on a subnet using PowerShell

by Klaus Graefensteiner 13. September 2010 22:44

Introduction

It’s Friday afternoon. The network guys threw the towel, after trying to replicate the DNS servers on both sides of the firewall. “Klaus” they said, “Would you please give us a list of host names and MAC addresses of the computers in the lab network?”. The network guys decided to just add static host name mappings to the DNS on the office network. This way we would be able to access the machines in the lab by hostname. Temporarily of course!

Great! Pulling up the MAC addresses for about 30 PCs, manually, is not what I call a great start into the weekend! Time to call…

PowerShell to the rescue

I studied a bunch of links on the interweb and came up with my own home brawn recipe. It uses a .NET call and the ARP (address resolution protocol) tool. No need for WMI and actually reading the configuration from each of the machines, which requires valid credentials to be passed in for each remote computer. This was in my case not possible.

Here is how it works. The script would iterate IP addresses from lets say 192.168.2.1 to 192.168.2.255 and call [System.Net.Dns]::GetHostbyAddress($IP).HostName. This call will try to return a hostname of a Windows PC using the address resolution protocol ARP. The address resolution protocol caches also the MAC address for each particular IP address. This mapping can be retrieved using the ARP tool with the –A parameter. Its out put looks like this:

#Interface: 192.168.2.49 --- 0x10003
#  Internet Address      Physical Address      Type
#  192.168.1.1            00-26-88-ed-42-06     dynamic   
#  192.168.1.51           00-0c-29-84-ff-af     dynamic   
#  192.168.2.2            00-00-bc-2f-93-06     dynamic   
#  192.168.2.35           00-50-56-bd-26-1a     dynamic   
#  192.168.2.36           00-50-56-bd-51-2b     dynamic   

The Regular Expression to parse the ARP –A output

One of the key aspects of my PowerShell script is to parse the output of the ARP tool using a regular expression. The regular expression is here:

$Regex = "^\s+(?<IP>{0}\d+)\s+(?<MAC>[0-9a-f]{2}-[0-9a-f]{2}-[0-9a-f]{2}-[0-9a-f]{2}-[0-9a-f]{2}-[0-9a-f]{2})" -f $SubnetRegex, "{1}", "{2}"

The Script in its simplicity and beauty

Here is the script in its hole beauty. It creates a csv file with IP addresses, MAC addresses and hostnames

$DebugPreference = "continue"

$Subnet = "192.168.2."
$SubnetData = New-Object -TypeName "System.Collections.ArrayList"

1..70 | ForEach-Object `
{ 
    $ClientTable = @{}
    $IP = "$Subnet$_"; 
    Write-Debug $IP;
    $ClientTable["IP"] = $IP
    $ClientTable["MAC"] = "?"
    try
    {
        $Hostname = [System.Net.Dns]::GetHostbyAddress($IP).HostName
        Write-Debug $Hostname
        $ClientTable["Hostname"] = $Hostname
    }
    catch
    {
        Write-Warning "No hostname found for $IP"
        $ClientTable["Hostname"] = "?"
    }
    
    $null = $SubnetData.add($ClientTable)
    
}


$SubnetData


#Get ARP Result
$ARPResultLines = ARP -a
$ARPResultLines.count

#Interface: 192.168.2.49 --- 0x10003
#  Internet Address      Physical Address      Type
#  192.168.1.1            00-26-88-ed-42-06     dynamic   
#  192.168.1.51           00-0c-29-84-ff-af     dynamic   
#  192.168.2.2            00-00-bc-2f-93-06     dynamic   
#  192.168.2.35           00-50-56-bd-26-1a     dynamic   
#  192.168.2.36           00-50-56-bd-51-2b     dynamic   

$SubnetRegex = $Subnet.replace(".", "\.");
$SubnetRegex

$Regex = "^\s+(?<IP>{0}\d+)\s+(?<MAC>[0-9a-f]{2}-[0-9a-f]{2}-[0-9a-f]{2}-[0-9a-f]{2}-[0-9a-f]{2}-[0-9a-f]{2})" -f $SubnetRegex, "{1}", "{2}"
$Regex


for($i=3; $i -lt $ARPResultLines.count; $i++)
{
    $Line = $ARPResultLines[$i]
    Write-Debug $Line
    if($Line.Trim() -ne "")
    {
        if($Line -match $Regex)
        {
            $IP = $matches.IP
            $MAC = $matches.MAC
        
            foreach($DataSet in $SubnetData)
            {
                if($DataSet["IP"] -eq $IP)
                {
                    $DataSet["MAC"] = $MAC
                }
        
            }
        }
        
    }
}

$SubnetData


Set-Content -Encoding "UTF8" -value "IP, Hostname, MAC" -Path "$Home\LabNetwork.csv"

foreach($DataSet in $SubnetData)
{
    $Hostname = $DataSet["Hostname"]
    $IP = $DataSet["IP"]
    $MAC = $DataSet["MAC"]
    Add-Content -Encoding "UTF8" -value "$IP, $Hostname, $MAC" -Path "$Home\LabNetwork.csv"

}

. $Home\LabNetwork.csv

Ausblick

budlight-bottle-thumb-121x240-9861

Figure 1: I don’t drink Bud Light, but I like the commercials

This is what I am thinking: Bud Light Real Men Of Genius Commercials.

Mr.-PowerShell-Doing-The-Work-For-Network-Guys-On-Friday-Afternoon Guy.

Tags: , , , , , , , , ,

PowerShell | Tips & Tricks

Comments

9/14/2010 12:49:59 AM #

pingback

Pingback from topsy.com

Twitter Trackbacks for
        
        Tellingmachine | Collecting IP address, MAC address and host names from all devices on a subnet using PowerShell
        [tellingmachine.com]
        on Topsy.com

topsy.com |

9/15/2010 12:55:12 AM #

Richard Lazaro

Hi,

I think you have an issue in your script.
If you need to check a subnet like this : 192.168.4.0/22 (192.168.4.0 to 192.168.7.255).

How this subnet is passed ?

Best Regards,
Richard Lazaro.

Richard Lazaro France |

Comments are closed

About Klaus Graefensteiner

I like the programming of machines.

Add to Google Reader or Homepage

LinkedIn FacebookTwitter View Klaus Graefensteiner's profile on Technorati
Klaus Graefensteiner

Klaus Graefensteiner
works as Developer In Test and is founder of the PowerShell Unit Testing Framework PSUnit. More...

Open Source Projects

PSUnit is a Unit Testing framwork for PowerShell. It is designed for simplicity and hosted by Codeplex.
BlogShell is The tool for lazy developers who like to automate the composition of blog content during the writing of a blog post. It is hosted by CodePlex.

Administration

About

Powered by:
BlogEngine.Net
Version: 1.6.1.0

License:
Creative Commons License

Copyright:
© Copyright 2012, Klaus Graefensteiner.

Disclaimer:
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Theme design:
This blog theme was designed and is copyrighted 2012 by Klaus Graefensteiner

Rendertime:
Page rendered at 5/20/2012 6:27:04 PM (PST Pacific Standard Time UTC DST -7)