Use PowerShell Invoke-Command for Remoting

Summary: Microsoft Windows PowerShell MVP, Don Jones, talks about using the Invoke-Command cmdlet for remoting.

Microsoft Scripting Guy, Ed Wilson, here. I am really excited about the idea I had for this week, and I hope you will be too. I asked Candace Gillhoolley at Manning Press about posting some sample works from some of the Manning Press library of books. She responded enthusiastically and shared five samples that we will post this week. Today we present Don Jones’ Learn Windows PowerShell in a Month of Lunches.

Learn Windows PowerShell in a Month of Lunches 


By Don Jones

One of the coolest things in Windows PowerShell is to send a command to multiple remote computers at the same time. In this article, based on chapter 10 of Learn Windows PowerShell in a Month of Lunches, author Don Jones explains how to use the Invoke-Command cmdlet to execute one-to-many, or 1:n, remoting. To save 35% on your next purchase, use Promotional Code jones1035 when you check out at


Using Invoke-Command for Remoting

The trick I will show you in this article—and one of the coolest things in Windows PowerShell—is to send a command to multiple remote computers at the same time. That’s right, full-scale distributed computing. Each computer will independently execute the command and send the results right back to you. It’s all done with:

Invoke-Command -computername Server-R2,Server-DC4,Server12 `
 -command { Get-EventLog Security -newest 200 |

 Where { $_.EventID -eq 1212 }} 

Try it now

Go ahead and run this command. Substitute the name of your remote computer (or computers) where I’ve put my three computer names.

Everything in those outermost {braces} will get transmitted to the remote computers—all three of them. By default, PowerShell will talk to up to 32 computers at once; if you specified more than that, it will queue them up, so that, as one computer completes, the next one in line will begin. If you have a really awesome network and powerful computers, you could raise that number by specifying the -throttleLimit parameter of Invoke-Command—read the command’s help for more information.

Be careful about the punctuation

We need to pause for a moment and really dig into that example command because this is a case where Windows PowerShell’s punctuation can get confusing, and that confusion can make you do the wrong thing when you start constructing these command lines on your own. There are two commands in that example which use curly braces: Invoke-Command and Where (which is an alias for Where-Object). Where is entirely nested within the outer set of braces. The outermost set of braces enclose everything that is being sent to the remote computers for execution; that includes:

Get-EventLog Security -newest 200 | Where { $_.EventID -eq 1212 }

I should tell you that you won’t see the -command parameter in the Help for Invoke-Command—yet, the command I just showed you will work fine. The -command parameter is actually an alias, or nickname, for the -scriptblock parameter that you will see listed in the Help. I just have an easier time remembering -command, so I tend to use it instead of -scriptblock—but they both work the same way.

If you read the help for Invoke-Command carefully (see how I’m continuing to push those help files?), then you’ll also notice a parameter that lets you specify a script file, rather than a command. That parameter lets you send an entire script to the remote computers—meaning, you can automate some pretty complex tasks and have each computer do its own share of the work.

Try it now

Make sure you can identify the -scriptblock parameter in the help for Invoke-Command and that you can spot the parameter that would enable you to specify the file path and name instead of a scriptblock.

I want to circle back to the -computername parameter for just a bit. When I first used Invoke-Command, I typed a comma-separated list of computer names, just as I did in the example above. But I have a lot of computers I work with, so I didn’t want to have to type them all in every time. I actually keep text files for some of my common computer categories, like Web servers and domain controllers. Each text file contains one computer name per line, and that’s it—no commas, no quotes, no nothing. Windows PowerShell makes it really easy for me to use those files:

Invoke-Command -command { dir } `
 -computerName (Get-Content webservers.txt)

The parentheses there force Windows PowerShell to execute Get-Content first—pretty much the same way parentheses work in math. The results of Get-Content are then stuck into the -computerName parameter, which then works against each of the computers that were listed in the file.

I also sometimes want to query computer names from Active Directory. This is a bit trickier. I can use the Get-ADComputer command (from the ActiveDirectory module in Windows Server 2008 R2) to retrieve computers, but I can’t just stick that command in parentheses like I did with Get-Content. Why not? Because Get-Content is just producing simple strings of text, which -computername is expecting. Get-ADComputer, on the other hand, is producing entire computer objects, and the -computername parameter won’t know what to do with them. So if I want to use Get-ADComputer, I need to find a way to just get the values from those computer objects’ Name properties. Here’s how:

Invoke-Command -command { dir } -computerName (

 Get-ADComputer -filter * -searchBase “ou=Sales,dc=company,dc=pri” |

 Select-Object -expand Name )

Try it now

If you’re running Windows PowerShell on a Windows Server 2008 R2 domain controller or on a Windows 7 computer that has the Remote Server Administration Toolkit installed, then you can run Import-Module ActiveDirectory and then try the above command. If your test domain doesn’t have a Sales OU that contains a computer account, then change ou=Sales to ou=Domain Controllers and be sure to change company and pri to the appropriate values for your domain. (For example, if your domain is, you would substitute mycompany for company and org for pri.)

Within the parentheses, I’ve piped the computer objects to Select-Object, and I’ve used their -expand parameter. I’m telling it to expand the Name property of whatever came in—in this case, those computer objects. So, the result of that entire parenthetical expression will be a bunch of computer names, not computer objects—and computer names are exactly what the -computername parameter wants to see.

By the way, just to be complete, I should mention that the -filter parameter of Get-ADComputer specifies that all computers should be included in the command’s output. The -searchBase parameter tells the command to start looking for computers in the specified location—in this case, the Sales OU of the company.pri domain. The Get-ADComputer command is only available on Windows Server 2008 R2 and on Windows 7 after installing the Remote Administration Server Toolkit (RSAT). On those operating systems, you have to run Import-Module ActiveDirectory to actually load the Active Directory cmdlets into the shell so that they can be used.

Ideas for on your own

One of the Windows PowerShell modules included in Windows 7 is Troubleshooting Pack, which provides command-line access to the new troubleshooting pack functionality in the operating system. I always tell my students and clients to consider enabling Windows PowerShell remoting on all of their client computers, in part because it gives you remote command-line access to those troubleshooting packs. When a user calls for help, rather than walking them through a wizard over the phone, you can just remote in and run the same wizard, in command-line form rather than GUI form, yourself.

Guest Writer’s Week will continue tomorrow when we will have a post from Richard Siddaway.

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

Ed Wilson, Microsoft Scripting Guy