Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerCLI strange behaviour of variable

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

like image 487
Askar Kopbayev Avatar asked Mar 28 '26 20:03

Askar Kopbayev


1 Answers

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.

like image 137
Mark Wragg Avatar answered Apr 02 '26 13:04

Mark Wragg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!