I recently demonstrated how to use Get-WMIObject in PowerShell to retrieve disk information for the system drive on remote computers, even if you don’t know what the system drive is ahead of time. Today I want to continue that exploration and show you some alternatives by expanding on this scenario. I have a list of computer names stored in a variable. It doesn’t matter how you populate the variable. My variable, $computers, contains computers that are running and a few that are offline or simply non-existant.
At the end of the previous article, I piped the list of computer names to the ForEach-Object cmdlet. That example took me about 9.5 seconds to run, which includes the WMI timeouts and error handling. I used ForEach-Object so that I could pipe results to Sort-Object and Format-Table. However I could also use the ForEach enumerator.
However, you cannot pipe this command to anything if you try something like this it will fail:
In order to use the ForEach enumerator, which unfortunately has the same name as the alias for ForEach-Object, you have to save the results to a variable and then do something with it.
Or, you can be clever and wrap the ForEach statement in a subexpression:
When I insert the command inside $(), PowerShell implicitly treats it as a variable. Here's my alternative expression using this technique:
This command also took about 9.5 seconds. I also moved the property selection to inside so that I am only selecting the properties I want for each computer. The sorting and formatting is left for the total results. Sometimes I have found using the ForEach enumerator to perform a little faster than ForEach-Object. That's why you need to test with Measure-Command. I am only testing with a handful of computers, but you might need to scale this to hundreds so every little performance gain matters. Once thing we could do is limit the WMI queries to computers we've confirmed are up and running. This would cut down on waiting for WMI to timeout and raise an exception. We can use Test-Connection. I can filter the list of computers by giving each one a single ping and only processing those that respond.
I get the same result but without the errors for offline computers and now it only took 6.2 seconds and increase of %35. As the number of computers in the list grows this starts becoming significant. By the way, it is still possible for errors to arise such as Access Denied, which is why I still have my Try/Catch scriptblock. But hopefully there will be very few computers with that type of problem. By "pre-qualifying" the computer names I've improved performance regardless. Next time we'll look into a few more performance tweaks with this scenario as well as introduce a new requirement.