PowerCLI variable behavior strange
An attempt was made to collect several properties of virtual machines, but for some reason all output records only contain information about the last virtual machine
$CSV
basically contains a couple of virtual machine 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 information 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 see that after the first loop, the $line
correct VM Centos1 information is updated and then added to $VMData
.
However, when the second loop starts, for example after execution, line.VMName = $entry.VMname
I see both variables $line
and $VMData
are updated with the name CentOS2.
So my question is, why is it $VMData
updated along with $line
?
I've used this piece of code before and it worked great.
I am running the following PS version
Major Minor Build Revision
----- ----- ----- --------
5 1 14393 1480
VMware PowerCLI 6.5 Release 1 build 4624819
source to share
You can fix this by moving the part $line = ''
inside the loop 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
I believe the problem occurs because in this case the PowerShell variable acts as a pointer (reference type), so when updated a $line
second time, it actually affects the existing result in $vmdata
.
By moving $line = ''
around inside the loop, you reset the variable on each iteration so that it doesn't fire that way.
I really recommend that 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 hash table to create a PowerShell object in a ForEach-Object loop, which you can then pipe the output to Export-CSV directly.
source to share