当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 单衬管和管道

作者:精品下载站 日期:2024-12-14 03:05:56 浏览:14 分类:玩电脑

单衬管和管道


当我第一次开始学习 PowerShell 时,如果我无法使用 PowerShell 一行代码完成任务,我就会回到 GUI。随着时间的推移,我逐渐掌握了编写脚本、函数和模块的技能。不要让自己被互联网上看到的一些更高级的示例所淹没。没有人是天生的 PowerShell 专家。我们都曾经是初学者。

对于仍在使用 GUI 进行管理的人,我有一些建议:在管理工作站上安装管理工具并远程管理服务器。这样,无论服务器运行的是 GUI 还是服务器核心安装的操作系统,都无关紧要。它将帮助您做好使用 PowerShell 远程管理服务器的准备。

与前面的章节一样,请务必在 Windows 10 实验室环境计算机上进行操作。

One-Liners

PowerShell 单行是一条连续的管道,不一定是一条物理行上的命令。并非一根物理行上的所有命令都是单行命令。

尽管以下命令位于多个物理行上,但它是一个 PowerShell 单行命令,因为它是一个连续的管道。它可以写在一根物理行上,但我选择在管道符号处换行。管道符号是 PowerShell 中允许自然换行的字符之一。

Get-Service |
  Where-Object CanPauseAndContinue -eq $true |
    Select-Object -Property *
Name                : LanmanWorkstation
RequiredServices    : {NSI, MRxSmb20, Bowser}
CanPauseAndContinue : True
CanShutdown         : False
CanStop             : True
DisplayName         : Workstation
DependentServices   : {SessionEnv, Netlogon, Browser}
MachineName         : .
ServiceName         : LanmanWorkstation
ServicesDependedOn  : {NSI, MRxSmb20, Bowser}
ServiceHandle       : SafeServiceHandle
Status              : Running
ServiceType         : Win32ShareProcess
StartType           : Automatic
Site                :
Container           :

Name                : Netlogon
RequiredServices    : {LanmanWorkstation}
CanPauseAndContinue : True
CanShutdown         : False
CanStop             : True
DisplayName         : Netlogon
DependentServices   : {}
MachineName         : .
ServiceName         : Netlogon
ServicesDependedOn  : {LanmanWorkstation}
ServiceHandle       : SafeServiceHandle
Status              : Running
ServiceType         : Win32ShareProcess
StartType           : Automatic
Site                :
Container           :

Name                : vmicheartbeat
RequiredServices    : {}
CanPauseAndContinue : True
CanShutdown         : False
CanStop             : True
DisplayName         : Hyper-V Heartbeat Service
DependentServices   : {}
MachineName         : .
ServiceName         : vmicheartbeat
ServicesDependedOn  : {}
ServiceHandle       : SafeServiceHandle
Status              : Running
ServiceType         : Win32ShareProcess
StartType           : Manual
Site                :
Container           :

Name                : vmickvpexchange
RequiredServices    : {}
CanPauseAndContinue : True
CanShutdown         : False
CanStop             : True
DisplayName         : Hyper-V Data Exchange Service
DependentServices   : {}
MachineName         : .
ServiceName         : vmickvpexchange
ServicesDependedOn  : {}
ServiceHandle       : SafeServiceHandle
Status              : Running
ServiceType         : Win32ShareProcess
StartType           : Manual
Site                :
Container           :

Name                : vmicrdv
RequiredServices    : {}
CanPauseAndContinue : True
CanShutdown         : False
CanStop             : True
DisplayName         : Hyper-V Remote Desktop Virtualization Service
DependentServices   : {}
MachineName         : .
ServiceName         : vmicrdv
ServicesDependedOn  : {}
ServiceHandle       : SafeServiceHandle
Status              : Running
ServiceType         : Win32ShareProcess
StartType           : Manual
Site                :
Container           :

Name                : vmicshutdown
RequiredServices    : {}
CanPauseAndContinue : True
CanShutdown         : False
CanStop             : True
DisplayName         : Hyper-V Guest Shutdown Service
DependentServices   : {}
MachineName         : .
ServiceName         : vmicshutdown
ServicesDependedOn  : {}
ServiceHandle       : SafeServiceHandle
Status              : Running
ServiceType         : Win32ShareProcess
StartType           : Manual
Site                :
Container           :

Name                : vmictimesync
RequiredServices    : {VmGid}
CanPauseAndContinue : True
CanShutdown         : False
CanStop             : True
DisplayName         : Hyper-V Time Synchronization Service
DependentServices   : {}
MachineName         : .
ServiceName         : vmictimesync
ServicesDependedOn  : {VmGid}
ServiceHandle       : SafeServiceHandle
Status              : Running
ServiceType         : Win32ShareProcess
StartType           : Manual
Site                :
Container           :

Name                : vmicvss
RequiredServices    : {}
CanPauseAndContinue : True
CanShutdown         : False
CanStop             : True
DisplayName         : Hyper-V Volume Shadow Copy Requestor
DependentServices   : {}
MachineName         : .
ServiceName         : vmicvss
ServicesDependedOn  : {}
ServiceHandle       : SafeServiceHandle
Status              : Running
ServiceType         : Win32ShareProcess
StartType           : Manual
Site                :
Container           :

