Join the Social

The information in this article was written about the Community Technology Preview (CTP) of Windows PowerShell 2.0. This information is subject to change in future releases of Windows PowerShell 2.0.

On This Page

Windows PowerShell 2.0: Join the Social Run a Remote Command: Invoke-Expression Run Remote Commands on Multiple Computers Create a Persistent Connection: Runspace Display the Originating Machine Tell Me More

Windows PowerShell 2.0: Join the Social

By June Blender

Windows PowerShell Documentation Team

I am not a social animal -- not like the Scripting Guys. I don't travel the world giving out bobbleheads or flaunt my style on Channel 9. No, I prefer to sit at my desk quietly typing Windows PowerShell commands into a little blue box in perfect anonymity.

But when I need to administer a group of remote computers, I want Windows PowerShell to be social. It needs to communicate with remote computers, so I don't have to communicate with users. Now, finally, with Windows PowerShell 2.0 CTP, I have achieved my dream of permanent reclusiveness. I can run commands on all of the remote computers I administer without ever leaving my little blue window.

If you haven't yet downloaded and configured your Windows PowerShell 2.0 CTP, do so immediately, or risk social alienation in your domain. Instructions are here.

WARNING: Windows PowerShell 2.0 CTP is just a preview (That's the P in CTP). The final version of Windows PowerShell 2.0 might be significantly different.

Now, as to remoting…

Run a Remote Command: Invoke-Expression

The first thing to learn about Windows PowerShell remoting is the Invoke-Expression cmdlet. Invoke-Expression is included in Windows PowerShell 1.0 to, um, invoke expressions, but it has taken on a whole new life in Windows PowerShell 2.0 CTP.

Let's start with a familiar "get-process" command, the one that gets objects representing each of the processes on your local computer.

get-process

To run the command on a remote computer, imbed the "get-process" command in an Invoke-Expression command. Assign this command to the value of the Command parameter of Invoke-Expression, then type the name of the remote computer in the value of the ComputerName parameter.

invoke-expression -computername Server01 -command get-process

Or, if you like the keystroke-saving shortcuts, use this equivalent command. The alias for Invoke-Expression is iex and the –Command parameter has position 1. You only need to type enough of the name of the ComputerName parameter to distinguish it from –Command.

iex -comp Server01 get-process

The result is a list of processes on the Server01 computer:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    113       4    13520      11820    58            1124 audiodg
   5951       7     3532       6492    77 1,141.79   1708 casha
    732      15    11536      13552    96     9.87   2068 CcmExec
...

The value of the Command parameter of Invoke-Expression must be a string, so if the command contains spaces or special characters, enclose the command in quotation marks.

This command gets only the PowerShell process on the Server01 computer.

invoke-expression -computername Server01 -command 'get-process powershell'

Here's the result.

Handles  NPM(K)    PM(K)   WS(K)   VM(M)   CPU(s)     Id ProcessName
-------  ------    -----   -----   -----   ------     -- -----------
        261       8    30476   28084     158     2.42   2364   powershell

Now, let's try running a remote command on more than one computer.

Run Remote Commands on Multiple Computers

To run commands on multiple computers with a single Windows PowerShell command, list the computer names in the value of the ComputerName parameter of Invoke-Expression. Separate the computer names with commas.

The following command runs the "Get-Process PowerShell" command on three remote computers, Server01, Server02, and Server03.

invoke-expression -computername Server01, Server02, Server03 -command 'get-process powershell'

Here's the output:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    696      18    42780      39268   159     3.88   1208 powershell
    227       7    29660      26564   133     2.47   3420 powershell
    262       8    30420      28036   158     2.59    284 powershell

You can also save the computer names in a variable and submit the variable as the value of the ComputerName parameter.

$a = "Server01", "Server02", "Server03"



invoke-expression -computername $a -command 'get-process powershell'

Or, if you have numerous computer names, read the computer names from a .txt file. In the file, place each computer name on a separate line. Then, use the Get-Content cmdlet to read the file. This command runs the "Get-Process PowerShell" command on all of the computers listed in the Servers.txt file.

invoke-expression -computername (get-content servers.txt) -command 'get-process powershell'

You can import the computer names from a spreadsheet, too.

invoke-expression -computername (import-csv servers.csv) -command 'get-process powershell'

To include the local computer in the list of computers, add the computer name or "localhost" to the value of the –ComputerName parameter. The following command gets the PowerShell processes on the local computer and on Server01.

invoke-expression -computername localhost, Server01  -command 'get-process powershell'

Here's the output:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
        865      18    41704      38488   165     4.86   1208 powershell
        227       7    29660      26564   133     2.38   2776 powershell

When you run a command on multiple computers, Windows PowerShell establishes a connection to each of the computers, runs the command on the computer, and then closes the connection.

But what if you need to run multiple commands that use the same data?

Create a Persistent Connection: Runspace

If you run a single command, or multiple, unrelated commands, the previous method works fine. But if you try something like this, it fails.

invoke-expression -computername Server01 -command '$a = "powershell"'

invoke-expression -computername Server01 -command 'get-process $a'

Invoke-Expression : The argument cannot be null or empty.
At line:1 char:4
+ iex <<<<  -computername juneb-testv -command 'get-process $a'

This method fails because each time you submit a remote command, Windows PowerShell establishes a connection, runs the command, and then closes the connection. The $a variable was set to "PowerShell" in one connection and the Get-Process command ran in a different connection. In the connection that Get-Process ran, the $a variable was not defined.

To run related commands that share data, such as the value of a variable, you need to establish a persistent connection to the remote computer. To do this, you establish a runspace on the remote computer. A runspace is like a separate Windows PowerShell environment on the remote computer. When you create a runspace, you can run multiple commands in the runspace, because the runspace persists until you delete it.

To create a runspace, use the New-Runspace cmdlet. This command creates a runspace on the Server01 remote computer and saves an object representing the runspace in the $r variable.

$r = new-runspace -computername Server01

If you display the value of the $r variable, you can see the runspace.

$r

Here's the output:

ComputerName    State    ShellName
------------    -----    ---------
Server01        Opened   Microsoft.PowerShell

To run commands in your runspace, use the Invoke-Expression command with the Runspace parameter. Together, these two commands get the PowerShell process on Server01.

invoke-expression -runspace $r -command ' $a = "powershell" '

invoke-expression -runspace $r -command 'get-process $a'

Here's the output:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    270       8    30532      28172   157     2.51   3696 powershell

In other words, a persistent runspace is very useful. You can create runspaces on multiple machines with a single command. But that leads to a new question…

Display the Originating Machine

One of the trickier parts of remote computing on Windows PowerShell 1.0 CTP is distinguishing the output from different computers. The following command gets the WinRm service on three different computers: the local computer ("localhost") and two remote computers, cleverly named Server01 and Server02.

invoke-expression -computername localhost, Server01, Server02 -command 'get-service winrm'

Here's the output:

Status   Name               DisplayName
------   ----               -----------
Running  WinRM              Windows Remote Management (WS-Manag...
Running  WinRM              Windows Remote Management (WS-Manag...
Running  WinRM              Windows Remote Management (WS-Manag...

Apparently, the command was successful, but what is not apparent is where the data came from. Which service is running on which computer?

To find originating computer, use the Format-Table cmdlet to add the the PsipHostEntry property to the display. This property contains the name of the remote computer.

invoke-expression -computer localhost, server01, server02 -command 'get-service winrm' |
format-table -property Status, Name, DisplayName, PsIPHostEntry

Here's the output:

Status    Name    DisplayName                           PsIPHostEntry
------    ----    -----------                           -------------
Running   WinRM   Windows Remote Management (WS-Mana...   Admin01
Running   WinRM   Windows Remote Management (WS-Mana...   Server01
Running   WinRM   Windows Remote Management (WS-Mana...   Server02

PsIPHostEntry is one of three properties that are added to objects returned from remote computers. (The other two are RunspaceID and Pipeline.)

Well, that's more than enough human interaction for me today.

Tell Me More

Okay, but this is just an introduction. You can learn more about remoting in Windows PowerShell 2.0 CTP, by reading the Windows PowerShell 2.0 CTP help.

Start with the conceptual docs:

get-help about_remoting
get-help about_runspace

You can also read about the new cmdlets:

get-help invoke-expression -full
get-help new-runspace -full

And don't forget to send the examples to Notepad, where you can look at them carefully.

get-help invoke-expression -examples | out-file tmp.txt | notepad tmp.txt