# Create dynamic property names for a collection

**URL:** <https://forums.powershell.org/t/create-dynamic-property-names-for-a-collection/22695>\
**Category:** PowerShell Help\
**Created:** [August 2, 2023, 7:35am UTC](https://forums.powershell.org/t/create-dynamic-property-names-for-a-collection/22695 "2023-08-02T07:35:18Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![JDMils](https://avatars.discourse-cdn.com/v4/letter/j/c89c15/32.png) [@JDMils](https://forums.powershell.org/u/JDMils)\
**Post date:** [August 2, 2023, 7:35am UTC](https://forums.powershell.org/t/create-dynamic-property-names-for-a-collection/22695/1 "2023-08-02T07:35:18Z")

</div>

I am extracting CPU properties from my Cisco IMC UCS rack servers, and some rack servers have one, two or four CPUs. My goal is to collect the CPU information and add them to my collection which is exported to CSV. My problem is that the collection should look like this, but it is not resulting this way:

> Item 1: CPUID\_1, CPUID\_2  
> Item 2: CPUID\_1, CPUID\_2, CPUID\_3, CPUID\_4  
> Item 3: CPUID\_1, CPUID\_2  
> Item 4: CPUID\_1

So I am trying to write my code so that the properties of the collection change to match the number of CPUs, however I cannot get this to work. My results are:

> Item 1: CPUID\_$CPUCounter, CPUID\_$CPUCounter  
> Item 2: CPUID\_$CPUCounter, CPUID\_$CPUCounter, CPUID\_$CPUCounter, CPUID\_$CPUCounter  
> Item 3: CPUID\_$CPUCounter, CPUID\_$CPUCounter  
> Item 4: CPUID\_$CPUCounter

Can you advise how I can create dynamic property headers?

My Code:

```auto
$CPUCounter = 1
        ForEach ($IMCServerProcessor in $IMCServerProcessors)
            {
            $Item | Add-Member -type NoteProperty -Name 'CPUID_$CPUCounter' -Value @($IMCServerProcessor.Id)
            $Item | Add-Member -type NoteProperty -Name 'CPUModel_$CPUCounter' -Value @($IMCServerProcessor.Model)
            $Item | Add-Member -type NoteProperty -Name 'OperState_$CPUCounter' -Value @($IMCServerProcessor.OperState)
            $Item | Add-Member -type NoteProperty -Name 'Presence_$CPUCounter' -Value @($IMCServerProcessor.Presence)
            $Item | Add-Member -type NoteProperty -Name 'SocketDesignation_$CPUCounter' -Value @($IMCServerProcessor.SocketDesignation)
            $Item | Add-Member -type NoteProperty -Name 'CPUVendor_$CPUCounter' -Value @($IMCServerProcessor.Vendor)
            $Item | Add-Member -type NoteProperty -Name 'CPUIMC_$CPUCounter' -Value @($IMCServerProcessor.Imc)
            $Item | Add-Member -type NoteProperty -Name 'Dn_$CPUCounter' -Value @($IMCServerProcessor.Dn)
            $Item | Add-Member -type NoteProperty -Name 'Rn_$CPUCounter' -Value @($IMCServerProcessor.Rn)
            $CPUCounter += 1
            }

```

---

<div class="post-metadata">

**Author:** ![JDMils](https://avatars.discourse-cdn.com/v4/letter/j/c89c15/32.png) [@JDMils](https://forums.powershell.org/u/JDMils)\
**Post date:** [August 7, 2023, 5:27am UTC](https://forums.powershell.org/t/create-dynamic-property-names-for-a-collection/22695/2 "2023-08-07T05:27:20Z")

</div>

I figgered out a way to do this. The minimum properties for a server in my case is 19 which includes one CPU’s worth of properties.  
Before collecting all server properties, this is assigned to a variable which records the maximum properties collected for any one server. This is stored in variable $MaxPropertiesCount.  
The code then enumerates all the server properties including the CPU properties and places them in a collection called “$IMCRackServerInventory”. It counts the number of properties for the current server and stores this count in the variable $ItemPropertyCount.  
While it is enumerating all the properties, it compares the number of server properties enumerated ($ItemPropertyCount) against the most properties enumerated so far ($MaxPropertiesCount). If the current server has more properties than the last ones, the $MaxPropertiesCount is updated to match this value.  
Once all servers’ properties have been enumerated, the variable $IMCRackServerInventory now contains varying number of properties per record. The records with less properties than $MaxPropertiesCount need to have the appropriate number of “dummy” variables added. This is the cool part.  
The ForEach cycles thru all records of the collection $IMCRackServerInventory, assigning each record to the variable $ServerData. If the current $ServerData has less properties then the maximum counted, a loop is initiated where the dummy properties are added to $ServerData.  
This is the interesting part. $ServerData seems to be dynamically linked to each record in $IMCRackServerInventory- what I mean here is that any changes to $ServerData will change the respective value in $IMCRackServerInventory via the ForEach.  
Here’s the code:

```auto

#
# ================================FUNCTION DECLARATION START====================================================================
#
 
#
# Check the required columns for this script to run, are present in the user-selected CSV import file.
Function CheckCSVColumnsExist
    {
    Param(
        [Object]$CSVImportFile,
        [Array]$ColumnsToCheck = ''    
        )
 
    $ColumnHeaders = (Import-Csv $CSVImportFile | Get-Member -MemberType NoteProperty).Name
    $MissingColumnHeaders = @()
    ForEach( $ColumnToCheck in $ColumnsToCheck)
        {
        $MissingColumnName = New-Object PSObject
        If ($ColumnHeaders -match $ColumnToCheck )
            {
            # Nothing to do.
            }
        Else
            {
            $MissingColumnName | Add-Member -type NoteProperty -Name 'Column_Name' -Value $ColumnToCheck
            $MissingColumnHeaders += $MissingColumnName
            }
         
        }
    Return $MissingColumnHeaders
    }
   
# This function shows the Open File dialog to the user so the user can
# select the import CSV file.
#
Function Get-FileName($InitialDirectory)
    {
    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
  
    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = $initialDirectory
    $OpenFileDialog.filter = "CSV (*.csv) | *.csv"
    $OpenFileDialog.ShowDialog() | Out-Null
    $OpenFileDialog.FileName
    }
 
#
# ================================FUNCTION DECLARATION FINISH===================================================================
#
 
#
# ================================SCRIPT START==================================================================================
#
#
Import-Module Cisco.IMC

# The input CSV file contains the details required for the script
# to log into each Cisco UCS server.
#
# Get the CSV import file name and path:
$ImportCSVFile = Get-FileName

Write-Host "Script starting." -ForegroundColor Green
 
# Check if the user cancelled the request.
if ($ImportCSVFile -eq "")
    { # They did!
    Throw "No file selected. Ending script"
    }

# Load the CSV file contents.
$UCSRackServerReport = Import-CSV $ImportCSVFile -ErrorAction SilentlyContinue
# Ask the user for the CIMC credential details.
$IMCServerCredential = Get-Credential admin

$IMCRackServerInventory = @()
# Read each entry in the import CSV file, then try to logon to the 
# CIMC of each one and collect hardware details.
$MaxPropertiesCount = 19
ForEach ($vRow in $UCSRackServerReport)
    {
    $Item = New-Object PSObject
    # Get the server CIMC IP.
    $RackServerIMCIP = $vRow."IP Address"
    # Get the server User Label and Host Name.
    $RackServerIMCUserLabel = $vRow."User Label"
    $RackServerIMCHostName = $vRow."Host Name"

    # If the User Label is blank, use the Host Name for console output updates.
    If ([string]::IsNullOrWhiteSpace($RackServerIMCUserLabel) )
        {
        $StringLabel = "[$RackServerIMCHostName/$RackServerIMCIP]"
        }
    Else
        {
        $StringLabel = "[$RackServerIMCUserLabel/$RackServerIMCIP]"
        }
    Try
        {
        # Let's connect to the CIMC.
        $Connected = $True
        Write-Host "$StringLabel Attempting a connection to server IMC." -ForegroundColor Yellow
        $IMCHandle = Connect-IMC -Name $RackServerIMCIP -Credential $IMCServerCredential -NotDefault -ErrorAction Stop
        }

    Catch [System.NullReferenceException]
        {
        Write-Host "$StringLabel Error: $($PSItem.ToString())" -ForegroundColor Red
        $Connected = $False
        $ErrorPropertyValue = "Null Reference Error"
        }

    Catch [System.Exception]
        {
        # Did not connect due to connection issue.
        Write-Host "$StringLabel Error: $($PSItem.ToString())" -ForegroundColor Red
        If ($PSItem.Exception.ToString().Contains("Unable to connect"))
            {
            # Set connection flag false.
            $Connected = $False
            $ErrorPropertyValue = "Not Connected"
            }
        Else
            {
            $Connected = $False
            $ErrorPropertyValue = "System Exception"
            Write-Host "Not a connection issue." -ForegroundColor Red
            }
        }
    Catch
        {
        Write-Host "$StringLabel Error: $($PSItem.ToString())" -ForegroundColor Red
        $Connected = $False
        $ErrorPropertyValue = "Unknown Error"
        }

    
    # Did we connect to the CIMC?
    If (!$Connected)
        {

        # No we did not. Record this event.
        If ([string]::IsNullOrWhiteSpace($RackServerIMCUserLabel) )
            {
            $NewUserLabel = $RackServerIMCHostName
            }
        Else
            {
            $NewUserLabel = $RackServerIMCUserLabel 
            }
        # Set collection details and the properties not read in will be set to $ErrorPropertyValue.
        $Item | Add-Member -type NoteProperty -Name 'UserLabel' -Value $NewUserLabel
        $Item | Add-Member -type NoteProperty -Name 'Model' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'Serial' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'ServerID' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'CIMC_IP' -Value $RackServerIMCIP
        $Item | Add-Member -type NoteProperty -Name 'Vendor' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'IMCName' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'DN' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'Rn' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'BMCFirmwarePackage' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'CPUID_1' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'CPUModel_1' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'OperState_1' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'Presence_1' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'SocketDesignation_1' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'CPUVendor_1' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'CPUIMC_1' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'Dn_1' -Value $ErrorPropertyValue
        $Item | Add-Member -type NoteProperty -Name 'Rn_1' -Value $ErrorPropertyValue
        }
    Else
        {
        # We connected OK.
        Write-Host "$StringLabel Connection to server IMC established." -ForegroundColor Cyan
        Write-Host "$StringLabel Gathering Rack Unit data." -ForegroundColor Cyan
        # Get rack server hardware details.
        $IMCServerUnit = Get-IMCRackUnit -Imc $IMCHandle
        # Check if User Label is blank and if so, use the IMC field as the server label.
        # Get the firmware package details.
        $IMCFirmwarePackage = Get-ImcFirmwareRunning -Imc $IMCHandle | Where {$_.Deployment -eq "system" -and $_.Type -eq "blade-controller"}
        # Add the firmware package details to the collection.
        
        If ([string]::IsNullOrWhiteSpace($IMCServerUnit.UsrLbl) )
            {
            $NewUserLabel = $IMCServerUnit.Imc
            }
        Else
            {
            $NewUserLabel = $IMCServerUnit.UsrLbl
            }
        # Record rack server hardware details.
        $Item | Add-Member -type NoteProperty -Name 'UserLabel' -Value $NewUserLabel
        $Item | Add-Member -type NoteProperty -Name 'Model' -Value $($IMCServerUnit.Model)
        $Item | Add-Member -type NoteProperty -Name 'Serial' -Value $($IMCServerUnit.Serial)
        $Item | Add-Member -type NoteProperty -Name 'ServerID' -Value $($IMCServerUnit.ServerId)
        $Item | Add-Member -type NoteProperty -Name 'CIMC_IP' -Value $RackServerIMCIP
        $Item | Add-Member -type NoteProperty -Name 'Vendor' -Value $($IMCServerUnit.Vendor)
        $Item | Add-Member -type NoteProperty -Name 'IMCName' -Value $($IMCServerUnit.Imc)
        $Item | Add-Member -type NoteProperty -Name 'DN' -Value $($IMCServerUnit.Dn)
        $Item | Add-Member -type NoteProperty -Name 'Rn' -Value $($IMCServerUnit.Rn)
        $Item | Add-Member -type NoteProperty -Name 'BMCFirmwarePackage' -Value $($IMCFirmwarePackage.Version)
        Write-Host "$StringLabel Gathering Processor data." -ForegroundColor Cyan
        $CPUCounter = 1
        # Get the rack server processor details.
        $IMCServerProcessors = Get-IMCProcessorUnit -Imc $IMCHandle
        # For multiple processors, cycle thru each object found.
        ForEach ($IMCServerProcessor in $IMCServerProcessors)
            {
            # Dynamically create the property name with "_#" at the end for each processor. Record processor details.
            $FieldName = "CPUID_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Id)
            $FieldName = "CPUModel_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Model)
            $FieldName = "OperState_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.OperState)
            $FieldName = "Presence_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Presence)
            $FieldName = "SocketDesignation_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.SocketDesignation)
            $FieldName = "CPUVendor_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Vendor)
            $FieldName = "CPUIMC_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Imc)
            $FieldName = "Dn_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Dn)
            $FieldName = "Rn_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Rn)
            $CPUCounter += 1
            }
        Write-Host "$StringLabel Gathering Firmware data." -ForegroundColor Cyan

        }

    $ItemPropertyCount = ($Item | Get-Member -MemberType NoteProperty ).Count
    Write-Host "$StringLabel ItemPropertyCount = [$ItemPropertyCount]."
    Write-Host "$StringLabel MaxPropertiesCount = [$MaxPropertiesCount]."
    If ($ItemPropertyCount -gt $MaxPropertiesCount)
        {
        $MaxPropertiesCount = $ItemPropertyCount
        }
    Else
        {
        #
        }
    $IMCRackServerInventory += $Item
    Write-Host "$StringLabel Data collection completed." -ForegroundColor Blue
    # Close the connection to the server's CIMC.
    If ($IMCHandle -ne $Null )
        {
        $CloseIMCHandle = Disconnect-IMC -Imc $IMCHandle
        }
    Write-Host "$StringLabel Closing session to server IMC." -ForegroundColor Blue
    Write-Host ""
    }

ForEach ($ServerData in $IMCRackServerInventory)
    {
    # Compare the number of properties in ServerData to the minimum number.
    $ServerDataPropertyCount = ($ServerData | Get-Member -MemberType NoteProperty ).count
    If ($ServerDataPropertyCount -lt $MaxPropertiesCount)
        {
        $MaxCPUs = ($MaxPropertiesCount - 10) /9
        $TotalCPUs = ($ServerDataPropertyCount - 10) /9
        # ServerData contains less properties - thus less CPU properties.
        $NextCPUField = $TotalCPUs + 1
        # Create dummy CPU properties to fill the collection properties for this record.
        For ($Index = $NextCPUField; $Index -le $MaxCPUs; $Index++)
            {
            
            $FieldName = "CPUID_$Index"; $ServerData | Add-Member -type NoteProperty -Name $FieldName -Value "NA"
            $FieldName = "CPUModel_$Index"; $ServerData | Add-Member -type NoteProperty -Name $FieldName -Value "NA"
            $FieldName = "OperState_$Index"; $ServerData | Add-Member -type NoteProperty -Name $FieldName -Value "NA"
            $FieldName = "Presence_$Index"; $ServerData | Add-Member -type NoteProperty -Name $FieldName -Value "NA"
            $FieldName = "SocketDesignation_$Index"; $ServerData | Add-Member -type NoteProperty -Name $FieldName -Value "NA"
            $FieldName = "CPUVendor_$Index"; $ServerData | Add-Member -type NoteProperty -Name $FieldName -Value "NA"
            $FieldName = "CPUIMC_$Index"; $ServerData | Add-Member -type NoteProperty -Name $FieldName -Value "NA"
            $FieldName = "Dn_$Index"; $ServerData | Add-Member -type NoteProperty -Name $FieldName -Value "NA"
            $FieldName = "Rn_$Index"; $ServerData | Add-Member -type NoteProperty -Name $FieldName -Value "NA"
            }
        }
        

    }

# Write the collected data to CSV file.
$IMCRackServerInventory | Export-CSV -Path "UCS_IMC_RackServer_Inventory.csv" -NoTypeInformation -UseCulture
Write-Host "Script Finished." -ForegroundColor Green

```

---

<div class="post-metadata">

**Author:** ![Olaf](https://sea1.discourse-cdn.com/flex019/user_avatar/forums.powershell.org/olaf/32/992_2.png) [@Olaf](https://forums.powershell.org/u/Olaf)\
**Post date:** [August 7, 2023, 6:56am UTC](https://forums.powershell.org/t/create-dynamic-property-names-for-a-collection/22695/3 "2023-08-07T06:56:17Z")

</div>

Sorry for the late answer.

It seems like you’re trying to press hierarchical data into a structured data format. Depending on the purpose of these data there might be a better way. What’s the actual purpose of the data collection?

Regardless of that … using `Add-Member` is a kind of outdated, quite cumbersome to write and hard to read. Nowadays - since PowerShell version 3.0 - we use `[PSCustomObject]` for those purposes.

> **[Everything you wanted to know about PSCustomObject - PowerShell](https://learn.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-pscustomobject?view=powershell-7.3)**
>
> PSCustomObject is a simple way to create structured data.

Regardless of that … using `Write-Host` for logging purposes is a bad idea.

> **[Write-Host Considered Harmful](https://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/)**
>
> When you are writing or reviewing PowerShell scripts, I’d like you to remember the following rule of thumb: Using Write-Host is almost always wrong.

Regardless of that …

> [@JDMils](#):
>
> CPU properties from my Cisco IMC UCS rack servers, and some rack servers have one, two or four CPUs. My goal is to collect the CPU information and add them to my collection which is exported to CSV. My problem is that the collection should look like this, but it is not resulting this way:

Do these CPUs from one Cisco IMC UCS rack server differ from each other? I’d expect these CPUs to be the same. In this case it should be enough to get the information about the CPUs once and add a counter how many of these CPUs are in this particular server, or am I wrong?

---

<div class="post-metadata">

**Author:** ![JDMils](https://avatars.discourse-cdn.com/v4/letter/j/c89c15/32.png) [@JDMils](https://forums.powershell.org/u/JDMils)\
**Post date:** [August 9, 2023, 2:55am UTC](https://forums.powershell.org/t/create-dynamic-property-names-for-a-collection/22695/4 "2023-08-09T02:55:58Z")

</div>

Thanks for your reply. I have read thru the documents you linked and they are helpful. The CPUs of each rack server differs depending on when the server was built as we keep adding more servers over time and the processors generally evolve as well. The code has to enumerate the CPUs of each server it logs into in order to get the CPU info, so the data has been obtained once per server. Remember that the results are exported to CSV so if I used a counter for each CPU type, I’d have to re-convert the counters back to actual CPU details in order for those details to appear in the CSV.

It looks to me like using the code:

```auto
ForEach ($IMCServerProcessor in $IMCServerProcessors)

```

Seems to create a linked record in $IMCServerProcessor to the parent $IMCServerProcessors so I was able to “pad-out” the “missing” properties and it seems to work really well.

Thanks again.

---

<div class="post-metadata">

**Author:** ![Olaf](https://sea1.discourse-cdn.com/flex019/user_avatar/forums.powershell.org/olaf/32/992_2.png) [@Olaf](https://forums.powershell.org/u/Olaf)\
**Post date:** [August 9, 2023, 7:13am UTC](https://forums.powershell.org/t/create-dynamic-property-names-for-a-collection/22695/5 "2023-08-09T07:13:36Z")

</div>

> [@JDMils](#):
>
> The CPUs of each rack server differs depending on when the server was built as we keep adding more servers over time and the processors generally evolve as well.

Hmmm … I think I didn’t make myself clear. What I meant and understood …

You wrote initially …

> [@JDMils](#):
>
> some rack servers have one, two or four CPUs.

And you listed them like this:

> [@JDMils](#):
>
> Item 1: CPUID\_1, CPUID\_2  
> Item 2: CPUID\_1, CPUID\_2, CPUID\_3, CPUID\_4  
> Item 3: CPUID\_1, CPUID\_2  
> Item 4: CPUID\_1

I assumed `Item 1` is one server. And if one single server uses only one particular type of CPU it should be enough when you put it like this somehow:

```auto
ServerName CPU-ID CPU-Count
---------- ------ ---------
Serer01 CPUID_1 4
Serer02 CPUID_2 2
Serer03 CPUID_12 6
Serer04 CPUID_6 24

```

Anyway …

> [@JDMils](#):
>
> so I was able to “pad-out” the “missing” properties and it seems to work really well.

I’m glad to hear that you’ve found a solution yourself and that it works for you. 👍🏼

---

<div class="post-metadata">

**Author:** ![JDMils](https://avatars.discourse-cdn.com/v4/letter/j/c89c15/32.png) [@JDMils](https://forums.powershell.org/u/JDMils)\
**Post date:** [August 10, 2023, 12:05am UTC](https://forums.powershell.org/t/create-dynamic-property-names-for-a-collection/22695/6 "2023-08-10T00:05:22Z")

</div>

To clarify, if a server has one physical CPU, the record in the collection for that server will go to CPU\_1 which will have say 9 properties such as:  
Server1: CPUID\_1: 1  
Server1: CPUModel\_1: Xeon Gold 6145  
Server1: OperState\_1: Operational  
Server1: Presence\_1: Available  
Server1: SocketDesignation\_1: 1  
Server1: CPUVendor\_1: Cisco  
Server1: CPUIMC: True  
Server1: Dn\_1: cpu-1  
Server1: Rn\_1: sys\rack\_server\_1\cpu-1

So a server with 2 CPUs will have 18 CPU properties. And these properties will become just columns in a CSV file. The aim is to extract the server physical details, firmware version and CPU types from each rack server so that I can determine the firmware upgrade path- the firmware to use is determined by the CPU Model.

And yeah, quite by surprise I was able to “pad” the records so that all records in the collection had the same number of properties/columns so that the Export-CSV would export ALL the properties of ALL the records. Like I said before, if ONE record has only 9 properties and all the others have say 28, then only 9 properties are exported to CSV by the Export-CSV command.

---

<div class="post-metadata">

**Author:** ![Olaf](https://sea1.discourse-cdn.com/flex019/user_avatar/forums.powershell.org/olaf/32/992_2.png) [@Olaf](https://forums.powershell.org/u/Olaf)\
**Post date:** [August 10, 2023, 12:22am UTC](https://forums.powershell.org/t/create-dynamic-property-names-for-a-collection/22695/7 "2023-08-10T00:22:31Z")

</div>

> [@JDMils](#):
>
> To clarify, if a server has one physical CPU, the record in the collection for that server will go to CPU\_1 which will have say 9 properties

> [@JDMils](#):
>
> So a server with 2 CPUs will have 18 CPU properties.

OK, but aren’t the properties of these two CPUs exactly the same? That’s what I meant.

---

<div class="post-metadata">

**Author:** ![krzydoug](https://sea1.discourse-cdn.com/flex019/user_avatar/forums.powershell.org/krzydoug/32/1008_2.png) [@krzydoug](https://forums.powershell.org/u/krzydoug)\
**Post date:** [August 10, 2023, 10:03pm UTC](https://forums.powershell.org/t/create-dynamic-property-names-for-a-collection/22695/8 "2023-08-10T22:03:39Z")

</div>

I agree with Olaf, your example here there would still be only 9 properties. You’d only get different properties if you have DIFFERENT cpus which is what I believe you are trying to say. If I understood correctly, then you probably want to say something more like this.

Server1 has 1 or more CPU that has a specific set of properties.  
Server2 has 1 or more CPUs with specific set of properties that may include property names that are the same as server1 but may also have different properties.  
You want to normalize the properties across all the CPUs

Here is how I handle situations like this.

```auto
# silly sample list to illustrate the point

$cpulist = [PSCustomObject]@{
    Brand = 'Intel'
    Speed = 'Fast'
    Cache = 'Yes please'
},
[PSCustomObject]@{
    Brand = 'Intel'
    Speed = 'Fast'
    Cache = 'Only on Tuesdays'
    Firmware = '0.1.0'
},
[PSCustomObject]@{
    Brand = 'Intel'
    Speed = 'Fast'
    Firmware = '0.1.0'
    Pins = 420
},
[PSCustomObject]@{
    Brand = 'AMD'
    Cache = '3MB'
    L2Cache = '6MB'
    Mood = 'cranky'
}

```

Now when you output these, you’ll see the “columns” are dictated by the first item.

```auto
$cpulist

Brand Speed Cache           
----- ----- -----           
Intel Fast Yes please      
Intel Fast Only on Tuesdays
Intel Fast                  
AMD 3MB

```

If a different CPU was first you’d have different columns

```auto
$cpulist | Select-Object -Skip 1

rand Speed Cache Firmware
----- ----- ----- --------
Intel Fast Only on Tuesdays 0.1.0   
Intel Fast 0.1.0   
AMD 3MB                      

```

To see each of these list their properties, you could force it with something like this

```auto
$cpulist | Foreach-Object {$_ | Out-Host}
Brand Speed Cache     
----- ----- -----     
Intel Fast Yes please

Brand Speed Cache Firmware
----- ----- ----- --------
Intel Fast Only on Tuesdays 0.1.0   

Brand Speed Firmware Pins
----- ----- -------- ----
Intel Fast 0.1.0 420

Brand Cache L2Cache Mood  
----- ----- ------- ----  
AMD 3MB 6MB cranky

```

But of course, that doesn’t look good and it definitely won’t export properly. We need to build a dynamic list of properties

```auto
$propertylist = New-Object System.Collections.Generic.list[string]

foreach($cpu in $cpulist){
    foreach($property in $cpu.psobject.properties.name){
        if($property -notin $propertylist){
            $propertylist.Add($property)
        }
    }
}

```

Now we can see all the unique properties and export to csv/json/xml

```auto
$cpulist | Select-Object -Property $propertylist | Format-Table

Brand Speed Cache Firmware Pins L2Cache Mood  
----- ----- ----- -------- ---- ------- ----  
Intel Fast Yes please                                   
Intel Fast Only on Tuesdays 0.1.0                       
Intel Fast 0.1.0 420                
AMD 3MB 6MB cranky

```

Please note the use of `Format-Table` was only to make the output pretty for the console. You do not want to use that for normal processing.

```auto
# Make a new list of CPUs with all the dynamic properties
$newcpulist = $cpulist | Select-Object -Property $propertylist

# Export
$newcpulist | ConvertTo-Csv -NoTypeInformation

```

The [psobject](https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.psobject?view=powershellsdk-7.3.0) hidden member can be quite useful in situations like this.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex019/uploads/powershell/original/1X/385e4f9fe133561ad30a814262fe0e0ae6bc3ef0.png) [@system](https://forums.powershell.org/u/system)\
**Post date:** [February 10, 2024, 5:34pm UTC](https://forums.powershell.org/t/create-dynamic-property-names-for-a-collection/22695/9 "2024-02-10T17:34:03Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
