Learn How to Run PowerShell Scripts Against Multiple Computers

Learn How to Run PowerShell Scripts Against Multiple Computers

  • Comments 9
  • Likes


Summary: Microsoft Scripting Guy Ed Wilson teaches you how to run Windows PowerShell Scripts against multiple computers in this step-by-step article.


Hey, Scripting Guy! QuestionHey, Scripting Guy! I am wondering on the best way to cause my script to work against multiple computers.

-- LS


Hey, Scripting Guy! AnswerHello LS, Microsoft Scripting Guy Ed Wilson here. I received a real nice email message this morning from my friend Jit who lives in Canberra, Australia. He was telling me that with the holidays, his children are out of school for a while, and he is afraid they will drive him crazy. I suggested he teach them Windows PowerShell. It will keep them entertained for hours. The kids can work their way through the Scripting Wife articles, and solve all the Beginner events from the 2010 Scripting Games. Even as the year 2010 comes to a close, have no fear, the events from the 2010 Scripting Games will remain posted, and you are free to work them at your leisure. In fact, when I was writing the events, I had this this very scenario in mind (well, ok, not the cheap babysitter scenario, but I did envision something interesting enough that a non-computer professional would enjoy solving.) Anyway, my last trip over to Australia, I wrote an article that talked about using Windows PowerShell to track items in a list. During that flight, I stopped in Nadi, Fiji and I still have some change from Fiji. The best souvenirs I have from the month long trip are the pictures I took, such as this one of a string ray.


In the article about packing for an Australian trip I hard-coded items into an array. That is, actually, one approach to your problem of running a script against multiple computers. If you have a fairly small collection of computers which you routinely work with, an array of computer names works very well. What makes the array of computer names work especially well for WMI queries is the ability of the computername  (CN is an alias for this parameter) to accept an array of computer names. This script shows the technique.


$computers = "hyperv","hyperv-box"

Get-WmiObject -Class win32_bios -cn $computers |

Format-table __Server, Manufacturer, Version -AutoSize


If, on the other hand, I have more than four or five computers which I routinely work with, or if I have different groups of computers to query, I will store the computer names in a text file. The composition of the text file is simple; each computer name receives its own line. Two things are essential to avoid potential problems: make sure that there are no spaces after the computer name before the carriage return to the next line, and make sure that there are no blank lines after the last computer name in the list. A sample text file that contains computer names for a script is seen in the following figure.


The Get-Content Windows PowerShell cmdlet retrieves the list of computer names from the text file, and converts the text into an array of computer names. One advantage of reading a text file is that multiple text files can be used. For example, one file might list critical servers, and another list might list moderately critical servers. I might run a particular script more frequently against critical servers, than I would run it against moderately critical servers (of course, the example script that checks bios versioning is a script that only has to run as frequently as the hardware vendor updates the bios.) Because a text file of computer names might have computers that are not online, I specified silentlyContinue for the ErrorAction parameter (EA is an alias for the parameter.) ErrorAction is a common parameter, and is therefore not specifically listen in the Help file for the Get-WmiObject Windows PowerShell cmdlet. Common parameters are parameters that are available to any cmdlet. These parameters are implemented by Windows PowerShell itself and do not have to be coded by cmdlet developers. The silentlyContinue value for ErrorAction parameter causes the cmdlet to ignore errors and to continue processing. In the Get-BiosVersionReadTxtFile.ps1 this means that if a computer is not online, that instead of displaying an error, the output will only display data from computers that respond to the query. The Script is seen here.


$computers = Get-Content -Path C:\fso\Computers.txt

Get-WmiObject -Class win32_bios -cn $computers -EA silentlyContinue |

Format-table __Server, Manufacturer, Version –AutoSize


When the script runs, the output seen in the following figure appears.


