MagicGuru
MagicGuru

Reputation: 175

Passing array to one of named parameters in script block?

I am trying to figure out a way to pass an array to a named parameter in a separate script. However, I could not find any solution.

Test2.ps1:

param(
    [int]$a,
    [int]$b,
    [int]$c,
    [string[]]$d
)

write-host "`$a = $a"
write-host "`$b = $b"
write-host "`$c = $c"
write-host "`$d:" -nonewline
foreach($str in $d) {
    write-host " $str" -nonewline
}
write-host

Main script:

$arr = @("abc", "def", "ghi")
$params = @{
    a = 1;
    b = 2;
    c = 3;
    d = $arr
}

#invoke-command -filepath "test2.ps1" -ArgumentList 1,2,3,@("abc", "def", "ghi")
$scriptPath = "test2.ps1"
$sb = [scriptblock]::create(".{$(get-content $ScriptPath -Raw)} $(&{$args} @params)")
invoke-command -scriptblock $sb

When executed, I got output that

$d:System.Object[]

The line below was copied from another Stackoverflow answer but I don't quite understand how it worked for the first 3 named parameters.

$sb = [scriptblock]::create(".{$(get-content $ScriptPath -Raw)} $(&{$args} @params)")

Especially the "$(&{$args} @params)" part. I have basic understanding of splatting, but this is beyond me. Much appreciated if someone can explain the syntax a bit for me.

Upvotes: 0

Views: 1475

Answers (1)

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174435

When you put @params inside an expandable string, you're forcing the parser to convert the resulting output to a string, and the default behavior of ToString() (if not overridden) is to just return the type name of the object in question.

Simply wait until you call the script before you supply the parameters:

$sb = [scriptblock]::Create("$(get-content $ScriptPath -Raw)")
& $sb $args @params

or, if you want to dot-source the script with specific parameters:

$sb = [scriptblock]::Create("$(get-content $ScriptPath -Raw)")
& {.$sb $args @params}

Upvotes: 1

Related Questions