PowerShell Pipeline如何工作–第1部分?

通过Pipeline结构使PowerShell更容易。使用Pipeline结构,我们可以将左侧命令输出的输入或字符串作为输入传递给命令的右侧。例如,

Get-Service | Out-File c:\services.txt

在上面的示例中,我们将Get-Service输出作为对象传递给Out-File命令,该命令位于管道的右侧,作为Input。在详细介绍管道如何工作之前,我们需要了解我们编写的每个命令都会产生输出,并且该输出已经由PowerShell使用管道格式化。

例如,Get-Process命令,如果我们不格式化该命令,则实际的默认命令是,

Get-Process | Out-Default | Out-Host

Out-DefaultOut-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

在此说明如下。要检查输入的内容究竟可以传递给命令右侧,我们需要使用属性名称为ParameterSet的Get-Command。您也可以使用Get-Help命令。

(Get-Command Get-Service).ParameterSets.Parameters

一旦运行上述命令,请注意两个属性ValueFromPipeLineValueFromPipelineByPropertyName,然后检查True值。让我们过滤掉那些属性。

在本文中,我们将介绍ValueFromPipleLine属性。下一篇文章(第2部分)将介绍valueFromPipelineByPropertyName参数。

(Get-Command Get-Service).ParameterSets.parameters | where{$_.ValueFromPipeline -eq 'True'} | Select Name,ParameterType

输出结果

Name ParameterType
---- -------------
Name System.String[]
InputObject System.ServiceProcess.ServiceController[]

从上面的输出中,我们可以将Name作为Input对象传递,其类型为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或过程名称无效。