PowerShell: 位置参数和ValueFromPipeline

4

我有一个看起来很简单的玩具问题,需要一个支持管道符的Join-Path函数。我们把它叫做Build-Path。因此,下面这些语句(我的测试1-4)应该是等效的:

Get-Location | Build-Path Test

Get-Location | Build-Path -Right Test

Build-Path -Left (Get-Location) -Right Test

Build-Path (Get-Location) Test

我尝试了许多方法,最接近的两个函数是互斥的:

A: 明确指定两个值的位置;未通过测试1。

function Build-Path
(
    [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
    [String] $Left, 
    [Parameter(Mandatory=$true, Position=1)]
    [String] $Right
)
{
    Join-Path $Left $Right
}

B: 管道参数位置未指定,Right的位置为0;测试4失败

function Build-Path
(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
    [String] $Left, 
    [Parameter(Mandatory=$true, Position=0)]
    [String] $Right
)
{
    Join-Path $Left $Right
}

我尝试过多种方式使用ParameterSets(没有保存我的尝试记录),但都没有成功,现在我有些困惑了。
你有什么想法吗?

$left | Join-Path -ChildPath $right <-- 我相当确定Join-Path已经可以完成你所要求的功能了。 - Ryan Bemrose
@RyanBemrose听起来很学究,但是不使用位置参数(即$left | Join-Path $right) - Steven Evers
1
单独的问题:在使用管道输入时,您没有进程块,这是您真正需要的。由于您只在管道中使用了一个对象,因此这并不明显。 - Mike Shepard
2
最简单的解决方法?交换你们的位置。你拥有的一切都会起作用,唯一需要改变的是第四步,你需要交换参数顺序。 - TheMadTechnician
1个回答

4

这种方式无法按照您的意愿工作。您的两个参数都是相同的数据类型,PowerShell会在检查是否从管道传入之前绑定参数,并尝试立即从位置0开始填充。

我甚至尝试使用参数集重新实现它:

function Build-Path {
[CmdletBinding(DefaultParameterSetName='Default',PositionalBinding=$false)]
param(
    [Parameter(
        ParameterSetName='Default',
        Mandatory=$true, 
        ValueFromPipeline=$true
    )]
    [Parameter(
        ParameterSetName='LooseyGoosey',
        Mandatory=$true,
        Position=0
    )]
    [String] 
    $Left, 

    [Parameter(
        ParameterSetName='Default',
        Mandatory=$true, 
        Position=0
    )]
    [Parameter(
        ParameterSetName='LooseyGoosey',
        Mandatory=$true,
        Position=1
    )]
    [String] 
    $Right
)

    Join-Path $Left $Right
}

如果想了解PowerShell是如何绑定参数的,可以使用Trace-Command命令:

Trace-Command -Name ParameterBinding -Expression { Build-Path (Get-Location) Test } -Verbose -PSHost

无论怎么切割,你都会遇到问题。没有 DefaultParameterSet?参数集无法解析。改变默认设置?那么哪些调用有效或无效就只是发生了变化而已。
同时,你也不能将 -Right 参数变成一个 [String[]] 数组,因为在绑定时 PowerShell 会尝试强制转换,所以一个 [String] 仍然会被接受并绑定。
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Get-Location]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Get-Location]
DEBUG: ParameterBinding Information: 0 : BIND cmd line args to DYNAMIC parameters.
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Get-Location]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Build-Path]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Build-Path]
DEBUG: ParameterBinding Information: 0 :     BIND arg [C:\Users\Briantist] to parameter [Right]
DEBUG: ParameterBinding Information: 0 :         Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 :             result returned from DATA GENERATION: C:\Users\Briantist
DEBUG: ParameterBinding Information: 0 :         BIND arg [C:\Users\Briantist] to param [Right] SKIPPED
DEBUG: ParameterBinding Information: 0 :     BIND arg [C:\Users\Briantist] to parameter [Left]
DEBUG: ParameterBinding Information: 0 :         Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 :             result returned from DATA GENERATION: C:\Users\Briantist
DEBUG: ParameterBinding Information: 0 :         BIND arg [C:\Users\Briantist] to param [Left] SKIPPED
DEBUG: ParameterBinding Information: 0 :     BIND arg [C:\Users\Briantist] to parameter [Right]
DEBUG: ParameterBinding Information: 0 :         Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 :             result returned from DATA GENERATION: C:\Users\Briantist
DEBUG: ParameterBinding Information: 0 :         BIND arg [C:\Users\Briantist] to param [Right] SKIPPED
DEBUG: ParameterBinding Information: 0 :     BIND arg [C:\Users\Briantist] to parameter [Right]
DEBUG: ParameterBinding Information: 0 :         Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 :             result returned from DATA GENERATION: C:\Users\Briantist
DEBUG: ParameterBinding Information: 0 :         COERCE arg to [System.String]
DEBUG: ParameterBinding Information: 0 :             Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 :         BIND arg [C:\Users\Briantist] to param [Right] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 :     BIND arg [Test] to parameter [Right]
DEBUG: ParameterBinding Information: 0 :         Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 :             result returned from DATA GENERATION: Test
DEBUG: ParameterBinding Information: 0 :         BIND arg [Test] to param [Right] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Build-Path]
DEBUG: ParameterBinding Information: 0 :     PROMPTING for missing mandatory parameters using the host

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接