[玩转系统] 了解 PowerShell 管道和创建函数
作者:精品下载站 日期:2024-12-14 13:07:48 浏览:13 分类:玩电脑
了解 PowerShell 管道和创建函数
PowerShell 管道是 PowerShell shell 和脚本语言最重要(也是最有用)的功能之一。一旦您了解了它的工作原理和功能的基础知识,您就可以在自己的功能中利用它的强大功能。在本教程中,您将这样做!
PowerShell 管道允许您将命令链接在一起以构建单个“管道”,从而简化代码、允许并行处理等。如果您准备好了解管道并构建自己的函数来利用管道,那么让我们开始吧!
先决条件
这篇文章将是一个教程,并且将是所有实践演示。如果您想继续操作,您将需要 PowerShell v3+。本教程将使用 Windows PowerShell v5.1。
了解 PowerShell 管道
大多数 PowerShell 命令通过参数接收一些输入。该命令接收一些对象作为输入,并在内部对其执行某些操作。然后它可以选择通过输出返回一些对象。
管道中的命令就像接力赛中的人类赛跑者一样。比赛中的每个参赛者,除了第一名和最后一名之外,都从前一位选手手中接过接力棒(物体),并将其传递给下一位选手。
例如,Stop-Service
cmdlet 有一个名为 InputObject
的参数。此参数允许您将特定类型的对象传递给 Stop-Service
来表示您想要停止的 Windows 服务。
要使用 InputObject
参数,您可以通过 Get-Service
检索服务对象,然后将该对象传递给 InputObject
参数,如下所示。这种通过 InputObject
参数向 Stop-Service
cmdlet 提供输入的方法效果很好,可以完成工作。
$service = Get-Service -Name 'wuauserv'
Stop-Service -InputObject $service
这种将输入传递给 Stop-Service
命令的方法需要两个不同的步骤。 PowerShell 必须首先运行 Get-Service
,将输出保存到变量,然后通过 InputObject
参数将该值传递给 Stop-Service
。
现在,将上面的代码片段与下面的代码片段进行收缩,它的作用是相同的。它要简单得多,因为您根本不需要创建 $services
变量,甚至不需要使用 InputObject
参数。相反,PowerShell“知道”您打算使用 InputObject
参数。它通过称为参数绑定的概念来实现这一点。
您现在已经将命令与 |
运算符“链接”在一起。您已经创建了一个管道。
Get-Service -Name 'wuauserv' | Stop-Service
但是,您不必仅使用两个命令来创建管道;您可以将任意数量的链接在一起(如果命令参数支持)。例如,下面的代码片段:
- 将
Get-Service
cmdlet 返回的所有对象传递给Where-Object
cmdlet。 - 然后,
Where-Object
cmdlet 查看每个对象的Status
属性,然后仅返回那些值为Running
的对象。 - 然后,每个对象都会发送到
Select-Object
,后者仅返回对象的Name
和DisplayName
属性。 - 由于没有其他 cmdlet 接受
Select-Object
输出的对象,因此该命令将对象直接返回到控制台。
Where-Object
和 Select-Object
cmdlet 了解如何通过称为参数绑定的概念处理管道输入,下一节将对此进行讨论。
Get-Service | Where-Object Status -eq Running | Select-Object Name, DisplayName
有关管道的更多信息,请运行命令Get-Help about_pipelines
。
管道参数绑定
乍一看,管道可能看起来微不足道。毕竟,它只是将对象从一个命令传递到另一个命令。但实际上,管道要复杂得多。命令仅接受通过参数的输入。即使您没有显式定义参数,管道也必须以某种方式确定要使用哪个参数。
当命令通过管道接收输入时确定要使用哪个参数的任务称为参数绑定。为了成功将从管道传入的对象绑定到参数,传入命令的参数必须支持它。命令参数支持以两种方式之一进行管道参数绑定; ByValue
和/或 ByPropertyName
。
按价值
命令参数接受整个传入对象作为参数值。 ByValue
参数在传入对象中查找特定类型的对象。如果该对象类型匹配,PowerShell 会假定该对象应绑定到该参数并接受它。
Get-ChildItem cmdlet 有一个名为 Path
的参数,该参数通过 ByValue
接受字符串对象类型和管道输入。因此,运行类似 'C:\Windows' | Get-ChildItem
返回 C:\Windows 目录中的所有文件,因为 C:\Windows
是一个字符串。
按属性名称
命令参数不接受整个对象,而是接受该对象的单个属性。它不是通过查看对象类型而是通过属性名称来实现此目的。
Get-Process cmdlet 有一个 Name
参数,该参数设置为接受管道输入 ByPropertyName
。当您将具有 Name
属性的对象传递给 Get-Process
cmdlet 时,例如 [pscustomobject]@{Name='firefox'} | Get-Process
,PowerShell 将传入对象上的 Name
属性匹配或绑定到 Name
参数并使用该值。
发现支持管道的命令参数
如前所述,并非每个命令都支持管道输入。命令作者必须在开发中创建该功能。该命令必须至少有一个支持管道的参数,放置 ByValue
或 ByPropertyName
。
如何知道哪些命令及其参数支持管道输入?您可以通过反复试验来尝试,但使用 Get-Help
命令使用 PowerShell 帮助系统有更好的方法。
Get-Help <COMMAND> -Parameter <PARAMETER>
例如,请查看下面的 Get-ChildItem
cmdlet 参数 Path
。可以看到它支持两种类型的管道输入。
一旦您知道哪些命令参数支持管道输入,您就可以利用该功能,如下所示。
# none-pipeline call
Get-ChildItem -Path 'C:\Program Files', 'C:\Windows'
# pipeline call
'C:\Program Files', 'C:\Windows' | Get-ChildItem
但是,另一方面,Get-Service
上的 DisplayName
参数不支持管道输入。
构建您自己的管道功能
尽管标准 PowerShell cmdlet 支持管道输入,但这并不意味着您无法利用该功能。值得庆幸的是,您也可以构建接受管道输入的函数。
为了进行演示,我们从一个名为 Get-ConnectionStatus
的现有函数开始。
- 该函数有一个名为
ComputerName
的参数(不接受管道输入),它允许您向其传递一个或多个字符串。 您可以看出ComputerName
参数不接受管道输入,因为它没有定义为参数属性 ([Parameter()]
)。 - 然后,该函数读取每个字符串并对每个字符串运行
Test-Connection
cmdlet。 - 对于传递的每个字符串计算机名称,它会返回一个具有
ComputerName
和Status
属性的对象。
function Get-ConnectionStatus
{
[CmdletBinding()]
param
(
[Parameter()] ## no pipeline input
[string[]]$ComputerName
)
foreach($c in $ComputerName)
{
if(Test-Connection -ComputerName $c -Quiet -Count 1)
{
$status = 'Ok'
}
else
{
$status = 'No Connection'
}
[pscustomobject]@{
ComputerName = $c
Status = $status
}
}
}
然后,您可以通过向 ComputerName
参数传递一个或多个主机名或 IP 地址来调用 Get-ConnectionStatus
,如下所示。
Get-ConnectionStatus -ComputerName '127.0.0.1', '192.168.1.100'
第 1 步:允许管道输入
要使该函数接受管道输入,必须首先定义适当的参数属性。此属性可以是 ValueFromPipeline
来接受管道输入 ByValue,也可以是 ValueFromPipelineByPropertyName
来接受管道输入 ByPropertyName。
对于本示例,请在 [Parameter()]
定义的括号内添加 ValueFromPipeline
参数属性,如下所示。
[Parameter(ValueFromPipeline)]
[string[]]$ComputerName
此时,从技术上来说,这就是您所要做的全部事情。 Get-ConnectionStatus
函数现在会将传递给它的任何字符串对象绑定到 ComputerName
参数。但是,即使发生参数绑定并不意味着函数会用它做任何有意义的事情。
第 2 步:添加进程块
当您希望 PowerShell 处理来自管道的所有对象时,接下来必须添加一个 Process
块。该块告诉 PowerShell 处理来自管道的每个对象。
如果没有 Process
块,PowerShell 将仅处理来自管道的第一个对象。 Process
块告诉 PowerShell 继续处理对象。
通过包含该函数的所有功能来添加一个 Process 块,如下所示。
function Get-ConnectionStatus
{
[CmdletBinding()]
param
(
[Parameter(ValueFromPipeline)]
[string[]]$ComputerName
)
Process ## New Process block
{
foreach($c in $ComputerName)
{
if(Test-Connection -ComputerName $c -Quiet -Count 1)
{
$status = 'Ok'
}
else
{
$status = 'No Connection'
}
[pscustomobject]@{
ComputerName = $c
Status = $status
}
}
} ## end Process block
}
始终从 Process
块内发送输出。从Process
块内发送输出将对象“流”到管道,允许其他命令从管道接受这些对象。
将对象传递到 PowerShell 管道
在上面的函数中定义了 Process
块后,您现在可以调用该函数,通过管道将值传递给 ComputerName
参数,如下所示。
Get-ConnectionStatus -ComputerName '127.0.0.1', '192.168.1.100'
## or
'127.0.0.1', '192.168.1.100' | Get-ConnectionStatus
此时,您可以利用管道的真正威力并开始将更多命令合并到组合中。例如,您可能有一个文本文件 C:\Test\computers.txt,其中一行 IP 地址通过新行分隔,如下所示。
127.0.0.1
192.168.1.100
然后,您可以使用 Get-Content
cmdlet 读取文本文件中的每个 IP 地址,并将它们直接传递给 Get-ConnectionStatus
函数。
Get-Content -Path C:\Test\computers.txt | Get-ConnectionStatus
将此设置更进一步,您可以将 Get-ConnectionStatus
返回的对象直接通过管道传递给 ForEach-Object
cmdlet。
代码如下:
- 读取文本文件中的所有计算机名称并将它们传递给
Get-ConnectionStatus
函数。 Get-ConnectionStatus
处理每个计算机名称并返回一个具有属性ComputerName
和Status
的对象。- 然后,
Get-ConnectionStatus
将每个对象传递给ForEach-Object
cmdlet,该 cmdlet 随后返回一个颜色为青色且具有人类可读状态的字符串。
Get-Content -Path C:\Test\computers.txt |
Get-ConnectionStatus |
ForEach-Object { Write-Host "$($_.ComputerName) connection status is: $($_.Status)" -ForegroundColor Cyan }
如果 ComputerName
参数上未启用管道输入,或者 Get-ConnectionStatus
未在 Process
块中返回对象,在处理完所有对象(IP 地址)之前,PowerShell 不会向控制台返回任何状态。
按属性名称绑定管道
到目前为止,Get-ConnectionStatus
cmdlet 设置为通过接受诸如 '127.0.0.1', ' 之类的字符串数组来接受管道输入 ByValue (
。如果输入是从 CSV 文件与 IP 地址文本文件接收的,此函数是否也能按预期工作?ValueFromPipeline
) 192.168.1.100'
也许您有一个如下所示的 CSV 文件,位于 C:\Test\pc-list.csv。
ComputerName,Location
127.0.0.1,London
192.168.1.100,Paris
请注意,CSV 文件中的 ComputerName
字段与 Get-ConnnectionStatus
ComputerName
参数的名称相同。
如果您尝试导入 CSV 并将其通过管道传递到 Get-ConnectionStatus
,该函数会在 ComputerName
列中返回意外结果。
Import-Csv -Path 'C:\Test\pc-list.csv' | Get-ConnectionStatus
ComputerName Status
------------ ------
@{ComputerName=127.0.0.1; Location=London} No Connection
@{ComputerName=192.168.1.100; Location=Paris} No Connection
你能猜出出了什么问题吗?毕竟,参数名称确实匹配,那么为什么 PowerShell 管道不将 Import-CSV
返回的输出绑定到 Get-ConnectionStatus 上的
?因为您需要参数属性ComputerName
参数ValueFromPipelineByPropertyName
。
截至目前,该函数的 ComputerName
参数的参数定义类似于 [Parameter(ValueFromPipeline)]
。因此,您必须添加 ValueFromPipelineByPropertyName
来设置 ComputerName
参数以支持输入 ByPropertyName,如下所示。
[CmdletBinding()]
param
(
[Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)]
[string[]]$ComputerName
)
一旦获得管道支持 ByPropertyName,您就可以告诉 PowerShell 开始查看对象属性名称和对象类型。进行此更改后,您应该会看到预期的输出。
PS> Import-Csv -Path 'C:\Test\pc-list.csv' | Get-ConnectionStatus
ComputerName Status
------------ ------
127.0.0.1 Ok
192.168.1.100 No Connection
概括
在本教程中,您了解了 PowerShell 管道的工作原理、它如何绑定参数,甚至如何创建支持 PowerShell 管道的您自己的函数。
尽管函数可以在没有管道的情况下工作,但它们不会将对象从一个命令“流”到另一个命令并简化代码。
您能想到您编写的或即将编写的一个函数可以通过使其管道就绪而受益吗?
猜你还喜欢
- 03-30 [玩转系统] 如何用批处理实现关机,注销,重启和锁定计算机
- 02-14 [系统故障] Win10下报错:该文件没有与之关联的应用来执行该操作
- 01-07 [系统问题] Win10--解决锁屏后会断网的问题
- 01-02 [系统技巧] Windows系统如何关闭防火墙保姆式教程,超详细
- 12-15 [玩转系统] 如何在 Windows 10 和 11 上允许多个 RDP 会话
- 12-15 [玩转系统] 查找 Exchange/Microsoft 365 中不活动(未使用)的通讯组列表
- 12-15 [玩转系统] 如何在 Windows 上安装远程服务器管理工具 (RSAT)
- 12-15 [玩转系统] 如何在 Windows 上重置组策略设置
- 12-15 [玩转系统] 如何获取计算机上的本地管理员列表?
- 12-15 [玩转系统] 在 Visual Studio Code 中连接到 MS SQL Server 数据库
- 12-15 [玩转系统] 如何降级 Windows Server 版本或许可证
- 12-15 [玩转系统] 如何允许非管理员用户在 Windows 中启动/停止服务
取消回复欢迎 你 发表评论:
- 精品推荐!
-
- 最新文章
- 热门文章
- 热评文章
[影视] 黑道中人 Alto Knights(2025)剧情 犯罪 历史 电影
[古装剧] [七侠五义][全75集][WEB-MP4/76G][国语无字][1080P][焦恩俊经典]
[实用软件] 虚拟手机号 电话 验证码 注册
[电视剧] 安眠书店/你 第五季 You Season 5 (2025) 【全10集】
[电视剧] 棋士(2025) 4K 1080P【全22集】悬疑 犯罪 王宝强 陈明昊
[软件合集] 25年6月5日 精选软件22个
[软件合集] 25年6月4日 精选软件36个
[短剧] 2025年06月04日 精选+付费短剧推荐33部
[短剧] 2025年06月03日 精选+付费短剧推荐25部
[软件合集] 25年6月3日 精选软件44个
[剧集] [央视][笑傲江湖][2001][DVD-RMVB][高清][40集全]李亚鹏、许晴、苗乙乙
[电视剧] 欢乐颂.5部全 (2016-2024)
[电视剧] [突围] [45集全] [WEB-MP4/每集1.5GB] [国语/内嵌中文字幕] [4K-2160P] [无水印]
[影视] 【稀有资源】香港老片 艺坛照妖镜之96应召名册 (1996)
[剧集] 神经风云(2023)(完结).4K
[剧集] [BT] [TVB] [黑夜彩虹(2003)] [全21集] [粤语中字] [TV-RMVB]
[实用软件] 虚拟手机号 电话 验证码 注册
[资源] B站充电视频合集,包含多位重量级up主,全是大佬真金白银买来的~【99GB】
[影视] 内地绝版高清录像带 [mpg]
[书籍] 古今奇书禁书三教九流资料大合集 猎奇必备珍藏资源PDF版 1.14G
[电视剧] [突围] [45集全] [WEB-MP4/每集1.5GB] [国语/内嵌中文字幕] [4K-2160P] [无水印]
[剧集] [央视][笑傲江湖][2001][DVD-RMVB][高清][40集全]李亚鹏、许晴、苗乙乙
[电影] 美国队长4 4K原盘REMUX 杜比视界 内封简繁英双语字幕 49G
[电影] 死神来了(1-6)大合集!
[软件合集] 25年05月13日 精选软件16个
[精品软件] 25年05月15日 精选软件18个
[绝版资源] 南与北 第1-2季 合集 North and South (1985) /美国/豆瓣: 8.8[1080P][中文字幕]
[软件] 25年05月14日 精选软件57个
[短剧] 2025年05月14日 精选+付费短剧推荐39部
[短剧] 2025年05月15日 精选+付费短剧推荐36部
- 最新评论
-
- 热门tag