Forum Discussion

JulianMilano's avatar
JulianMilano
Copper Contributor
Aug 03, 2023
Solved

Creating and exporting a collection with variable properties

My script logs into multiple Cisco UCS servers and extracts the CPU information, storing it in a collection which is then written to a CSV file. My problem is that I have a loop which creates a set o...
  • LainRobertson's avatar
    Aug 03, 2023

    JulianMilano 

     

    You've got a couple of options, but first, let's look at your question on why you're only getting the first two when in your debugging, you're seeing higher counts (such as the four CPU example.)

     

    Export-Csv constructs the header dynamically using the first object in the pipeline and doesn't alter it afterwards. If your first object is based on a 2-CPU processor then that's what your header will look like for all rows, and more importantly, all subsequent objects that come through the pipeline will only be checked for object properties matching the header, meaning even if entries for CPUs above 2 exist, Export-Csv will simply not look for them.

    Example script

     

     

    $Data = @(
        [PSCustomObject] @{
            Row1 = "Value1";
            Row2 = "Value2";
        },
        [PSCustomObject] @{
            Row1 = "Value1";
            Row2 = "Value2";
            Row3 = "Value3";
            Row4 = "Value4";
        }
    )
    
    $Data | Export-Csv -NoTypeInformation -Path "D:\Data\Temp\Forum\forum.csv";

     

     

    Output

    "Row1","Row2"
    "Value1","Value2"
    "Value1","Value2"

     

    Conversely, if I reverse the order of the data rows, we see the header change to reflect it:

    Output

    "Row1","Row2","Row3","Row4"
    "Value1","Value2","Value3","Value4"
    "Value1","Value2",,

     

    So, that's why you're not seeing your additional data when using Export-Csv.

     

    The easiest way to combat this is to pre-stage a specified number of CPU properties on each object, and then during the iterations, assign the values to those properties.

     

    For example, changing your existing lines 177 to 193, to something like this:

     

     

            # Get the rack server processor details.
            $IMCServerProcessors = Get-IMCProcessorUnit -Imc $IMCHandle
    
            # Pre-stage a fixed number of CPU columns (in this case, 4.)
            for ($index = 1; $index -le 4; $index++){
                Add-Member -InputObject $item -NotePropertyName "CPUID_$index" -NotePropertyValue $null;
                Add-Member -InputObject $item -NotePropertyName "CPUModel_$index" -NotePropertyValue $null;
                Add-Member -InputObject $item -NotePropertyName "OperState_$index" -NotePropertyValue $null;
                Add-Member -InputObject $item -NotePropertyName "Presence_$index" -NotePropertyValue $null;
                Add-Member -InputObject $item -NotePropertyName "SocketDesignation_$index" -NotePropertyValue $null;
                Add-Member -InputObject $item -NotePropertyName "CPUVendor_$index" -NotePropertyValue $null;
                Add-Member -InputObject $item -NotePropertyName "CPUIMC_$index" -NotePropertyValue $null;
                Add-Member -InputObject $item -NotePropertyName "Dn_$index" -NotePropertyValue $null;
                Add-Member -InputObject $item -NotePropertyName "Rn_$index" -NotePropertyValue $null;
            }
    
            # For multiple processors, cycle thru each object found.
            for ($index = 1; $index -le $IMCServerProcessors.Count; $index++)
            {
                $item."CPUID_$index" = $IMCServerProcessors[$index-1].Id;
                $item."CPUModel_$index" = $IMCServerProcessors[$index-1].Model;
                $item."OperState_$index" = $IMCServerProcessors[$index-1].OperState;
                $item."Presence_$index" = $IMCServerProcessors[$index-1].Presence;
                $item."SocketDesignation_$index" = $IMCServerProcessors[$index-1].SocketDesignation;
                $item."CPUVendor_$index" = $IMCServerProcessors[$index-1].Vendor;
                $item."CPUIMC_$index" = $IMCServerProcessors[$index-1].Imc;
                $item."Dn_$index" = $IMCServerProcessors[$index-1].Dn;
                $item."Rn_$index" = $IMCServerProcessors[$index-1].Rn;
            }

     

     

    There are other alternatives but they come with additional complexity - more than is worth the small amount of benefit of not having superfluous CPU columns is worth.

     

    At the end of the day, if you plan to use Export-Csv then your first pipeline object simply has to have present all the columns that can possibly feature in the resulting CSV, or else you are going to miss out on data.

     

    Cheers,

    Lain

Resources