Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pass named parameters with Invoke-Command?

I have a script that I can run remotely via Invoke-Command

Invoke-Command -ComputerName (Get-Content C:\Scripts\Servers.txt) `                -FilePath C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 

As long as I use default parameters, it works fine. However, the script has 2 named [switch] parameters (-Debug and -Clear)

How can I pass the switched parameters via the Invoke-Command? I've tried the -ArgumentList but I'm getting errors so I must have the syntax wrong or something. Any help is greatly appreciated.

like image 236
Sean Avatar asked Nov 19 '10 14:11

Sean


People also ask

How do you pass arguments to invoke a command?

To pass the argument in the Invoke-command, you need to use -ArgumentList parameter. For example, we need to get the notepad process information on the remote server.

How does invoke-command work?

The Invoke-Command cmdlet runs commands on a local or remote computer and returns all output from the commands, including errors. Using a single Invoke-Command command, you can run commands on multiple computers. To run a single command on a remote computer, use the ComputerName parameter.

What is the easiest way to pass locally defined variables to a remote system when using invoke-command?

One way to pass local variables to a remote scriptblock is to use the Invoke-Command ArgumentList parameter. This parameter allows you to pass local variables to the parameter and replace local variable references in the scriptblock with placeholders. Passing the local variables to the ArgumentList parameter is easy.

How do I call a PowerShell script with parameters?

You can run scripts with parameters in any context by simply specifying them while running the PowerShell executable like powershell.exe -Parameter 'Foo' -Parameter2 'Bar' . Once you open cmd.exe, you can execute a PowerShell script like below.


1 Answers

-ArgumentList is based on use with scriptblock commands, like:

Invoke-Command -Cn (gc Servers.txt) {param($Debug=$False, $Clear=$False) C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 } -ArgumentList $False,$True 

When you call it with a -File it still passes the parameters like a dumb splatted array. I've submitted a feature request to have that added to the command (please vote that up).

So, you have two options:

If you have a script that looked like this, in a network location accessible from the remote machine (note that -Debug is implied because when I use the Parameter attribute, the script gets CmdletBinding implicitly, and thus, all of the common parameters):

param(    [Parameter(Position=0)]    $one ,    [Parameter(Position=1)]    $two ,    [Parameter()]    [Switch]$Clear )  "The test is for '$one' and '$two' ... and we $(if($DebugPreference -ne 'SilentlyContinue'){"will"}else{"won't"}) run in debug mode, and we $(if($Clear){"will"}else{"won't"}) clear the logs after." 

Without getting hung up on the meaning of $Clear ... if you wanted to invoke that you could use either of the following Invoke-Command syntaxes:

icm -cn (gc Servers.txt) {      param($one,$two,$Debug=$False,$Clear=$False)     C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 @PSBoundParameters } -ArgumentList "uno", "dos", $false, $true 

In that one, I'm duplicating ALL the parameters I care about in the scriptblock so I can pass values. If I can hard-code them (which is what I actually did), there's no need to do that and use PSBoundParameters, I can just pass the ones I need to. In the second example below I'm going to pass the $Clear one, just to demonstrate how to pass switch parameters:

icm -cn $Env:ComputerName {      param([bool]$Clear)     C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 "uno" "dos" -Debug -Clear:$Clear } -ArgumentList $(Test-Path $Profile) 

The other option

If the script is on your local machine, and you don't want to change the parameters to be positional, or you want to specify parameters that are common parameters (so you can't control them) you will want to get the content of that script and embed it in your scriptblock:

$script = [scriptblock]::create( @" param(`$one,`$two,`$Debug=`$False,`$Clear=`$False) &{ $(Get-Content C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -delimiter ([char]0)) } @PSBoundParameters "@ )  Invoke-Command -Script $script -Args "uno", "dos", $false, $true 

PostScript:

If you really need to pass in a variable for the script name, what you'd do will depend on whether the variable is defined locally or remotely. In general, if you have a variable $Script or an environment variable $Env:Script with the name of a script, you can execute it with the call operator (&): &$Script or &$Env:Script

If it's an environment variable that's already defined on the remote computer, that's all there is to it. If it's a local variable, then you'll have to pass it to the remote script block:

Invoke-Command -cn $Env:ComputerName {      param([String]$Script, [bool]$Clear)     & $ScriptPath "uno" "dos" -Debug -Clear:$Clear } -ArgumentList $ScriptPath, (Test-Path $Profile) 
like image 100
Jaykul Avatar answered Oct 13 '22 18:10

Jaykul