Windows PowerShell 1.0 was a dramatic leap forward for the management and automation of Windows XP and later versions of the Windows OS platform. Based on the .NET Framework, PowerShell 1.0 has a consistent command structure (cmdlets), provides powerful built-in output formatting, and makes other technologies, particularly Windows Management Instrumentation (WMI), much more accessible. However, while some PowerShell 1.0 cmdlets and .NET objects can connect to remote computers, this capability is implemented on a case-by-case basis. Those cmdlets that support remote connections have a -ComputerName parameter, and they use either remote procedure calls (RPCs) or DCOM to make the connections.

While RPCs and DCOM work well in many management scenarios, it can be challenging to diagnose and troubleshoot problems. For example, the Get-Service cmdlet can retrieve services from a remote computer using the -ComputerName parameter, but the cmdlet doesn't have a -Credential parameter, so you must run it while logged on with an account that has permissions on the remote system.

Starting with Windows PowerShell 2.0, there's an alternative way to connect to remote computers called remoting. Remoting is based on the Windows Remote Management (WinRM) service. It lets you connect to a remote computer and run commands that execute on the remote computer. By way of analogy: As remote desktop is to GUI management, remoting is to the PowerShell command line. When you use remoting to run a cmdlet, the cmdlet actually runs on the remote computer but you can see the results on the local computer.

 

Getting Windows PowerShell 2.0

PowerShell 2.0 and the WinRM service are included with Windows 7 and Windows Server 2008 R2, so there's no separate installation needed on those OSs. For Windows Vista SP2, XP SP3, Windows Server 2008 SP2, and Windows Server 2003 SP2, you need to download and install the Windows Management Framework Core package.

 

Enabling Remoting

Before a computer will accept remote PowerShell connections, the following list of items must be in place:

  1. The WinRM service must be running.
  2. There must be a WinRM listener that accepts connections from one or more IP addresses.
  3. The Windows firewall must be configured to allow the WinRM connection.
  4. There must be an enabled and properly configured PowerShell session.

(If a computer won't be accepting remote PowerShell connections, these items don't apply.)

To help you get started quickly, the Microsoft PowerShell team created the Enable-PSRemoting cmdlet to automatically configure these items for you. You need to perform this configuration on the computer that you'll be accessing remotely, not the computer from which you'll perform the remoting. To run Enable-PSRemoting, you need to be running PowerShell as an administrator. (On Vista and Server 2008 and later, right-click the PowerShell icon and select Run as administrator.) If you include the -Force parameter, the Enable-PSRemoting cmdlet runs without prompting for permission to complete each configuration step. To get more information about the Enable-PSRemoting cmdlet, run the command

Get-Help Enable-PSRemoting

Running a Single Command on a Remote Computer

The simplest way to connect to PowerShell on a remote computer is to use the Enter-PSSession cmdlet. The cmdlet's default parameter is -ComputerName, so you can omit the parameter name when you type the command. For example, to connect to a remote computer named rigel, you'd type

PS C:\> Enter-PSSession rigel

(Note that I'm including the prompt for completeness. You wouldn't type the prompt as part of the command.) After you enter a remote session, the PowerShell prompt changes to include the remote computer's name in square brackets to show that you're now connected to a remote computer. In this case, the prompt would read 

\\[rigel\\]: PS C:\>

Once you're connected remotely, any commands you enter at the prompt are executed on the remote computer. For example, if you enter the command

\\[rigel\\]: PS C:\> Get-ChildItem C:\

the Get-ChildItem cmdlet executes on the remote computer. Its output will contain the files and folders on the remote computer's C drive. To exit the remote session, you use the Exit-PSSession cmdlet, as in 

\\[rigel\\]: PS C:\> Exit-PSSession

Running a Scriptblock on a Remote Computer

PowerShell remoting supports running a scriptblock (i.e., a block of PowerShell code surrounded by curly braces) on a remote computer. To do so, you use the Invoke-Command cmdlet with the -ComputerName parameter. For example, in the command shown in Figure 1, I used the Invoke-Command cmdlet to execute a Get-ChildItem command on a remote computer. In Figure 1, notice that I didn't use Enter-PSSession to first connect to the remote computer before running the scriptblock. Using Enter-PSSession and using Invoke-Command are two distinct ways to remote.

