Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell Splatting the Argumentlist on Invoke-Command

How is it possible to use the parameters collected in a hash table for use with ArgumentList on Invoke-Command?

$CopyParams = @{
    Source      = 'E:\DEPARTMENTS\CBR\SHARE\Target'
    Destination = 'E:\DEPARTMENTS\CBR\SHARE\Target 2'
    Structure   = 'yyyy-MM-dd'
}
Invoke-Command -Credential $Cred -ComputerName 'SERVER' -ScriptBlock ${Function:Copy-FilesHC} -ArgumentList @CopyParams

Whatever I try, it's always complaining about the 'Source':

Cannot validate argument on parameter 'Source'. The "Test-Path $_" validation script for the argument with
 value "System.Collections.Hashtable" did not return true. Determine why the validation script failed

This blog talks about a similar problem, but I can't get it to work.

The same is true for a simple Copy-Item within Invoke-Command, example:

Invoke-Command -Credential $Cred -ComputerName 'SERVER' -ScriptBlock {Copy-Item} -ArgumentList @CopyParams

Invoke-Command : Missing an argument for parameter 'ArgumentList'. Specify a parameter of type 'System.Obj
ect[]' and try again.
At line:11 char:89
+ ... ck {Copy-Item} -ArgumentList @CopyParams

Thank you for your help.

like image 357
DarkLite1 Avatar asked Jan 30 '15 11:01

DarkLite1


People also ask

How do you use splatting in PowerShell?

Here is the basic syntax for using splatting. You use the regular PowerShell command ( <CommandName> ) followed by the variable name indicating the splatted values ( @<SplattedValues> ). Not all parameters need to be included in the splat. You can pass other parameters ( <parameters> ) before or after the splat.

What does invoke-command do in PowerShell?

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 ArgumentList in PowerShell?

-ArgumentListSpecifies parameters or parameter values to use when this cmdlet starts the process. Arguments can be accepted as a single string with the arguments separated by spaces, or as an array of strings separated by commas.

How do I run a PowerShell script from the command line?

To run a script on one or many remote computers, use the FilePath parameter of the Invoke-Command cmdlet. The script must be on or accessible to your local computer. The results are returned to your local computer. For example, the following command runs the DiskCollect.


2 Answers

One-liner, to convert a remote script to accept named parameters from a hash.

Given a scriptblock which you wish to call like this:

$Options = @{
    Parameter1 = "foo"
    Parameter2 = "bar"
}

Invoke-Command -ComputerName REMOTESERVER -ArgumentList $Options -ScriptBlock {
    param(
        $Parameter1,
        $Parameter2
    )
    #Script goes here, this is just a sample
    "ComputerName: $ENV:COMPUTERNAME"
    "Parameter1: $Parameter1"
    "Parameter2: $Parameter2"
} 

You can convert it like so

Invoke-Command -Computername REMOTESERVER -ArgumentList $Options -ScriptBlock {param($Options)&{
    param(
        $Parameter1,
        $Parameter2
    )
    #Script goes here, this is just a sample
    "ComputerName: $ENV:COMPUTERNAME"
    "Parameter1: $Parameter1"
    "Parameter2: $Parameter2"
} @Options}

What's going on? Essentially we've wrapped the original script block like so:

{param($Options)& <# Original script block (including {} braces)#> @options }

This makes the original script block an anonymous function, and creates the outer script block which has a parameter $Options, which does nothing but call the inner script block, passing @options to splat the hash.

like image 174
Ben Avatar answered Nov 03 '22 00:11

Ben


Here's one way to approach passing named parameters:

function Copy-FilesHC 
{
  param ($Source,$Destination,$Structure)
  "Source is $Source"
  "Desintation is $Destination"
  "Structure is $Structure"
  }


$CopyParams = @{
    Source      = 'E:\DEPARTMENTS\CBR\SHARE\Target'
    Destination = "'E:\DEPARTMENTS\CBR\SHARE\Target 2'" #Nested quotes required due to embedded space in value.
    Structure   = 'yyyy-MM-dd'
}

$SB = [scriptblock]::Create(".{${Function:Copy-FilesHC}} $(&{$args}@CopyParams)")

Invoke-Command -Credential $Cred -ComputerName 'SERVER' -ScriptBlock $SB

Basically, you create a new script block from your invoked script, with the parameters splatted to that from the hash table. Everything is already in the script block with the values expanded, so there's no argument list to pass.

like image 44
mjolinor Avatar answered Nov 03 '22 02:11

mjolinor