In Powershell, how to pass $args of type string[] to a "function param()"... see code below, it doesn't work...
(Note: I dont want to pass a hash @{} of type Hashtable to the function as required by splatting. I want to pass a string[] type as arguments to function param)...
# FILE: run1.ps1
function run1{
param(
[switch]$go,
[string]$sim,
[switch]$rec
)
write-host "go: $go"
write-host "sim: $sim"
write-host "rec: $rec"
}
write-host ""
foreach ($a in $args) {
write-host "a: $a"
}
write-host ""
run1 $args
PS> ./run1.ps1
a: -go
a: -rec:
a: dfsdf
a: -rec
go: False
sim: -go -rec: dfsdf -rec
rec: False
CodePudding user response:
Instead of run1 $args, use run1 @args, i.e. splatting with the automatic $args variable.
That way, whatever arguments are passed to the run1.ps1 script - whether named or positional - are correctly passed through to the run1 function.
- Caveat: This does not work for pass-through
[switch]arguments with an explicit value (which is rare, however). For instance, if you were to invokerun1.ps1with-rec:$false(instead of simply omitting this argument),-recand$falsewould mistakenly be passed as two arguments, and$recwould end up being$true.
Note:
No user-defined array can provide this functionality[1] - the automatic
$argsarray has magic built in that enables this functionality; splatting with a user-defined array only supports passing positional arguments through, and that wouldn't work in your case, because[switch]parameters are always named (non-positional).For splatting based on user-defined variables that supports passing named arguments, hashtable-based splatting is necessary.
As an aside:
If you make your function an advanced one (in the simplest case by decorating the
param(...)block with[CmdletBinding()]), it'll ensure that no extra arguments are passed (ones that don't bind to predefined parameters), for added robustness.If you additionally make your script an advanced one - which requires defining parameters explicitly for the script itself too - you can pass the script's parameter values through via the automatic
$PSBoundParametersvariable variable, i.e. withrun1 @PSBoundParameters. This would also avoid the[switch]-related bug mentioned above.
[1] As Santiago Squarzon points out, there a limited way to make this work, but it is both highly obscure and more cumbersome than using a hashtable for splatting and therefore not worth considering.
For the sake of completeness: To have an array element represent a parameter name, use a dummy string decorated with a NoteProperty member literally named <CommandParameterName> whose value is the target parameter name (with or without the - prefix). A minimal example that is the equivalent of
Get-ChildItem -Directory -LiteralPath \:
$arr = ('' | Add-Member -PassThru '<CommandParameterName>' 'Directory'), ('' | Add-Member -PassThru '<CommandParameterName>' 'LiteralPath'), '\'; Get-ChildItem @arr
CodePudding user response:
function run1{
param(
[switch]$go,
[string]$sim,
[switch]$rec
)
write-host "go: $go"
write-host "sim: $sim"
write-host "rec: $rec"
}
$cmd = "run1 $args"
write-host "cmd: $cmd"
invoke-expression "$cmd"
PS> run1.ps1 -go -sim:asdfasdf rec
PS> run1.ps1 -go -sim:asdfasdf -rec
