PSCustomObject not working as expected

Hello,

Trying to build a .CSV report with information extracted from PowerCLI. The Write-Host shows all the relevant data, but the $outfile variable created within the [PSCustomObject] is empty. I’ve done this before but for some reason I don’t see my error.

Here is my code:

$outfile = $protectionGroups | # Build array of references to VMs for each protection group
    ForEach-Object {
        $protectionGroup = $_
        $protectionGroupInfo = $protectionGroup.GetInfo()
        $vms = $protectionGroup.ListAssociatedVms() 
        ForEach($vm in $vms) {
            $vm.UpdateViewData() # Update (populate) each VM view from the vSphere connection
            $vminfo = Get-VM $vm.Name | Select *

            Write-Host `
                $vminfo.Name `
                $vminfo.PowerState `
                $vminfo.NumCpu `
                $vminfo.ExtensionData.Config.RepConfig.Rpo `
                $vminfo.ExtensionData.Config.RepConfig.Destination `
                ([math]::Round($vminfo.MemoryGB, 0)) `
                ([math]::Round($vminfo.UsedSpaceGB, 2)) `
                ([math]::Round($vminfo.ProvisionedSpaceGB, 2)) `
                $vminfo.Guest `
                $vminfo.Notes
            
             [PSCustomObject] @{
                Name          = $vminfo.Name
                PowerState    = $vminfo.PowerState
                NumCPU        = $vminfo.NumCpu
                RPO           = $vminfo.ExtensionData.Config.RepConfig.Rpo
                Destination   = $vminfo.ExtensionData.Config.RepConfig.Destination
                MemoryGB      = [math]::Round($vminfo.MemoryGB, 0)
                UsedSpace     = [math]::Round($vminfo.UsedSpaceGB, 2)
                ProvisionedGB = [math]::Round($vminfo.ProvisionedSpaceGB, 2)
                Guest         = $vminfo.Guest
                Notes         = $vminfo.Notes
            }
        }
}

Thank you.

How do you know? How did you output it? :wink:

I’d start with removing the | select * and the complete Write-Host command.

Your $outfile variable should actually contain both … the output of the Write-Host AND the objects created with the [PSCustomObject].

I thought Write-Host statements weren’t captured by variables?

PS> $t = Write-Host "just testing"
PS> $t
PS>

using the above test returns nothing. Based on @palmero code if the write-host statements are working then I would think $vminfo is getting value from within the ForEach loop. It would seem like the PSCustomObjects should be outputting, and the $Outfile variable looks like where they’d go

1 Like

Ooops … my mistake … of course you’re right. :+1:

I usually don’t use Write-Host at all. Instead I just output variables by calling them and then the output ends up in the default output stream. That’s why I got it mixed up.
Sorry. :pray:

oh no it’s all good. I just thought I was missing something. I’m usually pretty conscious Write-Host’s behavior so sometimes I use it in loops to give me a visual indicator of what it’s working on, knowing that i’m not corrupting my object output since it’s a different stream.

If it’s more than just a few lines of code I do actually use Write-Verbose or Write-Debug. This way I can turn the verbose or debug output on and off and I don’t have to clean up my code later on from the Write-Hosts. :wink:

1 Like

I simplified it for the sake of clarity:

ForEach ($pg in $protGroups) {
    $pgInfo = $pg.GetInfo()
    $vms = $pg.ListAssociatedVms()
    
    $report = $vms |
        ForEach-Object {
            $_.UpdateViewData()
            $vminfo = Get-VM $_.Name
            [PSCustomObject] @{
                Name = $vminfo.Name
                PowerState = $vminfo.PowerState
        }
    }
}
$report | Export-Csv -Path $mycsv

However, the csv file ends up with only the VMs for the last protection group. It appears the PSCustomObject is being recreated for each group being processed in the outermost loop.

I added the += to the innermost loop and seems to work.

Would like to know if there is a cleaner way rather than keep adding.

Thanks

this is because your $report variable is defined with each iteration of the parent ForEach loop. When it’s done only the last $pg will have pscustomobjects in the $report variable.

$report = ForEach ($pg in $protGroups) {
    $pgInfo = $pg.GetInfo()
    $vms = $pg.ListAssociatedVms()
    
    $vms |
        ForEach-Object {
            $_.UpdateViewData()
            $vminfo = Get-VM $_.Name
            [PSCustomObject] @{
                Name = $vminfo.Name
                PowerState = $vminfo.PowerState
        }
    }
}
$report | Export-Csv -Path $mycsv

I moved the report variable to capture output from your parent loop, but that’s basically what you had when you started this and you said you weren’t getting any output.

2 Likes

Your solution more elegant, I’m kicking myself for not seeing it.

Thanks!