简体   繁体   中英

How to pass named parameters to another script in powershell

I want to pass all parameters from one powershell script to another script without knowing the named parameters. That other script is out of my control and I can not predict all the parameters it takes.

Example wrapper: wrapper.ps1

Set-StrictMode -v 2
$ErrorActionPreference="Stop"

write-host "ArgsIn:" $Args

$mypath= Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
$Cmd, $NewArgs =$Args | foreach { $_ -replace "one",'two' }
$Cmd = $mypath+"\"+$Cmd

write-host "Running:" $Cmd $NewArgs

& $Cmd @NewArgs
exit $LastExitCode 

Example called script: test.ps1 )

Param(
  [Parameter(Mandatory=$false)] [string]$BAR,
  [Parameter(Mandatory=$false)] [string]$FOO
)

write-host "test: Args:" $Args
write-host "FOO" $FOO
write-host "BAR" $BAR

exit 0 

If I call test.ps1 it works as expected:

PS C:\Test> .\test.ps1 -foo one -bar three
test: Args:
FOO one
BAR three

But if I try it via the wrapper, it maps the parameters positionally instead.

PS C:\Test> .\wrapper.ps1 test.ps1 -foo one
ArgsIn: test.ps1 -foo one
Running: C:\Test\test.ps1 -foo two
test: Args: test.ps1 -foo one
FOO two
BAR -foo

I have tried various alternative forms to call the script (including invoke-command and invoke-expression ).

One way that appeared to work was using

invoke-expression "& `"$Cmd`" $NewArgs" 

but that breaks as soon as any parameter contains a space:

PS C:\Test> .\wrapper.ps1 test.ps1 -foo "one three"
ArgsIn: test.ps1 -foo one three
Running: C:\Test\test.ps1 -foo two three
test: Args:
FOO two
BAR three

Is there any sensible way to do what I want?

I actually stumbled on something that works:

 & powershell.exe -file $Cmd @NewArgs 

But it feels ugly to call a second powershell instance to do what I need.

Maybe there is a cleaner version.

Excerpt from the About Splatting Syntax :

To provide parameter values for positional parameters, in which parameter names are not required, use the array syntax. To provide parameter name and value pairs, use the hash table syntax. The splatted value can appear anywhere in the parameter list.

In other words, if want to pass named parameters, you should splat your parameters as a hash table (rather than a array). Something like:

[CmdletBinding()] Param (
    $Cmd,
    [parameter(ValueFromRemainingArguments=$true)]$RemainingArguments
)
Set-StrictMode -v 2
$ErrorActionPreference="Stop"

$Cmd = $PSScriptRoot + '\' + $Cmd
$ArgName = $Null; $NewArgs = @{}
ForEach ($Arg in $RemainingArguments) {
    If ($Arg.StartsWith('-')) {$ArgName = $Arg.SubString(1)}
    ElseIf ($ArgName) {$NewArgs[$ArgName] = $Arg}
}

# $NewArgs['Foo'] = 'Three test'

write-host "Running:" $Cmd $NewArgs 

& $Cmd @NewArgs

Result:

PS C:\> .\wrapper.ps1 test.ps1 -foo 'one three'
Running: C:\...\test.ps1 System.Collections.DictionaryEntry
test: Args:
FOO one three
BAR

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM