PowerShell管道如何工作 – 第1部分?
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: 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.
而对于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**参数将在下一篇文章(第2部分)中介绍。
(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:\> Get-Process | gm TypeName: System.Diagnostics.Process Get-Process | Stop-Process
这意味着如果我们传递进程的名称或进程ID,则它不应该工作。
PS C:\> "2916" | Stop-Process InvalidArgument: (2916:String) [Stop-Process], ParameterBindingException PS C:\> "Notepad" | Stop-Process InvalidArgument: (Notepad:String) [Stop-Process], ParameterBindingException
在上面的示例中,传递进程ID或进程名称不起作用,因为管道不接受该输入。