Powershell 参数绑定 ByPropertyName 和 ByValue

Powershell Parameter binding ByPropertyName and ByValue

我想停止名为 "ALG" 的服务,所以我使用: "alg" | stop-service 有用。 Get-help stop-service -parameter name 说:管道 input:true(ByPropertyName, ByValue) 和 "alg" 是 "ByPropertyValue" 对吗? 我想停止一个名为记事本的进程,所以我使用: "notepad" | stop-process 并且出现错误。 Get-help stop-process -parameter name 说:管道输入 true(ByPropertyName) 并且 "notepad" 是 "ByPropertyName"?为什么会出现这个错误? 感谢您的帮助

如果您想通过 属性 名称 将对象的值绑定到参数 ,可以:

  1. 传递一个适当命名的对象 属性:
[pscustomobject]@{Name='notepad'} |Stop-Process
# or, for older versions of powershell:
'notepad' |Select @{Name='Name';Expression={$_}} |Stop-Process
  1. 将管道表达式显式绑定到命名参数:
'notepad' |Stop-Process -Name {$_}

"stop-service -name" 可以按值(字符串)进行管道传输,因此它使用它。 Stop-process 无法将字符串转换为 -inputobject 的进程类型,即按值管道。 "Stop-process -name" 仅为属性名称。

这里还有一些细微差别。可以强制字符串类型为 servicecontroller,但不能强制类型为 process。因此,理论上可以将字符串作为 -inputobject 以管道方式输入以用于停止服务,但不能用于停止进程。 "stop-service -inputobject alg" 也有效,但 "stop-process -inputobject notepad" 无效。这两个命令之间的不一致可能会造成混淆。

[System.ServiceProcess.ServiceController]'alg'

Status   Name               DisplayName
------   ----               -----------
Stopped  alg                Application Layer Gateway Service


[system.diagnostics.process]'notepad'
InvalidArgument: Cannot convert the "notepad" value of type "System.String" to type "System.Diagnostics.Process".

如果您真的想查看绑定:

trace-command parameterbinding {'alg' | stop-service} -pshost
trace-command parameterbinding {'notepad' | stop-process} -pshost
  • 答案提供了一个 解决方案 用于管道 strings (进程名称)到 Stop-Process.

  • 有正确的 解释 为什么管道字符串到 Stop-Process 不起作用(无需额外努力),并且还提供了一种有用的技术来跟踪参数绑定,但是 - 在撰写本文时 - 答案包含使问题有点混乱的附带信息。

让我提供更详细的解释:


Stop-Process,不像Stop-Service不是设计来接受strings(进程名称)作为管道输入。

虽然摘要中的字符串输入仍然可以工作,即如果字符串可以自动转换为预期的数据类型之一通过命令的 ByValue(整个对象)管道绑定参数,不是 Stop-Process 的情况,因为进程 name(字符串)无法(自动)转换为 System.Diagnostics.Process 实例 (-InputObject)[1].

  • 当 PowerShell 在调用期间考虑将管道输入绑定到参数 -Name 时,它会查找 具有 Name 属性,因为参数声明指定接受管道输入只有如果输入对象有一个属性 为参数命名:

    • 在帮助主题中,例如Stop-Process的那个,表示为ByPropertyName.

    • 在代码中表示为System.Management.Automation.ParameterAttribute类型的布尔ValueFromPipelineByPropertyName属性;也就是说,在 PowerShell 代码中,参数声明类似于:请注意,ValueFromPipelineByPropertyNameValueFromPipelineByPropertyName = $true
      的缩写 [Parameter(ValueFromPipelineByPropertyName)] [string[]] $Name

  • A [string] (System.String) 实例如 "alg" 没有 Name 属性 - 它是 本身名字.

  • 因此,在没有自动转换的情况下[1]System.Diagnostics.Process类型唯一的 ByValue 参数 -InputObject,并且 ByPropertyValue 参数没有 NameId 属性,调用 失败 带有以下错误消息,本质上告诉您管道输入无效(不能绑定到任何参数):

    • The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.

