PowerShell错误-无法通过管道将ComputerName属性传输到Get-Service(混合使用按值和按属性名称)

r8uurelv  于 2023-01-09  发布在  Shell
关注(0)|答案(2)|浏览(105)

看起来像个bug,不是吗?在这种情况下,PowerShell将哈希表转换为字符串“@{computername= comp 001}”,并尝试将其与-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
iyfjxgzm

iyfjxgzm1#

看起来像只虫子,不是吗?
不是这样的错误,而是Get-Service cmdlet的参数设计的意外结果:

    • ValueFromPipeline属性附加到[string]/[string[]][object]/[object[]]类型的参数(或[psobject]/[psobject[]])使该参数绑定到 * 任何 * 管道输入**,可能 * 除了 * 绑定到其他参数之外-* 除非 * 该参数由 * 命令行参数 * 绑定,这正是您的-Name *工作区所做的。
  • 原因是 * any * 数据类型的示例可以转换为[string]/是从[object][psobject])派生的,这导致 * any * 输入对象(无论类型如何)绑定到该参数。

简而言之:这里的问题不是[pscustomobject]@{computername='comp001'} * 没有 * 绑定到-ComputerName-它实际上 * 是 *-而是它 * 也 * 绑定到-Name,这是不变的。
PowerShell参数绑定器从根本上将管道输入绑定到 * 所有 * 合适的参数,而不仅仅是一个。
如前所述,防止-Name绑定进入 * 管道 * 的唯一方法是通过 * 参数 * 传递一个值--即使该值只是*,以表示包含任何名称的服务。
现在也在讨论on GitHub的行为。
旁注:
正如js2010(OP)所指出的,它 * 有 * 可能 * 在一个 * 参数中有意义地组合ValueFromPipelineValueFromPipelineByPropertyName属性,就像Get-Service所做的那样,但是注意约束:

  • 只适用于 * 不是 * 类型为[object][psobject]/[object[]][psobject[]]的参数(这样的参数总是 * 按值 * 绑定所有内容,而从不考虑 * 属性 *)。
      • 如果类型是[string][string[]],则会 * 考虑属性,但不能有 * 附加的 * 管道绑定参数**,因为这会带来原始问题:[string]/[string[]]参数将总是 * 也 * 绑定。
  • 与参数名匹配的输入对象属性的类型必须与参数类型匹配,或者必须至少可 * 转换 * 为参数类型才能绑定。

下面是一个示例命令,它首先将同一服务作为字符串绑定到-Name,然后作为具有.Name属性的对象绑定到-Name
x1米30英寸1x

qni6mghb

qni6mghb2#

当您将一个完整的对象发送到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会先尝试将任何管道值与该参数关联,然后再尝试其他方法解释命令。

相关问题