Using Powershell to get Adapter Information
Had an interesting thread come through on Spiceworks the other day that required some detective work with WMI. In the past, when I did WMI calls with vbScript I usually had to Google it and find someone else who’d done what I wanted to do and modify their script. But with Powershell you don’t have to dig through different blogs, or try to slog through the MSDN documentation, now you can just inspect the data and do it directly. Here’s what I did.
Updated Script – 1/28/14
Just updated the following script. Added parameters and pipeline support. Also updated the script to support PowerShell 3.0 and Get-CimInstance–which is the updated method of getting WMI information from modern OS’s. It does not support Windows XP, but frankly neither did the older version–there is not NetEnabled field in Windows XP so it would have failed on XP machines regardless. Hope you enjoy and you can read where the script came from below!
Get-AdapterInfo
The Script
It all came up when someone wanted to modify an old vbScript I had written 3 years ago–and to be honest I had forgotten I’d even written it!–that made a simple IP sweep of a network and reported simple information about the network adapter (IP, MAC and Computer Name). The twist was he needed a report on all of the network adapters and also wanted the network adapter name. So the first thing to do was take a look at the old script and see what it did. Turns out I was looking at the Win32_NetworkAdapterConfiguration class, so let’s take a look at it and see what information it has:
OK, there are a LOT of properties in here, but the thing what surprised me was there was no property for the Interface Name! OK, WMI is a relational database like any other database, so that means there has to be another table out there that does have the information and the two must connect together using a key field. The trick is figuring out which one. To be honest, I guess on this one and just took a stab to see if Win32_NetworkAdapter existed, and sure enough it did.
And a quick check of this class showed that the property “Name” was the interface name so we now have the 3 pieces of information we need, but how do we tie the two together? There were two promising properties in the list: Index and InterfaceIndex. So I pulled open a second window and compared the two:
Index looks like a winner to me, of course this is far from exacting discovery, so we’ll have to see how the final script comes out and compare it to real life but this is definitely enough information to work off of. So now we need to write a script to query Win32_NetworkAdapter and get the Interface Name and the Index number, then query Win32_NetworkAdapterConfiguration and get the IP address and MAC address.
ForEach ($Adapter in (Get-WmiObject Win32_NetworkAdapter -Filter "NetEnabled='True'")) { $Config = Get-WmiObject Win32_NetworkAdapterConfiguration -Filter "Index = '$($Adapter.Index)'" New-Object PSObject -Property @{ Name = $Adapter.Name IP = $Config.IPAddress MAC = $Config.MacAddress } }
Let’s see if this produces the right information:
We have the good mixed up with the bad here. The IP address is definitely related to the correct network adapter so we now know that Index is indeed the right key field to use, but clearly we have a number of network adapters in there that don’t have any information. They’re probably disabled, too, let’s check. A quick scan through the property fields shows there’s no Enabled field, which is too bad, but there is a NetEnabled field, let’s see if that works for us:
Interesting result, I would have expected true/false on all of them, not null values. But that’s ok, if we put in a filter for “True” that will get the active adapters which is what we really want anyway. Here’s the resulting output after adding -Filter “NetEnabled = ‘True'” to the Win32_NetworkAdapter cmdlet.
Now we’re talking, but we run into another problem. Notice the IP address is surrounded in curly brackets. This designates that the results are an array, not a simple string which makes sense, since you can have more then 1 IP address assigned to an interface, and in fact you can have more then one IP protocol assigned to an adapter (IPv6, of course). That means we have to process that data too. Time for another loop.
ForEach ($Adapter in (Get-WmiObject Win32_NetworkAdapter -Filter "NetEnabled='True'")) { $Config = Get-WmiObject Win32_NetworkAdapterConfiguration -Filter "Index = '$($Adapter.Index)'" ForEach ($Addr in ($Config.IPAddress)) { New-Object PSObject -Property @{ Name = $Adapter.Name IP = $Addr MAC = $Config.MacAddress } } }
And let’s take a look at the results:
Now the output is looking like what we want it to! At this point the meat of the script is written, it’s just a matter of wrapping a loop around the whole thing to go through several computers read from a text file. All I had was IP address so I used the Win32_Ping class to do the reverse lookup–unfortunately Test-Connection doesn’t have a reverse lookup capability otherwise I would have used that. Than I just added -ComputerName to the WMI calls to the resolved computer name as well as wrap some error correction around it.
This is something about Powershell that I just love. The ability to directly look at the WMI classes and figure this stuff out yourself. Trying to read the MSDN documentation is a horrible slog of links and guesses and I’ve never been particularly happy with it and Powershell now lets me avoid it! Maybe you too?
Muchísimas gracias por tu participación, no tenía ni la
más mínima idea.
I really like the script you wrote and it so happens I have a task to enumerate all active interfaces on the network and disable NETBIOS over TCP/IP. My intention was to use your script to enumerate all active interfaces to CSV and then use another script to disable NETBIOS over TCP/IP, such as:
Try {
Get-CimInstance win32_networkadapterconfiguration -Filter ‘servicename = “netvsc”‘ | Invoke-CimMethod -MethodName settcpipnetbios -Arguments @{TcpipNetbiosOptions = 2}
Write-Host “NetBios is Disabled over TCP/IP”
Write-Host “Script Check passed”
Exit 0
}
}
Catch {
Write-Host “Script Check Failed”
Exit 1001
}
Or….
$servers = “myserver01”, “myserver02”, “myserver03”, “myserver04”, “myserver05”, “myserver06”
Foreach ($server in $servers){
$adapter=(gwmi -computer $server win32_networkadapterconfiguration | where {$_.servicename -like “vmxnet*”})
$adapter.settcpipnetbios(2)
}
But, your script gets interface name and not “servicename” which the above example scripts use. What would I need to add to your script to provide “servicename” in addition to MAC, Host, IP Address, and Interface Name? By the way, I’m still very much a Powershell novice and still learning. Hence the question.