【问题标题】:PowerShell pipeline parameter binding orderPowerShell 管道参数绑定顺序
【发布时间】:2019-02-28 22:17:19
【问题描述】:

我有一个可以接受两种管道数据的高级函数:

  • PSTypeName 为“MyType”的自定义对象
  • 任何具有 ID 属性的对象

这是我的功能:

function Test-PowerShell {
    [CmdletBinding(DefaultParameterSetName = "ID")]
    param (
        [Parameter(
            Mandatory = $true,
            ParameterSetName = "InputObject",
            ValueFromPipeline = $true
        )]
        [PSTypeName('MyType')]
        $InputObject,

        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'ID',
            ValueFromPipelineByPropertyName = $true
            )]
        [int]
        $ID
    )

    process {
        if ($InputObject) {
            $objects = $InputObject
            Write-Verbose 'InputObject binding'
        }
        else {
            $objects = Get-MyType -ID $ID
            Write-Verbose 'ID binding'
        }

        # Do something with $objects
    }
}

我可以这样使用这个函数:

$obj = [PSCustomObject]@{
    PSTypeName = 'MyType'
    ID = 5
    Name = 'Bob'
}
$obj | Test-PowerShell -Verbose

请注意,此对象同时满足上述两个条件:它是 MyType,并且具有 ID 属性。在这种情况下,PowerShell 始终绑定到 ID 属性。这在性能方面并不理想,因为管道对象被丢弃,我必须使用 ID 重新查询它。我的问题是这样的:

如果可能,我如何强制 PowerShell 将管道绑定到 $InputObject?

如果我将默认参数集更改为 InputObject,PowerShell 将绑定到 $InputObject。但是,我不希望这样,因为当不带参数运行时,我希望 PowerShell 提示输入 ID,而不是 InputObject。

【问题讨论】:

    标签: powershell parameters typing


    【解决方案1】:

    简单的答案:删除$InputObject 上的Parameter 属性的Mandatory 参数以获得您想要的功能。我对参数绑定的工作原理没有足够的知识来解释为什么这样工作。

    function Test-PowerShell {
        [CmdletBinding(DefaultParameterSetName = 'ID')]
        param(
            [Parameter(ParameterSetName = 'InputObject', ValueFromPipeline)]
            [PSTypeName('MyType')]
            $InputObject,
    
            [Parameter(ParameterSetName = 'ID', Mandatory, ValueFromPipelineByPropertyName)]
            [int]
            $ID
        )
    
        process {
            $PSBoundParameters
        }
    }
    
    $o = [pscustomobject]@{
        PSTypeName = 'MyType'
        ID         = 6
        Name       = 'Bob'
    }
    
    
    PS> $o | Test-PowerShell
    
    Key         Value
    ---         -----
    InputObject MyType
    
    
    PS> [pscustomobject]@{ID = 6} | Test-PowerShell
    
    Key Value
    --- -----
    ID      6
    

    下面的想法和实验。

    这是解决您的问题的一个解决方法(定义您自己的类型):

    Add-Type -TypeDefinition @'
    public class MyType
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
    '@
    

    然后你将你的参数标记为[MyType],就像你从[pscustomobject]创建对象一样:

    [MyType]@{ ID = 6; Name = 'Bob' }
    

    事后看来,这种方法行不通。您遇到的是DefaultParameterSet 的行为。我建议更改您作为管道输入的内容。与仅使用 Test-PowerShell -ID 5Test-PowerShell 并被提示输入 ID 的用户相比,是否有将 ID 作为管道输入的用例?

    根据我的测试,以下建议可能会如您所愿:

    function Test-PowerShell {
        [CmdletBinding(DefaultParameterSetName = 'ID')]
        param(
            [Parameter(ParameterSetName = 'InputObject', Mandatory = $true, ValueFromPipeline = $true)]
            [PSTypeName('MyType')]
            $InputObject,
    
            [Parameter(ParameterSetName = 'ID', Mandatory = $true, ValueFromPipeline = $true)]
            [int]
            $ID
        )
    
        process {
            $PSBoundParameters
        }
    }
    

    以现有内置 cmdlet 为例,它们不会对一个对象使用相同的名称或属性来表示多个参数。在Get-ChildItem 中,LiteralPathPath 都接受管道输入,但LiteralPath 只接受 PropertyName LiteralPathPSPath(别名)。 Path 是 ByValue 和 PropertyName,但仅作为 Path

    【讨论】:

    • 感谢您的帮助。据我所知,您的代码中的主要区别是自定义类型定义而不是使用 PSTypeName?
    • @DavidHaymond 是的,但这实际上并没有什么不同,所以你可以忽略它。在我的编辑中,我的想法更进一步;尝试刷新。
    • 这不是我想要的。要使用另一个内置 cmdlet 示例,InputObject 仅接受管道输入 ByValue,Id 仅接受管道 ByPropertyName。当我不带参数运行Stop-Process 时,它会提示输入Id,所以看起来ID 参数集是默认的。当传递一个进程对象(例如Get-Process | Stop-Process)时,PowerShell如何知道将其绑定到InputObject而不是Id,因为该进程对象具有Id属性?
    • @DavidHaymond 所以我找到了一种让它像Stop-Process cmdlet 一样工作的方法:remove Mandatory from the Parameter attribute for $InputObject
    • 谢谢;那行得通!我认为这一定是因为 PowerShell 使用指定的参数(而不是管道)来确定要选择的参数集。如果InputObjectID 都是必需的,则无论管道值如何,PowerShell 都无法确定要使用的适当参数集,因此它会选择默认参数集并然后 绑定管道输入。如果InputObject不是强制的,则InputObject参数集有效且被PowerShell选中,管道绑定到InputObject
    猜你喜欢
    • 1970-01-01
    • 2019-05-15
    • 2015-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-28
    相关资源
    最近更新 更多