Как работает $ _ при конвейере в PowerShell? - PullRequest
0 голосов
/ 24 мая 2019

Я запутался, как переменная $ _ работает в определенных контекстах трубопровода. В этом примере для резервного копирования ключа 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;}

Итак, для всего блока, заключенного в скобки {}, будет ли переменная $ _ ВСЕГДА одинаковой для любого количества трубопроводов? Например, объект, который мы передаем по конвейеру, меняется. Это больше не объект BitLockerVolume, а объект KeyProtector. Так будет ли $ _ всегда ссылаться на объект BitLockerVolume в этом случае, или он будет меняться дальше по конвейеру в зависимости от различных типов объектов, передаваемых далее по цепочке?

Ответы [ 4 ]

3 голосов
/ 24 мая 2019

Таким образом, $ _ является информацией из текущего канала.

1,2 | %{
    $_
}

response

1
2

, в то время как

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

response

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 разных канала.Первый получает «БитлокерВолюмволюме».Вторая начинается с отправки BitlockerVolume's KeyProtector.

Это все равно, что сказать

Для каждого тома Bitlocker, Get KeyProtector.

Для каждого KeyProtector, получите мне те, которые имеютэлемент RecoveryPassword

Foreach KeyProtector с элементом RecoveryPassword, резервная защита ключа BitLocker с использованием точек монтирования KeyProtector

Так что в одном последнем замечании я бы также предположил, что приведенный вами пример не будет работать.То, что вы можете искать, это ...

Get-BitlockerVolume | % {
    $MountPoint = $_.MountPoint
    $_.KeyProtector | ? RecoveryPassword | Backup-BitlockerKeyProtector -MountPoint $MountPoint -KeyProtectorId $_.KeyProtectorId
}
1 голос
/ 24 мая 2019

Давайте расширим псевдонимы и заполните предполагаемые параметры. $ _ можно использовать только внутри блоков скриптов '{}', которые являются опциями для командлетов. То, что вы находитесь в трубе, не означает, что вы можете использовать $ _. $ _ Здесь принадлежит Foreach-Object. Where-Object использует оператор сравнения.

Get-BitlockerVolume | Foreach-Object -Process {
  $_.KeyProtector | Where-Object -Property RecoveryPassword | 
    Backup-BitlockerKeyProtector -MountPoint $_.MountPoint
}
0 голосов
/ 24 мая 2019

Я бы хотел немного поработать над ответом ArcSet .Так как я наконец понял, что значение $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, и ссылаемся на переменную $PSItem, известную как $_, тогда он будет ссылаться на типы объектов, которые были переданы в последний раз.конвейер, в этом случае объекты будут иметь тип BitLockerVolumeKeyProtector.

0 голосов
/ 24 мая 2019

Я знаю, что здесь уже есть хорошие ответы, но я чувствую, что один важный вопрос не был рассмотрен.Вопрос о том, что происходит с $_ по всему блоку Foreach-Object {} , когда существует вложение.Я собираюсь использовать пример ArcSet, так как это был выбран ответ.

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

Обратите внимание, что $_ становится текущим объектом, обрабатываемым кодом внутри блоков Foreach-Object {}.При входе во второй блок Foreach-Object, $_ изменяется.При выходе из второго блока Foreach-Object $_ возвращается обратно к объекту, который будет продолжаться для обработки оставшейся частью первого блока.Таким образом, $_ не остается прежним и не теряется при обработке блока.Вам нужно будет либо присвоить $_ в качестве другой переменной, либо в соответствующих ситуациях использовать переключатель -PipelineVariable для доступа к этим объектам в разных блоках.

...