PowerShell中的Wrapper函数:传递剩余参数

svujldwt  于 2023-05-22  发布在  Shell
关注(0)|答案(4)|浏览(226)

我尝试在PowerShell中编写一个 Package 器函数,它基本上计算第一个参数,并基于此在计算机上运行一个程序。然后, Package 器函数的所有剩余参数都应该传递给运行的程序。
所以它应该看起来像这样:

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

现在仅仅添加$args不起作用,那么我必须做些什么才能使它起作用呢?另一个选择可能是使用Invoke-Expression,但感觉有点像eval,所以我想尽可能避免,另外我认为这样做会限制我只能使用字符串参数,对吗?如果可能的话,我希望有对 Package 程序/cmdlet的完全支持-基本上就像一个动态别名。这可能吗?

kxkpmulp

kxkpmulp1#

这就是你想要的。如果您需要向可执行文件传递带有破折号前缀的选项,而这些选项与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)
    }
}
g52tjvyc

g52tjvyc2#

您的解决方案可用于 * 外部程序(例如您的C:\Program Files\some\program.exe示例):你总是可以传递一个 * 数组 * 的值(这就是$args到一个外部程序,它的元素将作为 * 单独的参数*(字符串化,如果必要的话)传递。
*如果您将$args更改为@args[1],则可以使用 any 命令使解决方案工作,以利用称为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
    }
}

注意事项
**自动$args变量,收集所有声明了 no 参数的参数,仅在 * 简单 (非高级)函数和脚本中可用; advanced functions and scripts-那些使用[CmdletBinding()]属性和/或[Parameter()]属性的-要求声明 * 所有 * 潜在参数。
*PowerShell有 * 内置的魔法 *,使自动 * 数组 * 变量$args也支持通过splatting传递 * 命名 * 参数,这是没有 * 自定义 * 数组或集合支持的。

  • 相比之下,*自定义数组和集合只支持splatting * 位置 (未命名)参数,但是,它涵盖了对 * 外部程序 * 的所有调用。
    *在调用 PowerShell 命令时,此限制存在问题,但是:例如,如果您希望通过splatting将 named 参数-Path C:\传递到Set-Location cmdlet,则使用通过ValueFromRemaining Arguments声明的自定义集合参数(如OldFart's answerSet-Location @Remaining)中所示)将 * 不起作用;要支持通过 named 参数传递(而不是通过@args,如果可用的话),您必须使用基于 hashtable 的splatting

因此,*如果您的函数是 * 高级 * 函数 ,并且 * 您需要支持将 named 参数传递给其他PowerShell命令,则需要使用不同的方法this answer显示了两个备选方案。
[1]对于 external programs,有一种极端情况,@args的行为与$args不同,即如果$args数组包含--%,则stop-parsing symbol@args识别它,$args将其视为文字。

jei2mxaa

jei2mxaa3#

你写的东西是有效的。请注意,$args是函数期望的参数之上的未命名参数。
所以如果你调用test作为

test -option "A" 1 2 3

$args将具有1,2,3
请注意,如果将test调用为

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

$args将具有-other,B,1,2,3

3mpgtkmj

3mpgtkmj4#

我想改进this answer,并建议一个既适用于位置参数又适用于命名参数的解决方案:

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')
    {
        Invoke-Expression "& `"C:\Program Files\some\program.exe`" $Remaining"
    }
}

注意事项Be aware的'调用表达式'的安全问题!

相关问题