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
0 comments