PowerShell中的包装函数:传递剩余参数

pok*_*oke 8 parameters powershell

我正在尝试在PowerShell中编写一个包装器函数,它基本上评估第一个参数,并基于它在计算机上运行程序.然后,包装函数的所有剩余参数都应传递给运行的程序.

所以看起来应该是这样的:

function test ( [string] $option )
{
    if ( $option -eq 'A' )
    {
        Write-Host $args
    }
    elseif ( $option -eq 'B' )
    {
        . 'C:\Program Files\some\program.exe' $args
    }
}
Run Code Online (Sandbox Code Playgroud)

现在只是添加$args不起作用,所以我需要做些什么来使它工作?另一种选择可能是使用Invoke-Expression,但感觉有点像eval我想尽可能避免,此外我认为这样做会限制我只对字符串参数吧?如果可能的话,我希望得到对包装程序/ cmdlet的完全支持 - 基本上就像动态别名一样.这甚至可能吗?

Old*_*art 11

这样做可以满足您的要求.如果您需要将带有破折号前缀的选项传递给与PowerShell常见参数冲突或导致歧义的可执行文件,则可能会遇到麻烦.但这可能会让你开始.

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)
    }
}
Run Code Online (Sandbox Code Playgroud)


mkl*_*nt0 7

  • 您的解决方案按原样适用于外部程序(例如您的C:\Program Files\some\program.exe示例):您始终可以将值数组这是什么)传递给外部程序,并且其元素将作为单独的参数传递(如果需要,则进行字符串化) 。$args

  • 如果更改为$args@args[1] ,您可以使您的解决方案适用于任何命令,以利用称为splatting的 PowerShell 参数传递技术:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

注意事项

  • 自动$args变量收集所有未声明参数的参数,仅在简单(非高级)函数和脚本可用高级函数和脚本- 使用[CmdletBinding()]属性和/或 属性的函数[Parameter()]和脚本 - 要求声明所有潜在参数。

  • PowerShell 具有内置魔法,使自动数组变量$args还支持通过 splatting传递命名参数,而自定义数组或集合不支持这种方式。

    • 相比之下,自定义数组和集合仅支持展开位置(未命名)参数,但这涵盖了对外部程序的所有调用。
    • 然而,在调用PowerShell命令时,这种限制是有问题的:例如,如果您想通过 splatting 将命名参数传递-Path C:\Set-Locationcmdlet,那么使用通过 声明的自定义集合参数ValueFromRemaining Arguments(如OldFart 的答案( Set-Location @Remaining) 中所示)是行不通的;为了支持传递命名参数(除了 via @args,如果可用),您必须使用基于hashtable的 splatting

因此,如果您的函数是高级函数,并且需要支持将命名参数传递给其他 PowerShell 命令,则需要一种不同的方法此答案显示了两种替代方法。


[1] 对于外部程序,存在一种与@args行为不同的极端情况$args,即如果$args数组包含--%,则停止解析符号@args识别它,$args将其视为文字。