PowerShell 管道如何工作 - 第一部分?
管道结构使 PowerShell 的使用更加便捷。借助管道结构,我们可以将左侧命令输出或字符串的输入传递到右侧命令作为输入。例如:
Get-Service | Out-File c:\services.txt
在上面的例子中,我们将 Get-Service 的输出作为对象传递给 Out-File 命令,该命令位于管道的右侧作为输入。在详细介绍管道的工作原理之前,我们需要了解我们编写的每个命令都会产生输出,并且这些输出已经由 PowerShell 使用管道进行了格式化。
例如,Get-Process 命令,如果我们不格式化此命令,则实际的默认命令是:
Get-Process | Out-Default | Out-Host
Out-Default 和 Out-Host 不可见,但实际上在后台运行。Out-Default 设置默认格式,而 Out-Host 命令则在控制台上打印输出。
在管道结构中,命令的右侧从输出的左侧获取输入。因此,我们需要了解究竟可以传递给管道的内容,我们不能像下面这样传递进程名称或 PID 等随机数据。
"PowerShell" | Get-Process
"1002"| Get-Process
上述命令将生成错误,提示上述命令未将提供的输入作为管道输入。
Get-Process:输入对象无法绑定到该命令的任何参数,因为该命令不接受管道输入,或者输入 及其属性与任何接受管道输入的参数都不匹配。
而对于 Get-Service,我们可以传递名称。
PS C:\> "Winrm","Spooler" | Get-Service Status Name DisplayName ------ ---- ----------- Running Winrm Windows Remote Management (WS-Managem… Running Spooler Print Spooler
解释如下。为了检查我们可以将什么内容作为命令右侧的输入传递,我们需要使用 Get-Command 并指定属性名称 ParameterSet。您也可以使用 Get-Help 命令。
(Get-Command Get-Service).ParameterSets.Parameters
运行上述命令后,请注意两个属性:ValueFromPipeLine 和 ValueFromPipelineByPropertyName,并检查其是否为 True 值。让我们筛选出这些属性。
本文将介绍 ValueFromPipleLine 属性。 valueFromPipelineByPropertyName 参数将在下一篇文章(第二部分)中介绍。
(Get-Command Get-Service).ParameterSets.parameters | where{$_.ValueFromPipeline -eq 'True'} | Select Name,ParameterType
输出
Name ParameterType ---- ------------- Name System.String[] InputObject System.ServiceProcess.ServiceController[]
从上面的输出中,我们可以将 Name 作为输入对象传递,其类型为 String[]。这意味着我们可以传递多个服务名称,这与前面的示例讨论过的情况相同。
PS C:\> "Winrm","Spooler" | Get-Service Status Name DisplayName ------ ---- ----------- Running Winrm Windows Remote Management (WS-Managem… Running Spooler Print Spooler
第二个是 InputObject,其类型为 ServiceController[]。这是您在使用命令 Get-Member 时看到的类型,在第一行中,您将获取 TypeName。
PS C:\> Get-Service | Get-Member TypeName: System.Service.ServiceController
为了更好地理解,我们再举一个 Stop-Service 命令的例子。
(Get-Command Stop-Service).ParameterSets.parameters | where{$_.ValueFromPipeline -eq 'True'} | Select Name,ParameterType
Name ParameterType
---- -------------
InputObject System.Diagnostics.Process[]
因此,Stop-Process 命令仅接受 Process 数组作为输入,如果您检查 Get-Process,其成员类型也是 System.Diagnostics.process。这意味着我们可以使用管道将整个 Get-Process 作为输入传递给 Stop-Process。
PS C:\> "2916" | Stop-Process InvalidArgument: (2916:String) [Stop-Process], ParameterBindingException PS C:\> "Notepad" | Stop-Process InvalidArgument: (Notepad:String) [Stop-Process], ParameterBindingException
这意味着如果我们传递进程名称或进程 ID,它将无法正常工作。
PS C:\> "2916" | Stop-Process InvalidArgument: (2916:String) [Stop-Process], ParameterBindingException PS C:\> "Notepad" | Stop-Process InvalidArgument: (Notepad:String) [Stop-Process], ParameterBindingException
在上面的例子中,传递进程 ID 或进程名称不起作用,因为管道不接受该输入。

