Wrapper function in PowerShell: Pass remaining parameters

后端 未结 3 1477
旧巷少年郎
旧巷少年郎 2021-01-02 03:37

I’m trying to write a wrapper function in PowerShell that basically evaluates the first parameter and based on that runs a program on the computer. All the remaining paramet

相关标签:
3条回答
  • 2021-01-02 03:43
    • Your solution works as-is for external programs (such as your C:\Program Files\some\program.exe example): you can always pass an array of values (which is what $args is) to an external program, and its elements will be passed as individual arguments (stringified, if necessary).

    • You can make your solution work with any command if you change $args to @args[1], to take advantage of a PowerShell parameter-passing technique called splatting:

    function test ( [string] $option )
    {
        if ( $option -eq 'A' )
        {
            Write-Host $args
        }
        elseif ( $option -eq 'B' )
        {
            # Use @args to also support passing *named* arguments
            # through to *PowerShell* commands.
            & $someCommand @args
        }
    }
    

    Caveats:

    • The automatic $args variable, which collects all arguments for which no parameter was declared, is only available in simple (non-advanced) functions and scripts; advanced functions and scripts - those that use the [CmdletBinding()] attribute and/or [Parameter()] attributes - require that all potential parameters be declared.

    • PowerShell has built-in magic that makes the automatic array variable $args also support passing named parameters through via splatting, which no custom array or collection supports.

      • By contrast, custom arrays and collections only support splatting positional (unnamed) arguments, which, however, covers all calls to external programs.
      • When calling PowerShell commands, this limitation is problematic, however: For instance, if you wanted to pass the named argument -Path C:\ through to the Set-Location cmdlet via splatting, using a custom collection parameter declared via ValueFromRemaining Arguments, as shown in OldFart's answer (Set-Location @Remaining), would not work; to support passing through named arguments (other than via @args, if available), you must use hashtable-based splatting.

    Therefore, if your function is an advanced one and you need to support passing named arguments through to other PowerShell commands, a different approach is required: this answer shows two alternatives.


    [1] With external programs, there is a corner case where @args behaves differently from $args, namely if the $args array contains --%, the stop-parsing symbol: @args recognizes it, $args treats it as a literal.

    0 讨论(0)
  • 2021-01-02 03:54

    What you have written does work. Note that what is there is $args is the unnamed arguments that are over and above the parameters expected by the function.

    So if you call test as

    test -option "A" 1 2 3
    

    $args will have 1,2,3

    Note that if you call test as

    test -option "A" -other "B" 1 2 3
    

    $args will have -other,B,1,2,3

    0 讨论(0)
  • 2021-01-02 03:56

    This sort of does what you ask. You may run into trouble if you need to pass dash-prefixed options to the executable that conflict or cause ambiguity with the PowerShell common parameters. But this may get you started.

    function Invoke-MyProgram
    {
        [CmdletBinding()]
        Param
        (
            [parameter(mandatory=$true, position=0)][string]$Option,
            [parameter(mandatory=$false, position=1, ValueFromRemainingArguments=$true)]$Remaining
        )
    
        if ($Option -eq 'A')
        {
            Write-Host $Remaining
        }
        elseif ($Option -eq 'B')
        {
            & 'C:\Program Files\some\program.exe' @Remaining # NOTE: @ not $ (splatting)
        }
    }
    
    0 讨论(0)
提交回复
热议问题