在PowerShell中进行管道输送时,$ _如何工作?

时间:2019-05-24 14:51:41

标签: powershell pipe

我很困惑$ _变量在管道的某些情况下如何工作。在此示例中,用于备份Bitlocker密钥:

Get-BitlockerVolume | % {$_.KeyProtector | ? RecoveryPassword | Backup-BitlockerKeyProtector -MountPoint $_.MountPoint}

这是我用英语阅读的方式:

  • 获取所有BitLockerVolume对象
  • 对于每个BitLockerVolume对象,将KeyProtector字段通过管道转发
  • 管道KeyProtector对象进一步转发给具有RecoverPassword的对象
  • 运行Backup-BitlockerKeyProtector,并提供MountPoint

但是,MountPoint是BitLockerVolume对象的字段,如下所示:

PS C:\Windows\system32> Get-BitLockerVolume | Get-Member | Where-Object {$_.Name -eq "MountPoint"}


   TypeName: Microsoft.BitLocker.Structures.BitLockerVolume

Name       MemberType Definition
----       ---------- ----------
MountPoint Property   string MountPoint {get;}

因此,对于包裹在braccet {}中的整个块,在任何数量的管道传输中,$ _变量是否总是相同?例如,我们正在管道传输的对象正在更改。它不再是BitLockerVolume对象,而是一个KeyProtector对象。那么,在这种情况下,$ _是否始终引用BitLockerVolume对象,还是根据在链中进一步传递的对象的不同类型,它会进一步在管道中更改?

4 个答案:

答案 0 :(得分:3)

所以$ _是当前管道的信息。

1,2 | %{
    $_
}

响应

1
2

同时

1,2 | %{
    "a","b" | %{
        $_
    }
}

响应

a
b
a
b

我们首先可以看到%_的输出来自给定的最后一个信息1,2。尽管下一个示例仍然循环1,2,但是输出来自a,b内部的管道。

可以通过将第一个管道信息存储到第二个管道的变量中来解决此问题

1,2 | %{
    $Num = $_
    "a","b" | %{
        $Num
    }
}

哪种情况下输出是

1
1
2
2

在您给出的示例中,让我们看一下它的格式

Get-BitlockerVolume | % {
    $_.KeyProtector | ? RecoveryPassword | Backup-BitlockerKeyProtector -MountPoint $_.MountPoint
}

您有2个不同的管道。首先是获取“ BitlockerVolumevolume”。 第二个步骤是您发送BitlockerVolume's KeyProtector

这就像在说

对于每个Bitlocker卷,获取KeyProtector。

对于每个KeyProtector,请给我一个具有RecoveryPassword成员的人

具有成员RecoveryPassword的Foreach KeyProtector,使用KeyProtector的挂载点的备份Bitlocker密钥保护器

因此,最后一点,我还要假设您给出的示例无效。 您可能正在寻找的是这个...

Get-BitlockerVolume | % {
    $MountPoint = $_.MountPoint
    $_.KeyProtector | ? RecoveryPassword | Backup-BitlockerKeyProtector -MountPoint $MountPoint -KeyProtectorId $_.KeyProtectorId
}

答案 1 :(得分:1)

让我们扩展别名并填写隐含参数。 $ _只能在脚本块'{}'内使用,这些脚本块是cmdlet的选项。仅仅因为您在管道中,并不意味着您可以使用$ _。这里的$ _属于Foreach-Object。 Where-Object使用比较语句。

Get-BitlockerVolume | Foreach-Object -Process {
  $_.KeyProtector | Where-Object -Property RecoveryPassword | 
    Backup-BitlockerKeyProtector -MountPoint $_.MountPoint
}

答案 2 :(得分:0)

我知道这里已经有了不错的答案,但是我感到一个重要的问题没有得到解决。在整个嵌套$_时,Foreach-Object {}块中1,2 | % { "$_ before second foreach" 'a','b' | % { "$_ inside second foreach" } "$_ after second foreach" } 1 before second foreach a inside second foreach b inside second foreach 1 after second foreach 2 before second foreach a inside second foreach b inside second foreach 2 after second foreach 会发生什么的问题。我将使用ArcSet的示例,因为这是选择的答案。

$_

请注意,Foreach-Object {}成为Foreach-Object块中的代码正在处理的当前对象。进入第二个$_块时,Foreach-Object发生变化。退出第二个$_块时,$_ 变回到将被继续处理的对象,并由第一个块的其余部分处理。因此$_在块处理期间既不保持不变也不丢失。您将需要将-PipelineVariable分配为另一个变量,或者在适用情况下使用{{1}}开关来访问不同块中的那些对象。

答案 3 :(得分:0)

Id'仅需要一点点在ArcSet的answer上构建。由于我最终了解到$PSItem的值在类型沿管道更改时会发生变化,因此我运行了这段代码进行一些检查。

Get-BitLockerVolume | % {$_.GetType()}

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    BitLockerVolume                          System.Object
True     False    BitLockerVolume                          System.Object
True     False    BitLockerVolume                          System.Object

在这里我们可以看到管道返回的某些对象是BitLockerVolume类型的。

现在,根据我的原始问题/示例,如果我们进一步基于KeyProtector用管道传输对象,则$PSItem变量的对象类型将更改。

Get-BitLockerVolume | % { $_.KeyProtector | ? RecoveryPassword  | % {$_.GetType()}}

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    BitLockerVolumeKeyProtector              System.Object
True     False    BitLockerVolumeKeyProtector              System.Object

因此,在流水线的最后,我们执行其他Backup-BitlockerKeyProtector这样的cmdlet,并引用$PSItem变量(又名$_),然后它将引用该对象类型最后一次通过管道传递,在这种情况下,对象将是BitLockerVolumeKeyProtector类型。