[英]PowerShell pipeline parameter binding order
I have an advanced function that can accept two kinds of pipeline data: 我有一个高级函数,可以接受两种管道数据:
Here's my function: 这是我的功能:
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
}
}
I can use this function like this: 我可以像这样使用这个函数:
$obj = [PSCustomObject]@{
PSTypeName = 'MyType'
ID = 5
Name = 'Bob'
}
$obj | Test-PowerShell -Verbose
Note that this object satisfies both of the above conditions: It is a MyType, and it has an ID property. 请注意,此对象满足上述两个条件:它是MyType,并且具有ID属性。 In this case, PowerShell always binds to the ID property.
在这种情况下,PowerShell始终绑定到ID属性。 This isn't ideal performance-wise because the piped object is discarded and I have to re-query it using the ID.
这在性能方面并不理想,因为管道对象被丢弃,我不得不使用ID重新查询它。 My question is this:
我的问题是:
How do I force PowerShell to bind the pipeline to $InputObject if possible? 如果可能,如何强制PowerShell将管道绑定到$ InputObject?
If I change the default parameter set to InputObject, PowerShell binds on $InputObject. 如果我将默认参数设置更改为InputObject,PowerShell将绑定$ InputObject。 I don't want this, however, because when run without parameters, I want PowerShell to prompt for an ID, not an InputObject.
但是,我不希望这样,因为在没有参数的情况下运行时,我希望PowerShell提示输入ID,而不是InputObject。
Simple answer: remove the Mandatory
argument to the Parameter
attribute on $InputObject
to get the functionality you want. 简单的答案:删除
$InputObject
上的Parameter
属性的Mandatory
参数以获得所需的功能。 I don't have enough knowledge on how parameter binding works to explain why this works. 我没有关于如何参数绑定作品解释为什么这个作品足够的知识。
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
Here's a workaround to your problem (defining your own type): 这是解决您的问题的方法(定义您自己的类型):
Add-Type -TypeDefinition @'
public class MyType
{
public int ID { get; set; }
public string Name { get; set; }
}
'@
And then you would tag your parameter as [MyType]
, creating objects like you would from [pscustomobject]
:然后你将你的参数标记为 [MyType]
,创建像[pscustomobject]
那样的对象:
[MyType]@{ ID = 6; Name = 'Bob' }
In hindsight, this method does not work. 事后看来,这种方法不起作用。 What you're running into is the behavior of the
DefaultParameterSet
. 您遇到的是
DefaultParameterSet
的行为。 I'd suggest changing what you take as pipeline input. 我建议你改变你的管道输入。 Is there a use-case for taking the ID as pipeline input versus a user just using
Test-PowerShell -ID 5
or Test-PowerShell
and being prompted for the ID? 是否存在将ID作为管道输入而不是仅使用
Test-PowerShell -ID 5
或Test-PowerShell
并被提示输入ID的用户的用例?
Here's a suggestion that may work as you intend from my testing: 这是一个可能与我的测试有关的建议:
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
}
}
To take an example from an existing built-in cmdlet, they don't use the same name or properties on an object for multiple parameters. 要从现有的内置cmdlet中获取示例,它们不会在对象上使用相同的名称或属性来表示多个参数。 In
Get-ChildItem
, both the LiteralPath
and Path
take pipeline input, but LiteralPath
only takes it by PropertyName LiteralPath
or PSPath
(aliased). 在
Get-ChildItem
, LiteralPath
和Path
接受管道输入,但LiteralPath
只接受PropertyName LiteralPath
或PSPath
(别名)。 Path
is ByValue and PropertyName, but only as Path
. Path
是ByValue和PropertyName,但仅作为Path
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.