Stop-Service,相比之下,设计来接受字符串输入,因为它的-Name参数是(也)声明为接受字符串直接作为输入对象,作为一个整体

  • 在帮助主题中,例如Stop-Service,这表示为ByValue.

  • 在PowerShell代码中,表示为ValueFromPipeline:
    [Parameter(ValueFromPipeline)] [string[]] $Name

注:

  • 虽然给定的参数可以是两者ByValueByPropertyValue——这Stop-Service-Name 参数确实是这种情况 - 这不是典型的。

  • 通常,管道绑定参数声明为 标量 而不是数组(例如,对于 Sort-Object-InputObject <PSObject> 而不是-InputObject <PSObject[]>),这意味着仅通过管道支持传递多个参数,而不是通过直接参数 - 请参阅 GitHub issue #4242 了解背景信息。


检查管道绑定参数:

  • 命令的给定参数:
PS> Get-Help Stop-Process -Parameter Name

-Name <String[]>
    Specifies the process names of the processes to stop. You can type multiple process names, separated by commas, or use wildcard characters.
    
    Required?                    true
    Position?                    named
    Default value                None
    Accept pipeline input?       True (ByPropertyName)
    Accept wildcard characters?  true

注意 Accept pipeline input? 行;对于 non-pipeline-binding 参数,您会在第二列中看到 False

  • 全部 给定命令支持的管道绑定参数
PS> Get-Help Stop-Process -Parameter * | Where pipelineInput -like True*

-Id <Int32[]>
    Specifies the process IDs of the processes to stop. To specify multiple IDs, use commas to separate the IDs. To find the PID of a process, type 
    `Get-Process`.
    
    Required?                    true
    Position?                    0
    Default value                None
    Accept pipeline input?       True (ByPropertyName)
    Accept wildcard characters?  false
    

-InputObject <Process[]>
    Specifies the process objects to stop. Enter a variable that contains the objects, or type a command or expression that gets the objects.
    
    Required?                    true
    Position?                    0
    Default value                None
    Accept pipeline input?       True (ByValue)
    Accept wildcard characters?  false
    

-Name <String[]>
    Specifies the process names of the processes to stop. You can type multiple process names, separated by commas, or use wildcard characters.
    
    Required?                    true
    Position?                    named
    Default value                None
    Accept pipeline input?       True (ByPropertyName)
    Accept wildcard characters?  false

注意:上述技术从基于 MAML 的帮助文件中收集参数信息,可能伴随给定的 cmdlet(大多数 内置 cmdlet 确实带有此类帮助文件)。虽然帮助文件中的信息 应该 正确反映了 cmdlet 的实际参数定义并且通常如此,但不能保证如此。如有疑问,请改用以下技术,它直接检查 cmdlet 的实际定义:

# Lists all pipeline-binding parameters defined by the given cmdlet,
# by examining the actual cmdlet definition.
(Get-Command Stop-Process).ParameterSets.Parameters | 
  Where-Object { $_.ValueFromPipeline -or $_.ValueFromPipelineByPropertyName} |
    Select-Object -Unique Name, Aliases, ParameterType, @{
      Name = 'Accepts pipeline input'
      Expression = { 
        'True ({0})' -f  ($(
           if ($_.ValueFromPipeline) { 'ByValue'}
           if ($_.ValueFromPipelineByPropertyName) { 'ByPropertyName' }
        ) -join ', ')
      }
    } | Sort-Object Name

[1] 除非通过 System.Management.Automation.ArgumentTransformationAttribute-derived attribute (which is uncommon), PowerShell's usual conversion rules apply here, which employ several techniques, discussed in . In the case of System.Diagnostics.Process, conversion from a string isn't possible, because the target type neither has a single-argument constructor that has a string, nor does it have a static .Parse() method. A quick test for convertibility is to attempt a cast: [System.Diagnostics.Process] 'notepad' fails. By contrast, [System.ServiceProcess.ServiceController] 'alg' works, because that type does have a single-parameter constructor that accepts a string 声明参数支持自定义类型转换,但请注意,此转换 而不是 参数绑定期间 调用 Stop-Service 时发挥作用,例如 'alg' | Stop-Service - 在那里,字符串按原样绑定到 ByValue -Name参数.