理解Powershell管道

Posted Hlove贾小贱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解Powershell管道相关的知识,希望对你有一定的参考价值。

深入理解管道

在我們前面的一些命令使用中可以看到,我們有使用管道 ​​|​​​ 來連接Cmdlet,可以看到管道可以帮助我们更好的完成工作,那么我们也应该深入的去了解一下它的原理,以便于我们后续使用中能更好的使用它,避免在出现问题的时候不知道怎么去解决,接下来我们一起看一下吧


Powershell如何传递数据给管道

当两条命令串联在一起时,Powershell必须搞清楚怎样将第一条命令的输出作为第二条命令的输入 示例 我们在文本中输入一些文本

# 写入一些文本
Add-Content -Path D:\\amos.txt -Value WManSvc,AVS-17053-45304,AVS-17053-45304
# 运行下面的命令
Get-Content -Path D:\\amos.txt | Get-Service

当运行Get-content命令时,他会将文本文件中的计算机名称放入管道中。之后Powershell再决定如何将该数据传递给Get-Service命令,但Powershell一次只能使用单个参数接收传入数据。也就是说。Powershell必须决定由Get-Service的那个参数接收Get-content的输出结果。这个决定过程就成为管道参数绑定(Pipeline parameter binding)


方案A:使用ByValue进行管道输入

当使用ByValue这种方式实现管道参数绑定时,Powershell会确认命令A产生的数据对象类型,然后查看B中有哪个参数可以接收经由管道传过来对象的类型。我们可以使用​​Get-Content -Path d:\\amos.txt | gm​​​ 和 ​​help Get-Service  -Full ​​  进行查看。

理解Powershell管道_powershell

可以看到​​Get-Content -Path d:\\amos.txt​​命令产生的对象类型是System.String,通过查询帮助信息,可以看到Get-Service中有存在可以从ByValue管道中接收String类型的参数。检查发现,可以接收String类型数据的参数是-Name,查看帮忙信息,其说明是“指定要检索的服务名称”。因为第一个字段我设置的是一个服务名称,所以查询第一个字符串的时候Powershell可以正确的输出,后面两个报错很明显是告诉我们找不到这个服务名称。

理解Powershell管道_powershell_02

Powershell只允许使用一个参数接收ByValue管道返回的对象类型,那也就意味着,由于-Name参数接收了来自ByValue管道返回的String类型数据,那么其它参数就没有办法再接收该数据了。

理解Powershell管道_powershell_03

其实在这里​​help Get-Service  -Full​​进行查看可以看到所有参数的一些信息,每个参数是做什么的,是否接收管道输入等信息,如果不会使用命令的话可以多使用帮助命令来理解。

示例1

notepad.exe
Get-Process -Name notepad | Get-Member
help Stop-Process -Full
Get-Process -Name notepad | Stop-Process

理解Powershell管道_powershell_04

我们首先开启了一个记事本的进程,我们在执行​​Get-Process -Name notepad | Stop-Process​​时,Stop-Process命令会使用-InputObject参数来接收这些来自ByValue管道的进程对象。这是诠释管道参数绑定一个比较恰当的示例,同时也反映了Powershell中比较重要的一个知识点:大部分情况下,使用相同名称的命令都可以使用ByValue方式互相之间进行管道传输。


方案B:使用ByValue进行管道输入

示例2

Get-Service -Name * | Get-Member
Get-Service -Name * | Stop-Process

理解Powershell管道_powershell_05

我们可以看到Get-Service返回的是System.ServiceProcess.ServiceController类型的对象,但是我们查遍Stop-Process没有一个参数接收System.ServiceProcess.ServiceController类型对象,这也就意味着使用ByValue方式进行处理的方案失败了,此时Powershell会尝试使用其它备选方案ByPropertyName。

使用该方案同样需要将命令A的输出结果传递给命令B的参数。但是ByPropertyName与ByValue稍有不同。很多人都会认为这里的原理很复杂,其实Shell对该功能的实现其实非常简单:仅仅是孕照能够匹配参数名称的属性名称。在本例中属性“Name”与参数名称“-Name”相同,Shell会尝试将这两个值进行关联。

理解Powershell管道_powershell_06

过程的大致是这样,首先,他会检查-Name参数是否可以接收来自ByPropertyName管道的输出。在该示例中,-Name参数可以接收来自ByPropertyName管道输出结果,所以这个连接可以正常工作。与ByValue管道只能使用一个参数不同,ByPropertyName会将每个匹配的属性与参数进行关联。在这个示例中,只有Name属性与-Name参数匹配。

理解Powershell管道_powershell_07

示例3

# 用记事本新建下面一个文件 Alias.CSV
Name,Value
d,Get-childitem
sel,select-object
go,invoke-command
import-csv d:\\Alias.csv

理解Powershell管道_powershell_08

我們可以看到CSV文件中的列名称成为属性,而CSV中每一行的值成为一个对象。现在我们可以使用New-Alias进行接收数据,我们可以先看下 New-Alias是否支持参数进行接收,我們可以看到两个参数都可接收管道输入,在执行后我们可以看到新增加了三个别名

理解Powershell管道_powershell_09

Import-Csv D:\\Alias.csv | New-Alias

理解Powershell管道_powershell_10

基本上管道在这里我们就能有个大概的认识了,这些内容我都是从书中 Windows PowerShell实战指南 第3版 中学习到的,这里的内容大部分都是从书中看到自己实践一遍来的。如果大家对Powershell有兴趣的话,可以购买图书自己看。虽然现在网络上有很多学习教程,但是有时候我还是认为看书更能静下心来学习,当然每个人的学习方法不一样,请根据自己的方式来学习吧。

以上是关于理解Powershell管道的主要内容,如果未能解决你的问题,请参考以下文章

PowerShell 管道添加换行符

PowerShell ForEach / 管道混乱

管道文件到 uglifyjs - 来自 Powershell

Powershell:将外部命令输出通过管道传输到另一个外部命令

如何从PowerShell命令行转义管道字符以传递到非PowerShell命令

“创建管道时出错。”在 Azure 管道自托管代理中运行 powershell 脚本时