Machines Serial Numbers

Hello all,
I’m trying to get a list of pc’s names and their serial numbers from DC.
Using -
(Get-ADComputer -Filter 'Name -like "*REV*" -and Enabled -eq "true"').Name | Foreach-Object {Get-CimInstance Win32_Bios -ComputerName $_ -ErrorAction SilentlyContinue | Select-Object PSComputerName,SerialNumber} | Out-GridView
The output is only few pc’s from a couple of hundreds and all the process is very slow.
What is the proper way to get this info?
Thank you in advance.

First, and ideally, get an idea of the number of systems the first part (before the pipeline) will discover.

Second, the resultant dataset will most likely be something that would want to keep, at least for a while. You lose this by sending to Out-Gridview. There may be more than just computer name and serial number that you could use or want from Win32_Bios like the install date, manufacturer, or BIOS version. If you are going through the trouble to get 1 property, why not get more.

Handling the output can be straight-forward, like Export-CSV, or complex, like logging to a CSV or readily importable data type for systems offline, that produce errors, and the valid data you want. This logging can be appended by each loop.

Regarding looping and the performance. If you are using PowerShell 7, ForEach-Object has a -Parallel switch. That could yield faster results. If not, there’s always PoshRSJob or ThreadJob that would help with iteration. Get-CIMInstance parameter ComputerName accepts an array; that could be a bit faster than what you’re experiencing now. An internet search for PowerShell multithreading might provide some ideas or even some walkthroughs.

If you have control over your AD, there’s a very different approach. In a nutshell, have each computer update one or more properties on its own AD object via a startup script. Then you can query AD directly and not have to connect to potentially 1000s of systems.

Hopefully, I’ve given you some ideas on how to proceed. I’ve done both scenarios, harvest data from a few thousand systems via multithreading and extending the AD schema to include properties that I wanted and got them there via a startup script.

I apologize if this went deep really fast. Honestly I was using my response to help me unwind and go to sleep.

Hope that helps.

Thanks, appreciate your help.
Enjoy dreaming :wink:

Would a Test-Connection pre-test speed up the process? I feel it takes extra time to reach out to the machine and fail if it is offline. Filter out the machines that are offline and then run a the ciminstance against the machines reporting online.

2 Likes

You could give this a try, I got pretty fast results with 100 machines. As Dave mentioned running a job in the back round could be beneficial.

$Complist = (Get-ADComputer -Filter 'Name -like "*REV*" -and Enabled -eq "true"').Name

foreach($Comp in $CompList){
    
    $PingTest = Test-Connection -ComputerName $Comp -Quiet -Count 1 -ErrorAction SilentlyContinue

    if($PingTest){

    Get-CimInstance -ClassName Win32_Bios -ComputerName $Comp -ErrorAction Ignore | Select PScomputername,SerialNumber #Output of your choice
     
    }
     else{

      #Logfile for failed ping tests
     
    }
     
}
2 Likes

Definitely, filter to the left as soon as possible.

Another good filter attribute would be pwdLastSet. If it’s more than 45 days (technically 30, the extra 15 is just a buffer) old, the system hasn’t connected to the domain meaning that it’s been offline and you’ll likely not be able to connect to it anyway.

Check this Tweet and subsequent article for pointers.

1 Like

Could you use the AD filter and Test-Connection to build the list of systems, then just use that array directly with Get-CIMInstance? I wonder if that would yield faster results since the iteration would be handled by .NET/C# directly instead of the foreach PowerShell statement.

1 Like

Thank you for this tip! That’s a great idea.

Thank you very much, I’ll try it soon.