If I have more than a dozen computers to manage, or if the makeup of the list of computers changes very frequently, I prefer to query Active Directory Domain Services (AD DS) for a current list of computers. Unfortunately, this particular change necessitated a rather “radical” modification to the script. The first thing I have to do is to import the Microsoft ActiveDirectory module. (For more information about how to obtain and using the Microsoft ActiveDirectory module refer to this Hey Scripting Guy! blog article.) After the ActiveDirectory module loads, I use the Get-ADComputer cmdlet to return a collection of computer objects. I pipeline the results to the ForEach-Object cmdlet-Object cmdlet. Unfortunately, this slows things significantly, but is necessary because the Get-WmiObject cmdlet does not accept pipelined input for the computername parameter. Because I am inside a Foreach-Object process statement, I have to create a custom object to emit to the Format-Table cmdlet. This enables me to retrieve a single list output, instead of lots of individual tables. The complete Get-BiosVersionQueryAD.ps1 script appears here.


Import-Module -Name ActiveDirectory

Get-ADComputer -filter * |

Foreach-Object {

 Get-WmiObject -Class win32_bios -cn $_.name -EA silentlyContinue |

 Select-Object __Server, Manufacturer, Version } |

Format-Table -Property * -AutoSize


When the Get-BiosVersionQueryAD.ps1 script runs, the output seen in the following figure appears.


There are other ways of retrieving input lists of computer names but these are the top three methods that I use. Other ways of retrieving input would including querying a Microsoft Excel spreadsheet, querying a Microsoft Access database, or even a SQL Server database. One could, of course, query a Microsoft Word file but that would be an awful lot like querying a text file, but would have the associated overhead of working with COM objects. Instead of querying Microsoft Word files, I copy the text from the document, and paste it into Notepad. The Get-Content Windows PowerShell cmdlet is just much too easy to use to justify the overhead of working with Word files for simply maintaining a listing of computer names.

LS, that is all there is to retrieving input lists of computer names. Script design week will continue tomorrow when I will talk about how to work with the pipeline.

I invite you to follow me on Twitter or Facebook. If you have any questions, send email to me at scripter@microsoft.com or post them on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.


Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • How about if i need to generate a list of all my computers (workstations and servers) in my forest?

    Thanks in advance!

  • @Rupert

    That is exactly what i do in the Get-BiosVersionQueryAD.ps1 script that I talk about near the end of the article. I also reference additional articles that can help you do this.

  • Love this...plain and simple to get me out the door running.

    Thanks for sharing all your knowledge on this and many other sites!

  • I was given a project to try to get all of the computers in our domain that in the AD have the description tomb-stoned and compare that to a list of already populated computer and pick out duplicates unfortunately I am still on my "Hello world" edition of my skills so I am not 100% on how i am going to do this.

  • Awesome script !
    You are doing great wonders to PoSH learners

  • thanks

  • What if I wanted this script to email me the output of the results across the unprotected Internet and I wanted to mask the server hostnames with something more generic like server1, server2, server3 etc. ??

  • I love using stuff like this but it takes a lot of time the more machines you add. Is there a way to get this to be "parallel" opposed to "serial." What I mean by that is can I have it read my list of machines and broadcast what I want it to do to all of the machines and then return the value? So that I don't have to wait for machine1 to get done then machine2 has to get done before I can get machine3 information. I would like for machine1, machine2, and machine3 to get the instructions set and run at the same time and return the value.
    I say this because I was checking 200 machines to see if something was installed. On one machine that takes about a minute so you are looking at 200 minutes instead of each machine getting the instructions and returning values in a minute or so.

  • I have a bunch of servers (95 servers) in my company which we use on a regular basis and get refreshed regularly. the thing is, when they get refreshed the appv packages sometimes go missing. i need ONE power shell script that i can run against all the servers at the same time to see the discrepancies. I am ok with reaching out to each server that has an issue, but i cant run a script in all 95 every single day. i see that a .txt file with server names can be a good start. can i also use that script to run against such a big collection of servers? I am a complete noob when it comes to power shell, so please advice.