Name                : Winmgmt
RequiredServices    : {RPCSS}
CanPauseAndContinue : True
CanShutdown         : True
CanStop             : True
DisplayName         : Windows Management Instrumentation
DependentServices   : {wscsvc, NcaSvc, iphlpsvc}
MachineName         : .
ServiceName         : Winmgmt
ServicesDependedOn  : {RPCSS}
ServiceHandle       : SafeServiceHandle
Status              : Running
ServiceType         : Win32ShareProcess
StartType           : Automatic
Site                :
Container           :

常用字符处可能会出现自然换行符,包括逗号 (,) 和左方括号 ([)、大括号 ({) 和圆括号 (其他不太常见的包括分号 (;)、等号 (=) 以及单引号和双引号。引号 (',")。

使用反引号 (`) 或重音字符作为行继续字符是一个有争议的话题。我的建议是尽可能避免它。我经常看到在自然换行符之后立即使用反引号编写 PowerShell 命令。它没有理由在那里。

Get-Service -Name w32time |
>> Select-Object -Property *
Name                : w32time
RequiredServices    : {}
CanPauseAndContinue : False
CanShutdown         : True
CanStop             : True
DisplayName         : Windows Time
DependentServices   : {}
MachineName         : .
ServiceName         : w32time
ServicesDependedOn  : {}
ServiceHandle       : SafeServiceHandle
Status              : Running
ServiceType         : Win32ShareProcess
StartType           : Manual
Site                :
Container           :

前两个示例中显示的命令在 PowerShell 控制台中运行良好。但如果您尝试在 PowerShell ISE 的控制台窗格中运行它们,它们将生成错误。 PowerShell ISE 的控制台窗格不会像 PowerShell 控制台那样等待在下一行输入命令的其余部分。要避免在 PowerShell ISE 的控制台窗格中出现此问题,请在继续执行另一行命令时使用 Shift+Enter,而不是仅按 Enter 。

下一个示例不是 PowerShell 单行代码,因为它不是一个连续的管道。它是一行中的两个单独的命令,用分号分隔。

$Service = 'w32time'; Get-Service -Name $Service
Status   Name               DisplayName
------   ----               -----------
Running  w32time            Windows Time

许多编程和脚本语言需要在每行末尾有一个分号。虽然它们可以在 PowerShell 中以这种方式使用,但不建议这样做,因为不需要它们。

向左过滤

本章中显示的命令的结果已被过滤为一个子集。例如,Get-ServiceName 参数一起使用来筛选仅返回到 Windows 时间服务的服务列表。

在管道中,您总是希望尽早将结果过滤到您要查找的内容。这是使用第一个命令或最左边的命令上的参数来完成的。这有时称为左过滤

以下示例使用 Get-ServiceName 参数立即将结果筛选到仅 Windows 时间服务。

Get-Service -Name w32time
Status   Name               DisplayName
------   ----               -----------
Running  w32time            Windows Time

将命令通过管道传送到 Where-Object 来执行过滤的示例并不罕见。

Get-Service | Where-Object Name -eq w32time
Status   Name               DisplayName
------   ----               -----------
Running  W32Time            Windows Time

第一个示例在源处进行筛选,仅返回 Windows 时间服务的结果。第二个示例返回所有服务,然后将它们传送到另一个命令以执行过滤。虽然在本例中这似乎不是什么大问题,但想象一下如果您正在查询 Active Directory 用户列表。您是否真的想从 Active Directory 返回数千个用户帐户的信息,只是为了将它们传送到另一个命令,将它们过滤到一个很小的子集?我的建议是始终过滤左侧,即使它看起来并不重要。你会习惯它,当它确实重要时,你会自动过滤左侧。

曾经有人告诉我,指定命令的顺序并不重要。这与事实相差甚远。在执行过滤时,指定命令的顺序确实很重要。例如,请考虑以下场景:您使用 Select-Object 仅选择几个属性,并使用 Where-Object 筛选不在选择范围内的属性。在这种情况下,必须首先进行过滤,否则在尝试执行过滤时该属性将不存在于管道中。

Get-Service |
Select-Object -Property DisplayName, Running, Status |
Where-Object CanPauseAndContinue

上例中的命令不会返回任何结果,因为当 Select-Object 的结果通过管道传输到 Where-Object 时,CanPauseAndContinue 属性不存在。该特定属性未被“选择”。本质上,它被过滤掉了。颠倒 Select-ObjectWhere-Object 的顺序会产生所需的结果。

Get-Service |
Where-Object CanPauseAndContinue |
Select-Object -Property DisplayName, Status
DisplayName                                    Status
-----------                                    ------
Workstation                                    Running
Netlogon                                       Running
Hyper-V Heartbeat Service                      Running
Hyper-V Data Exchange Service                  Running
Hyper-V Remote Desktop Virtualization Service  Running
Hyper-V Guest Shutdown Service                 Running
Hyper-V Time Synchronization Service           Running
Hyper-V Volume Shadow Copy Requestor           Running
Windows Management Instrumentation             Running

管道

正如您在本书到目前为止所展示的许多示例中所看到的那样,很多时候一个命令的输出可以用作另一命令的输入。在第 3 章中,Get-Member 用于确定命令生成的对象类型。第 3 章还展示了如何使用 Get-Command 的 ParameterType 参数来确定哪些命令接受该类型的输入,尽管不一定是通过管道输入。

根据命令帮助的彻底程度,它可能包括输入输出部分。

help Stop-Service -Full
...
INPUTS
    System.ServiceProcess.ServiceController, System.String
        You can pipe a service object or a string that contains the name of a service
        to this cmdlet.

OUTPUTS
    None, System.ServiceProcess.ServiceController
        This cmdlet generates a System.ServiceProcess.ServiceController object that
        represents the service, if you use the PassThru parameter. Otherwise, this
        cmdlet does not generate any output.
...

前面的结果中只显示了帮助的相关部分。如您所见,INPUTS 部分指出可以将 ServiceControllerString 对象通过管道传输到 Stop-Service cmdlet。它不会告诉您哪些参数接受该类型的输入。确定该信息的最简单方法之一是查看 Stop-Service cmdlet 完整版帮助中的不同参数。

help Stop-Service -Full
...
-DisplayName <String[]>
    Specifies the display names of the services to stop. Wildcard characters are
    permitted.

    Required?                    true
    Position?                    named
    Default value                None
    Accept pipeline input?       False
    Accept wildcard characters?  false

-InputObject <ServiceController[]>
    Specifies ServiceController objects that represent the services to stop. Enter a
    variable that contains the objects, or type a command or expression that gets the
    objects.

    Required?                    true
    Position?                    0
    Default value                None
    Accept pipeline input?       True (ByValue)
    Accept wildcard characters?  false

-Name <String[]>
    Specifies the service names of the services to stop. Wildcard characters are
    permitted.

    Required?                    true
    Position?                    0
    Default value                None
    Accept pipeline input?       True (ByPropertyName, ByValue)
    Accept wildcard characters?  false
...

再次,我只显示了上一组结果中帮助的相关部分。请注意,DisplayName 参数不接受管道输入,InputObject 参数接受 ServiceController按值管道输入对象,名称参数接受字符串对象的按值管道输入。它还接受按属性名称的管道输入。

当参数通过属性名称和值接受管道输入时,它始终首先尝试按值。如果按值失败,则会尝试按属性名称按价值有点误导。我更喜欢按类型称呼它。这意味着,如果您将生成 ServiceController 对象类型的命令的结果通过管道传输到 Stop-Service,它会将该输入绑定到 InputObject 参数。但是,如果您将生成 String 输出的命令结果通过管道传输到 Stop-Service,它会将其绑定到 Name 参数。如果您将不生成 ServiceControllerString 对象的命令结果通过管道传输到 Stop-Service,但它确实生成包含以下内容的输出:名为 Name 的属性,然后它将输出中的 Name 属性绑定到 Stop-ServiceName 参数。

确定 Get-Service 命令生成的输出类型。

Get-Service -Name w32time | Get-Member
   TypeName: System.ServiceProcess.ServiceController

Get-Service 生成 ServiceController 对象类型。

正如您之前在帮助中看到的,Stop-ServiceInputObject 参数通过管道按值接受 ServiceController 对象>(按类型)。这意味着当 Get-Service cmdlet 的结果通过管道传输到 Stop-Service 时,它们会绑定到 InputObject 参数停止服务

Get-Service -Name w32time | Stop-Service

现在尝试字符串输入。将 w32time 通过管道传递给 Get-Member 只是为了确认它是一个字符串。

'w32time' | Get-Member
   TypeName: System.String

如之前帮助中所示,通过管道将字符串传递给 Stop-Service按值将其绑定到 Stop-Service 的 Name 参数。通过将 w32time 通过管道传输到 Stop-Service 来测试这一点。

'w32time' | Stop-Service

请注意,在前面的示例中,我在字符串 w32time 周围使用了单引号。在 PowerShell 中,应始终使用单引号而不是双引号,除非带引号的字符串的内容包含需要扩展到其实际值的变量。通过使用单引号,PowerShell 不必解析引号内包含的内容,因此您的代码运行速度会更快一些。

创建一个自定义对象,以通过 Stop-ServiceName 参数的属性名称测试管道输入。

$CustomObject = [pscustomobject]@{
 Name = 'w32time'
 }

CustomObject 变量的内容是 PSCustomObject 对象类型,并且包含名为 Name 的属性。

$CustomObject | Get-Member
   TypeName: System.Management.Automation.PSCustomObject

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
Name        NoteProperty string Name=w32time

如果要用引号将 $CustomObject 变量引起来,则需要使用双引号。否则,使用单引号,文字字符串 $CustomObject 将通过管道传输到 Get-Member,而不是变量包含的值。

尽管将 $CustomObject 的内容通过管道传输到 Stop-Service cmdlet 会绑定到 Name 参数,但这次它通过属性名称

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