How can I make this script better?

This topic contains 5 replies, has 4 voices, and was last updated by Profile photo of Dave Wyatt Dave Wyatt 3 years, 4 months ago.

  • Author
    Posts
  • #11708
    Profile photo of Barry Thomson
    Barry Thomson
    Participant

    Hello,

    I have a script to search for LAN and WLAN MAC addresses, along with the serial number of device.

    Is there a way that I could improve on what I've got here?

    I'd love to make this output data with no spaces in rows, so if it doesn't find the machine online, it will add a an entry for this in the output.

    Also, I have two separate WMI queries for the two MAC addresses. Is this efficient having this twice? I had originally done this because it was the only way I could figure out how to get everything in its own cell in Excel.

    Any help would be hugely appreciated.

    function Get-MacaddressNoPrompt
    {

    $computers = Get-Content -path C:\Machines.txt

    foreach ($computer in $computers) {

    $LANMAC = Get-WmiObject -Class win32_networkadapter -ComputerName $computer |
    where {$_.NetConnectionID -eq "Local Area Connection"} |
    Select-Object PSComputerName, macaddress, netconnectionid

    $WLANMAC = Get-WmiObject -Class win32_networkadapter -ComputerName $computer |
    where {$_.NetConnectionID -eq "Wireless Network Connection"} |
    Select-Object PSComputerName, macaddress, netconnectionid -ErrorAction Ignore

    $Serial = Get-WmiObject -Class win32_bios -ComputerName $computer |
    select serialnumber

    $properties = @{ 'ComputerName'= $LANMAC.PSComputerName;
    'LAN'= $LANMAC.macaddress;
    'WLAN'= $WLANMAC.macaddress;
    'Serial'= $Serial.serialnumber}

    $MACSerial = New-Object -TypeName psobject -Property $properties
    Write-Output $MACSerial

    }
    }

    Get-MacaddressNoPrompt |
    Export-CSV -NoTypeInformation -Path $env:USERPROFILE\MACaddresses-$(Get-Date -Format dd-MM-yyyy-HHmm).csv

  • #11709
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    You can use a single call to Get-WmiObject for the Win32_NetworkAdapter class, then work with the data locally from there. You can also cut down in the network traffic a bit by using a Filter in the Get-WmiObject command (in case there are more network adapters on the system than the ones you actually want to look at.)

    I haven't tested this code, but I made a few small changes based on what you posted. Hopefully it helps:

    function Get-MacaddressNoPrompt
    {
    
        $computers = Get-Content -path C:\Machines.txt
    
        foreach ($computer in $computers) {
            $adapters = Get-WmiObject -Class win32_networkadapter -ComputerName $computer -Filter 'NetConnectionID = "Local Area Connection" OR NetConnectionID = "Wireless Network Connection"'
    
            $computerName = $adapters[0].PSComputerName
    
            $LANMAC = $adapters |
            Where-Object { $_.NetConnectionID -eq 'Local Area Connection' } |
            Select-Object -ExpandProperty MacAddress
    
            $WLANMAC = $adapters |
            Where-Object { $_.NetConnectionID -eq 'Wireless Network Connection' } |
            Select-Object -ExpandProperty MacAddress
    
            $Serial = Get-WmiObject -Class win32_bios -ComputerName $computer |
            Select-Object -ExpandProperty SerialNumber
    
            $properties = @{
                'ComputerName'= $computerName
                'LAN' = $LANMAC
                'WLAN' = $WLANMAC
                'Serial' = $Serial
            }
    
            $MACSerial = New-Object -TypeName psobject -Property $properties
            Write-Output $MACSerial
    
        }
    }
    
    Get-MacaddressNoPrompt |
    Export-CSV -NoTypeInformation -Path $env:USERPROFILE\MACaddresses-$(Get-Date -Format dd-MM-yyyy-HHmm).csv
    
  • #11710
    Profile photo of Barry Thomson
    Barry Thomson
    Participant

    Hi Dave,

    Thank you very much. I hadn't thought of doing like this at all, and don't think I would have stumbled upon it, as still very new to this.

    This is perfect.

    Thank you

  • #11728
    Profile photo of Richard Siddaway
    Richard Siddaway
    Moderator

    I think you can simplify your code a bit

    Try this
    function Get-MacaddressNoPrompt {
    [CmdletBinding()]
    param(
    [string[]]$computername
    )

    PROCESS {

    foreach ($computer in $computername) {
    $adapters = Get-WmiObject -Class win32_networkadapter -ComputerName $computer -Filter 'NetConnectionID = "Local Area Connection" OR NetConnectionID = "Wireless Network Connection"'

    foreach ($adapter in $adapters){
    switch($adapter.NetConnectionID) {
    "Local Area Connection" {$LANMAC = $adapter.NetConnectionID; break}
    "Wireless Network Connection" {$WLANMAC = $adapter.NetConnectionID; break}
    }
    }

    $properties = @{
    'ComputerName'= $computer
    'LAN' = $LANMAC
    'WLAN' = $WLANMAC
    'Serial' = (Get-WmiObject -Class win32_bios -ComputerName $computer).SerialNumber
    }

    New-Object -TypeName psobject -Property $properties

    }
    }
    }

    Get-MacaddressNoPrompt -computername (Get-Content C:\Machines.txt) |
    Export-CSV -NoTypeInformation -Path $env:USERPROFILE\MACaddresses-$(Get-Date -Format dd-MM-yyyy-HHmm).csv

  • #11812
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    [quote=11803]First of all, you don't account for foreign versions of Windows (and using only default names), such as on my Norwegian work computer, where “Wireless Network Connection” actually has the default name “Trådløs nettverkstilkobling”.
    [/quote]

    That's a good point, but there don't appear to be a lot of options. Looking over the properties of Win32_NetworkAdapter, it appeared that filtering on AdapterType or AdapterTypeID might have been a good idea, but those fields are NULL on my system for adapters that are disabled (such as my wireless NIC, when I'm connected via Ethernet instead.)

    Looking for PhysicalAdapter=TRUE seems like a reasonable alternative, although that is also returning my VPN adapter for some reason, in addition to the Ethernet and Wireless cards.

    The MSFT_NetAdapter class has some additional properties that might help, but it's only available on Windows 8 / Server 2012 or later.

  • #11803
    Profile photo of Joakim Svendsen
    Joakim Svendsen
    Participant

    Disclaimer: I am doing this because I'm bored and looking for an excuse to code.

    Anyway, the logic is severely flawed for most scenarios that I can think of, such as iterating a list of servers/clients and wanting their LAN and WLAN MAC addresses (which seems to be what's wanted). First of all, you don't account for foreign versions of Windows (and using only default names), such as on my Norwegian work computer, where "Wireless Network Connection" actually has the default name "Trådløs nettverkstilkobling". This might be fine in your environment where you might be able to assume only English Windows exists (well, except for that foreign guy who brought his own laptop and had it joined to the domain) – but unless you actually have a script that sets these names to these assumed defaults, it's a pretty horribly unreliable way of determining what adapter is LAN and WLAN. They could have been renamed. And what about "Local Area Connection 2" (default name for second adapter)? 3? I added support for handling multiple values in my little cmdlet which was initially based on Dave and Richard's code.

    Another thing you're ignoring is Windows versions. On Windows 8.1 (and probably 8), the default name is no longer "Local Area Connection", but "Ethernet". Again, you might be in a position to make assumptions, but I wrote something a bit more robust and flexible anyway.

    As I'm writing this I got to thinking that I bet there's a better way to determine this rather than NetConnectionID. Looking at the properties returned from the WMI class: maybe the ProductName or Manufacturer properties against a list you hard-code, but it doesn't seem convenient at all. I'm already done writing up the code, so I'll just post it along with some examples.

    If you remove the "[ordered]" part before the hash literal (object properties) this should also work with PowerShell v2, unless I overlooked something. Some of the syntax in the examples below assumes v3 or above.

    Here is a test run on a laptop with Norwegian Windows 7 that demonstrates the "parameterized" LAN filter and WLAN filter, and how it doesn't return anything with the defaults. I use the -Verbose parameter to display the WQL query that's formed. Multiple values for the parameters are supported for each filter, and you can use the -Like wildcards "*" and "?".

    PS P:\PowerShell> 'localhost' | Get-MacCrap -Verbose | ft -a
    VERBOSE: Using filter: NetConnectionID LIKE "%Local Area Connection%" OR NetConnectionID LIKE "%Wireless Network Connection%"
    
    ComputerName LAN WLAN Serial
    ------------ --- ---- ------
    localhost             5XGX422
    

    There you can see that no MAC addresses are listed, because the filters don't match the list which looks like this:

    PS P:\PowerShell> gwmi win32_networkadapter | % netconnectionid
    Lokal tilkobling
    Trådløs nettverkstilkobling
    Bluetooth-nettverkstilkobling
    VMware Network Adapter VMnet1
    VMware Network Adapter VMnet8
    

    Now specify custom, localized filters:

    PS P:\PowerShell> 'localhost' | Get-MacCrap -Verbose -WlanFilter 'Trådløs*' -LanFilter 'Lokal tilkobling' | ft -a
    VERBOSE: Using filter: NetConnectionID LIKE "Lokal tilkobling" OR NetConnectionID LIKE "Trådløs%"
    
    ComputerName LAN               WLAN              Serial
    ------------ ---               ----              ------
    localhost    5C:27:0A:82:42:B7 19:13:96:54:29:71 5XGX422
    

    Now try something where you get multiple hits (skipping WLAN now) and observe that multiple values are semicolon-joined:

    PS P:\PowerShell> 'localhost' | Get-MacCrap -LanFilter 'VMware*' | ft -a
    
    ComputerName LAN                                 WLAN Serial
    ------------ ---                                 ---- ------
    localhost    00:50:56:D0:00:02;00:50:56:D0:00:06      5XGX422
    

    Ok, that's about it. I'm uploading the code in a Get-MacCrap.ps1.txt file. ... I'm having trouble uploading (getting an error), so I uploaded it to my own site here: http://www.powershelladmin.com/wiki/File:Get-MacCrap.ps1.txt

    Cheers.

You must be logged in to reply to this topic.