PowerShell 管道如何工作 - 第一部分?

powershellmicrosoft technologiessoftware & coding更新于 2026/2/10 12:37:17

管道结构使 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 或进程名称不起作用,因为管道不接受该输入。


相关文章