简体   繁体   English

PowerShell 错误? 无法通过管道将 ComputerName 属性传递给 Get-Service(混合 byvalue 和 bypropertyname)

[英]PowerShell bug? Can't pipe ComputerName property to Get-Service (mixing byvalue and bypropertyname)

Seems like a bug, no?看起来像一个错误,不是吗? In this case, PowerShell converts the hashtable to a string '@{computername=comp001}' and tries to use it with -Name (ByValue) instead of -ComputerName (ByPropertyName).在这种情况下,PowerShell 将哈希表转换为字符串 '@{computername=comp001}' 并尝试将它与 -Name (ByValue) 一起使用,而不是 -ComputerName (ByPropertyName)。 Even PS 6 does it.甚至 PS 6 也能做到。 Piping to Get-Service -Name * works fine.管道到Get-Service -Name *工作正常。

PS C:\> [pscustomobject]@{computername='comp001'} | get-service
get-service : Cannot find any service with service name '@{computername=comp001}'.
At line:1 char:45
+ [pscustomobject]@{computername='comp001'} | get-service
+                                             ~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (@{computername=comp001}:String) 
[Get-Service], ServiceCommandException
    + FullyQualifiedErrorId : 
NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand

Seems like a bug, no?看起来像一个错误,不是吗?

Not a bug as such, but an unexpected consequence of the parameter design of the Get-Service cmdlet:不是错误本身,而是Get-Service cmdlet 参数设计的意外结果:

Attaching the ValueFromPipeline attribute to a parameter typed [string] / [string[]] or [object] / [object[]] (or [psobject] / [psobject[]] ) makes that parameter bind to any pipeline input , possibly in addition to binding to other parameters - unless that parameter is bound by command-line argument , which is what your -Name * workaround does.ValueFromPipeline属性附加到类型为[string] / [string[]][object] / [object[]] (或[psobject] / [psobject[]] )的参数会使该参数绑定到任何管道输入,可能在除了绑定到其他参数 -除非该参数由命令行参数绑定,这就是您的-Name *解决方法所做的。

  • The reason is that instances of any data type can be converted to [string] / are derived from [object] ( [psobject] ), causing any input object, irrespective of type, to bind to that parameter.原因是任何数据类型的实例都可以转换为[string] / 派生自[object] ( [psobject] ),导致任何输入对象,无论类型如何,都绑定到该参数。

In short: the problem here isn't that [pscustomobject]@{computername='comp001'} isn't bound to -ComputerName - it actually is - it is that it is also bound to -Name , invariably.简而言之:这里的问题不在于[pscustomobject]@{computername='comp001'}没有绑定到-ComputerName - 它实际上- 它总是绑定到-Name
The PowerShell parameter binder fundamentally binds pipeline input to all suitable parameters , not just one. PowerShell参数绑定器从根本上将管道输入绑定到所有合适的参数,而不仅仅是一个。

As stated, the only way to prevent the -Name binding from the pipeline is to pass a value by argument - even if that value is just * to signal inclusion of services of any name.如上所述,防止管道中-Name绑定的唯一方法是通过参数传递值 - 即使该值只是*表示包含任何名称的服务。

The behavior is now also being discussed on GitHub .现在也在GitHub 上讨论这种行为。


Side note:边注:

As js2010 (the OP) points out, it is possible to meaningfully combine the ValueFromPipeline and ValueFromPipelineByPropertyName attributes in a single parameter , the way Get-Service does, but note the constraints:作为js2010(在OP)指出,可能有意义结合ValueFromPipelineValueFromPipelineByPropertyName属性的一个参数,该方式Get-Service做,但要注意的限制:

  • It only works for a parameter not typed [object] or [psobject] / [object[]] or [psobject[]] (such a parameter would invariably bind everything by value without ever considering properties ).仅适用于键入[object][psobject] / [object[]][psobject[]]的参数(这样的参数将始终按值绑定所有内容而无需考虑属性)。

    • If the type is [string] or [string[]] , properties are considered, but you cannot have additional pipeline-binding parameters , because that presents the original problem: the [string] / [string[]] parameter will invariably also bind.如果类型是[string][string[]]考虑属性,但不能有额外的管道绑定参数,因为这会带来原始问题: [string] / [string[]]参数总是也会绑定.
  • The type of an input object's property matching the parameter name must either match the parameter type or must at least be convertible to it in order to be bound.与参数名称匹配的输入对象的属性类型必须与参数类型匹配,或者必须至少可以转换为参数类型才能绑定。

Here's a sample command that binds the same service to -Name first as a string and then as an object with a .Name property:这是一个示例命令,它首先将相同的服务作为字符串绑定到-Name ,然后作为具有.Name属性的对象:
'rpcss', [pscustomobject] @{ Name = 'rpcss' } | Get-Service

As you are sending a complete object to Get-Service , it has only two options for binding: Name and InputObject , which are the parameters that accept ByValue pipeline input.当您将一个完整的对象发送到Get-Service ,它只有两个绑定选项: NameInputObject ,它们是接受ByValue管道输入的参数。 Unfortunately, your object is not in a form that either understands.不幸的是,您的对象不是可以理解的形式。

You can see what PowerShell is doing by running this Trace-Command :您可以通过运行此Trace-Command来查看 PowerShell 正在做什么:

Trace-Command -Name ParameterBinding -PSHost -Expression {[pscustomobject]@{ComputerName='comp001'} | Get-Service}

As you say, the way around this is to supply a value for -Name , so it doesn't attempt to bind it:正如您所说,解决此问题的方法是为-Name提供一个值,因此它不会尝试绑定它:

[pscustomobject]@{ComputerName='comp001'} | Get-Service -Name *

Once again, you can use Trace-Command as above to see that it is now happy to bind '*' to -Name , then it goes on to bind the additional parameters like -ComputerName .再一次,您可以像上面一样使用Trace-Command来查看现在很高兴将 '*' 绑定到-Name ,然后它继续绑定其他参数,如-ComputerName

The PowerShell documentation ( about_Parameters ) states: PowerShell 文档 ( about_Parameters ) 指出:

When a parameter is "True (by Value)", Windows PowerShell tries to associate any piped values with that parameter before it tries other methods to interpret the command.当参数为“True(按值)”时,Windows PowerShell 会尝试将任何管道值与该参数相关联,然后再尝试其他方法来解释命令。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM