How to pass arguments for remote commands

When invoking remote commands, one often wants to use local values as arguments to the remote command. This post explains how to do that.

Hardcoded values

Let’s start with a simple example. Below you can see how Get-Process is invoked in a remote session when the Id parameter is set to 0:

PS> $s = New-PSSession -Computer localhost
PS> Invoke-Command -Session $s -Script { Get-Process -Id 0 }
 
Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName     PSComputerName
-------  ------    -----      ----- -----   ------     -- -----------     --------------
      0       0        0         24     0               0 Idle            localhost

Passing local values

What if we want to calculate the value of the Id parameter programmatically, instead of hard-coding it to a particular integer? Well, script blocks can declare parameters and the param block can be used to pass a value to the command that is being invoked. In the following example, we declare the $processId parameter in the script block and then use the Args parameter of Invoke-Command to set the value of $processId to $pid, which is the process ID of the current Windows PowerShell process.

PS> $s = New-PSSession -ComputerName localhost
PS> Invoke-Command -Session $s -Script { param($processId) Get-Process -Id $processId } -Args $pid
 
Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName     PSComputerName
-------  ------    -----      ----- -----   ------     -- -----------     --------------
    533      13    46160      37456   198     6.07   9488 powershell      localhost

The example above demonstrates that Get-Process was invoked with a process id of the local Windows PowerShell console.  Invoke-Command takes whatever you pass in the Args parameter and binds it to script block’s parameters in the remote session. Note that above I simply passed in a value of a local $pid variable, but any local expression (not just a simple variable dereference) can be used instead.

Referring to remote variables

A different behavior takes place when you don’t declare script block parameters using the "param" keyword:

PS> $s = New-PSSession -ComputerName localhost
PS> Invoke-Command -Session $s -Script { Get-Process -Id $pid }
 
Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName     PSComputerName
-------  ------    -----      ----- -----   ------     -- -----------     --------------
    329      10    21216      33524   154     7.63   6596 wsmprovhost     localhost

In this case $pid is an unbound variable and Windows PowerShell assumes that it refers to the $pid variable in the remote session. Therefore, as you can see Get-Process returns the process that hosts the remote session.

Magic $args variable

What happens when you use the Args parameter of Invoke-Command cmdlet, but don’t declare any parameters in the script block? Local values are still passed to the remote session and in this case are bound to the $args variable. This can save some typing:

PS> $s = New-PSSession -ComputerName localhost
PS> Invoke-Command -Session $s -Script { Get-Process -Id $args[0] } -Args $pid

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName                    PSComputerName
-------  ------    -----      ----- -----   ------     -- -----------                    --------------
    808      46    76840      81876   596     5.05   7824 powershell                     localhost

Thanks,

Lukasz Anforowicz [MSFT]

Windows PowerShell Developer

Microsoft Corporation