The Invoke-Command cmdlet's first parameter is -ScriptBlock, which specifies the code you want to run. In Figure 1, I omitted the -ScriptBlock parameter name because it's optional. The -ComputerName parameter specifies the remote computer's name. As the Get-ChildItem cmdlet's output shows, PowerShell even adds the remote computer's name in the PSComputerName column to the output for your convenience.

 

Running a Scriptblock on Multiple Remote Computers

You can also run a scriptblock on multiple remote computers. This is referred to as a 1-to-many or fan-out configuration. Although the Invoke-Command cmdlet's -ComputerName parameter is shown with a single computer name in Figure 1, it can support multiple computer names. For example, the command 

PS C:\> Invoke-Command<br>  \\{ Get-ChildItem env:co* \\}<br>  -Computer titan,rigel

executes the Get-ChildItem cmdlet on two remote computers. (Although this command wraps here, you'd enter it all on one line in the PowerShell console. The same holds true for the other commands that wrap.) Just as in Figure 1, the PSComputerName column in the output will contain the computer names.

Running a Scriptblock as a Background Job

PowerShell 2.0 supports background jobs, which let you run a command in the background. This capability can be useful for commands that take a long time to run.

To start a background job on the local computer, you can use the Start-Job cmdlet. However, this cmdlet doesn't have a -ComputerName parameter, which means you can't use it to run a background job on a remote computer. Instead, you need to use the Invoke-Command cmdlet with the -AsJob parameter. For example, the topmost command in Figure 2 runs a scriptblock as a background job on the titan remote computer.

After I entered this command, the prompt appeared right away, as PowerShell dispatched the scriptblock to run on the remote computer and returned control to me afterward. The warning message indicates that the executed command didn't fit in the console window, so it wasn't included in the output. If I would've had a wider console window, the PowerShell output formatter would've listed the command as well. The Id and Name columns identify the job by ID and friendly name, respectively, and the State column indicates whether the job is still running, paused, or completed. The HasMoreData column tells you whether all the data was retrieved from the job or whether the job has more data that needs to be retrieved.

To check whether a background job has completed, you can use the Get-Job cmdlet, as the second command in Figure 2 shows. When you don't include any parameters, Get-Job checks the status of all the jobs that were started in the current session. If you have many jobs running, you can use parameters such as -Id or -Name to specify which job you want to check. When a background job is finished, the State column in the output will read Completed.

To retrieve a background job's results, you can use the Receive-Job cmdlet. Like Get-Job, Receive-Job returns the output from all the jobs that were started in the current session, unless you use a parameter to specify which job. For example, the last command in Figure 2 uses the -Id parameter to get the output from the job whose ID is 9. (I omitted the -Id parameter name because it's optional.) Figure 3 shows the end of the output from this remote background job.

 

Creating PowerShell Sessions

The previous remoting examples showed how to access a PowerShell prompt on a remote computer and how to run commands on remote computers. What I haven't mentioneded yet is that remoting always occurs in the context of a session. A session is where PowerShell lives. When you open a PowerShell console window or PowerShell's Integrated Scripting Environment (ISE), you're creating a session. Without remoting, all sessions run on the local computer and are independent of one another. All the previous examples of remoting create temporary sessions, which are automatically discarded when the remoting is completed. You can also create remote session instances and reuse them, which is much more efficient when you need to access remote computers more than once.

To create new sessions, you use the New-PSSession cmdlet with the -ComputerName parameter. (You can omit the parameter name in commands.) For example, the command

<p>C:\> $sessions =<br>  New-PSSession phineas,ferb,perry</p>

creates three sessions on the three computers named phineas, ferb, and perry. You can view the sessions by outputting the $sessions variable. Just type

$sessions

at the prompt and press Enter. The Invoke-Command cmdlet's -Session parameter supports the session objects created by New-PSSession, so you can then use a command such as 

C:\> Invoke-Command \\{ Get-ChildItem \\}<br>  -session $sessions

This command executes the Get-ChildItem cmdlet on phineas, ferb, and perry, but doesn't close the connections. You can add the -AsJob parameter to run the command in the background, as in

C:\> Invoke-Command \\{ Get-ChildItem \\}<br>  -session $sessions -asjob

You can then use the Get-Job and Receive-Job cmdlets to check the job's status and receive its output.

 

A New Way to Work

PowerShell remoting is a new and powerful way to run commands on remote computers. I hope this demonstration whets your appetite for the new possibilities it provides. For more information about remoting, including troubleshooting, see the PowerShell about_Remote Help topics.