3

Trying to collect few properties of VMs, but for some reasons all entries in the output contains the info about the last VM only

The $CSV basically contains a couple of VM names:

VMName
Centos1
Centos2

Here is the code I'm using:

$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

here is the CSV output - as you can see both lines contain info about 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",

When I debug it I can see that after first cycle $line is updated with correct information of VM Centos1 and then it is added to $VMData.

However, when the second cycle starts, e.g. after executing line.VMName = $entry.VMname I can see that both variables $line and $VMdata are updated with CentOS2 name.

So, my question is why $VMdata gets updated along with $line?

I used this piece of code before and it worked just fine.

I am running the following version of PS

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

VMware PowerCLI 6.5 Release 1 build 4624819

Mark Wragg
  • 22,105
  • 7
  • 39
  • 68

1 Answers1

4

You can fix this by moving the $line = '' part inside the ForEach loop:

$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

I believe the problem occurs because in this instance the PowerShell variable is acting like a pointer (a reference type), so when you update $line the second time it actually affects the existing result in $vmdata.

By moving $line = '' inside the loop you reset the variable on each iteration so it doesn't act this way.

I actually however recommend you do this instead:

$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

This uses a hashtable to create a PowerShell object within a ForEach-Object loop which you can then pipe the output to directly to Export-CSV.

Mark Wragg
  • 22,105
  • 7
  • 39
  • 68