【问题标题】:PowerShell bug? Can't pipe ComputerName property to Get-Service (mixing byvalue and bypropertyname)PowerShell 错误?无法通过管道将 ComputerName 属性传递给 Get-Service(混合按值和按属性名)
【发布时间】:2018-05-13 18:13:45
【问题描述】:

看起来像一个错误,不是吗?在这种情况下,PowerShell 将哈希表转换为字符串“@{computername=comp001}”并尝试将其与 -Name (ByValue) 而不是 -ComputerName (ByPropertyName) 一起使用。即使是 PS 6 也能做到。管道到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

【问题讨论】:

  • -ComputerName 参数已从 PS 6.x 中的 Get-Service 中删除,但在较低版本中似乎是一个错误

标签: powershell pipe pipeline parameterbinding


【解决方案1】:

看起来像一个错误,不是吗?

本身并不是一个错误,而是Get-Service cmdlet 的参数设计的意外结果:

ValueFromPipeline 属性附加到类型为[string] / [string[]][object] / [object[]](或[psobject] / [psobject[]])的参数使该参数绑定到any 管道输入,可能除了绑定到其他参数 - 除非该参数被命令行参数绑定,这就是您的 -Name * 解决方法所做的。

  • 原因是any数据类型的实例可以转换为[string]/派生自[object]([psobject]),导致any输入对象,无论类型如何,都绑定到该参数。

简而言之:这里的问题不在于[pscustomobject]@{computername='comp001'} 没有绑定到-ComputerName - 实际上 -就是总是绑定到-Name
PowerShell 参数绑定器从根本上将管道输入绑定到所有合适的参数,而不仅仅是一个。

如上所述,防止-Name管道 绑定的唯一方法是通过参数 传递一个值——即使该值只是*表示包含任何名称的服务。

该行为现在也在讨论on GitHub


旁注:

正如 js2010(OP)指出的那样,可以在一个单个参数中有意义地组合ValueFromPipelineValueFromPipelineByPropertyName 属性 strong>,就像Get-Service 所做的那样,但请注意约束:

  • 仅适用于类型为[object][psobject]/[object[]][psobject[]]的参数(这样的参数将始终绑定所有内容按价值,而不考虑属性)。

    • 如果类型是[string][string[]],则考虑属性,但您不能有其他管道绑定参数,因为这会显示原来的问题:[string] / [string[]] 参数总是会绑定。
  • 与参数名称匹配的输入对象的属性类型必须与参数类型匹配或至少必须可转换才能绑定。

    李>

这是一个示例命令,它首先将同一服务作为字符串绑定到 -Name,然后作为具有 .Name 属性的对象:
'rpcss', [pscustomobject] @{ Name = 'rpcss' } | Get-Service

【讨论】:

    【解决方案2】:

    当您向Get-Service 发送一个完整的对象时,它只有两个绑定选项:NameInputObject,它们是接受ByValue 管道输入的参数。不幸的是,您的对象不是一种可以理解的形式。

    您可以通过运行此Trace-Command 来查看 PowerShell 正在做什么:

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

    正如你所说,解决这个问题的方法是为-Name 提供一个值,因此它不会尝试绑定它:

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

    再一次,您可以像上面一样使用Trace-Command 来查看它现在很乐意将'*' 绑定到-Name,然后它继续绑定附加参数,如-ComputerName

    PowerShell 文档 (about_Parameters) 指出:

    当参数为“True(按值)”时,Windows PowerShell 会尝试 在尝试其他参数之前,将任何管道值与该参数相关联 解释命令的方法。

    【讨论】:

    • 我不知道这在哪里记录,但 Get-Service 有一个 -ComputerName 选项,可以通过属性名称输入。可能还有其他示例,其中管道 byvalue 参数(字符串)优先于管道 bypropertyname 另一个参数。
    • 但是将哈希表转换为字符串?这在哪里有用?
    • 将对象转换为字符串是一项基本操作,这就是为什么每个 .NET 对象都有一个 ToString() 方法(甚至是哈希表)。它有多大用处取决于具体情况。在这种情况下,真正的问题是“如果你只有一把锤子,那么一切看起来都像钉子”。 -Name 只接受和理解字符串,所以如果你给它anything else,它不知道比把它当作一个字符串更好。我猜你希望它会决定输入不是以字符串开头并默认绑定ByPropertyName,但这不是它的工作原理。
    猜你喜欢
    • 2015-08-26
    • 1970-01-01
    • 2013-06-14
    • 2014-10-27
    • 2021-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-30
    相关资源
    最近更新 更多