Странное поведение переменной PowerCLI

Пытаюсь собрать несколько свойств ВМ, но по каким-то причинам все записи в выводе содержат информацию только о последней ВМ

$CSV в основном содержит несколько имен виртуальных машин:

VMName
Centos1
Centos2

Вот код, который я использую:

$VMdata = @()
$line = '' | Select VMName, VMToolStatus, VMToolVersion, UUID, Tag, Notes

foreach($entry in $csv){
    $line.VMName = $entry.VMname
    $line.VMToolStatus = (get-vm $entry.VMname).ExtensionData.Guest.ToolsRunningStatus
    $line.VMToolVersion = (get-vm $entry.VMname).ExtensionData.Guest.ToolsVersion
    $line.UUID = (get-vm $entry.VMname).ExtensionData.Config.UUID
    $line.Notes = (get-vm $entry.VMname).Notes
    $line.Tag = get-vm $entry.VMname | Get-TagAssignment | Select -ExpandProperty Tag  | select Name
    $VMdata += $line
}

$VMdata | Export-Csv -Path c:\report.csv -NoTypeInformation -Force

вот вывод CSV - как видите, обе строки содержат информацию о VM Centos2.

"VMName","VMToolStatus","VMToolVersion","UUID","Tag","Notes","StartupOrder"

"CentOS2","guestToolsRunning","2147483647","564d7fd7-e58f-e546-ecdf-c347e35cd453",,"Test Note",

"CentOS2","guestToolsRunning","2147483647","564d7fd7-e58f-e546-ecdf-c347e35cd453",,"Test Note",

Когда я его отлаживаю, я вижу, что после первого цикла $line обновляется правильной информацией о VM Centos1, а затем добавляется к $VMData.

Однако, когда начинается второй цикл, т.е. после выполнения line.VMName = $entry.VMname я вижу, что обе переменные $line и $VMdata обновляются именем CentOS2.

Итак, мой вопрос: почему $VMdata обновляется вместе с $line?

Я использовал этот фрагмент кода раньше, и он работал нормально.

Я использую следующую версию PS

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      14393  1480 

VMware PowerCLI 6.5, выпуск 1, сборка 4624819


person Askar Kopbayev    schedule 28.07.2017    source источник


Ответы (1)


Вы можете исправить это, переместив часть $line = '' внутрь цикла ForEach:

$VMdata = @()

foreach($entry in $csv){
    $line = '' | Select VMName, VMToolStatus, VMToolVersion, UUID, Tag, Notes
    $line.VMName = $entry.VMname
    $line.VMToolStatus = (get-vm $entry.VMname).ExtensionData.Guest.ToolsRunningStatus
    $line.VMToolVersion = (get-vm $entry.VMname).ExtensionData.Guest.ToolsVersion
    $line.UUID = (get-vm $entry.VMname).ExtensionData.Config.UUID
    $line.Notes = (get-vm $entry.VMname).Notes
    $line.Tag = get-vm $entry.VMname | Get-TagAssignment | Select -ExpandProperty Tag  | select Name
    $VMdata += $line
}

$VMdata | Export-Csv -Path c:\report.csv -NoTypeInformation -Force

Я считаю, что проблема возникает из-за того, что в этом случае переменная PowerShell действует как указатель (ссылочный тип), поэтому, когда вы обновляете $line во второй раз, это фактически влияет на существующий результат в $vmdata.

Перемещая $line = '' внутри цикла, вы сбрасываете переменную на каждой итерации, чтобы она не действовала таким образом.

Однако на самом деле я рекомендую вам сделать это вместо этого:

$CSV | ForEach-Object {
    $Props = @{
        VMName = $_.VMname
        VMToolStatus = (get-vm $_.VMname).ExtensionData.Guest.ToolsRunningStatus
        VMToolVersion = (get-vm $_.VMname).ExtensionData.Guest.ToolsVersion
        UUID = (get-vm $_.VMname).ExtensionData.Config.UUID
        Notes = (get-vm $_.VMname).Notes
        Tag = (get-vm $_.VMname | Get-TagAssignment | Select -ExpandProperty Tag  | select Name)
    }
    New-Object -TypeName PSObject -Property $Props
} | Export-Csv -Path c:\report.csv -NoTypeInformation -Force

При этом используется хеш-таблица для создания объекта PowerShell в цикле ForEach-Object, в который вы можете передать выходные данные непосредственно в Export-CSV.

person Mark Wragg    schedule 28.07.2017
comment
К вашему сведению, я только что добавил второе решение, которое немного чище с точки зрения кода. - person Mark Wragg; 28.07.2017