Powershell PipelineVariable использует последнее значение - PullRequest
1 голос
/ 04 февраля 2020

У меня происходит странная ошибка. Я строю запрос и получаю странную ошибку. Когда я выполняю эту команду Powershell:

Get-CimInstance -Class Win32_DiskDrive -Filter 'MediaType = "Removable Media"' -KeyOnly | ForEach-Object {$Details = $_.PNPDeviceID;$_}|
Get-CimAssociatedInstance -Association Win32_DiskDriveToDiskPartition -KeyOnly |
Get-CimAssociatedInstance -Association Win32_LogicalDiskToPartition |
Select-Object Name, @{ n='SerialNumber'; e={$Details.split("\")[-1].split("&")[0]}}

Моя переменная $ Details одинакова для обоих объектов

Name SerialNumber
---- ------------
F:   4C530001090425122264
E:   4C530001090425122264

Более дружественный пример:

Get-CimInstance Win32_Diskdrive -PipelineVariable disk |
Get-CimAssociatedInstance -ResultClassName Win32_DiskPartition -PipelineVariable partition |
Get-CimAssociatedInstance -ResultClassName Win32_LogicalDisk |
Select-Object @{n='Disk';e={$disk.deviceid}},
@{n='DiskSize';e={$disk.size}},
@{n='DiskModel';e={$disk.model}},
@{n='Partition';e={$partition.name}},
@{n='RawSize';e={$partition.size}},
@{n='DriveLetter';e={$_.DeviceID}},
VolumeName,Size,FreeSpace

Все есть нормально, пока я все не передам в первую ассоциацию, после этого переменная $ Details одинакова для обоих объектов.

1 Ответ

1 голос
/ 04 февраля 2020

Ваш подход - либо через переменную, установленную в блоке ForEach-Object, либо через переменную, установленную с помощью
-PipelineVariable общего параметра - , работает только в том случае, если все последующие командлеты в том же конвейере обрабатывают и выводят свои входные объекты один за другим , по мере их получения .

Подход не работает с командлетами, которые (должны) агрегировать все вводят сначала , до передачи результатов, яркими примерами которых являются Sort-Object и Group-Object.

Для чего может быть из соображений производительности, Get-CimAssociatedInstance также, по-видимому, выполняет такое агрегирование : он собирает всех объектов, полученных через конвейер, перед созданием вывод на их основе. Результат net состоит в том, что $Details / $disk содержит только информацию о последнем Win32_DiskDrive экземпляре в остальной части конвейера.

Обходное решение :

За счет производительности , оберните ваши Get-CimAssociatedInstance вызовы в ForEach-Object блоках, чтобы они обрабатывали каждый входной объект один за другим .

Вот упрощенный пример:

# NOTE: Get-CimAssociatedInstance is called *inside a ForEach-Object* block.
Get-CimInstance Win32_Diskdrive -PipelineVariable drive |
  ForEach-Object { $_ | Get-CimAssociatedInstance -ResultClassName Win32_DiskPartition } |
    Select-Object Name, @{ n='PNPDeviceId'; e = { $drive.PnpDeviceId } }

Вы увидите что-то похожее на следующее, показывающее соответствующие ID диска устройства PNP для каждого раздела:

Name                  PNPDeviceId
----                  -----------
Disk #0, Partition #0 SCSI\DISK&VEN_VMWARE_&PROD_VMWARE_VIRTUAL_S\5&1EC51BF7&0&000000
Disk #0, Partition #1 SCSI\DISK&VEN_VMWARE_&PROD_VMWARE_VIRTUAL_S\5&1EC51BF7&0&000000
Disk #1, Partition #0 USBSTOR\DISK&VEN_PI-201&PROD_SATA/USB20_DRIVE&REV_1.04\071008DP1D00DFG0484N____&0

Без обертки ForEach-Object вокруг Get-CimAssociatedInstance все PNPDeviceId были бы одинаковыми (значение диска last ).

Примечание : Обходной путь ForEach-Object работает только с командлетами, которые могут эффективно обрабатывать отдельных объектов ввода . Это не будет работать для командлетов, таких как Sort-Object, которые должны сначала собрать все входные данные (чтобы произвести сортировку по всем входным объектам).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...