PowerShell – Create collections of custom objects

Background

Today a colleague asked my how he could store object collections in memory (a PowerShell variable) instead of writing and reading to/from CSV files. While searching for it he found tons of examples but most were written specifically for one target, he needed something more basic and flexible. He asked me if I already had a topic about it on my blog. Sadly I had to disappoint him, it wasn’t on my blog, yet. However I knew the answer and I will now also share this on my blog.

Creating the collection

Lets start of with creating an ArrayList in PowerShell:

Done. This is our generic collection, it can contain any PowerShell (.NET) object.

Before adding items to the collection be very aware that the fields of the first item added dictate which fields the collection will have.

For example take object $A and object $B.
Object $A has two string fields: “fieldA” and “fieldB”
Object $B also has two string fields: “fieldB” and “fieldC”
If object $A is added to our new empty collection, the collection would then have two fields: “fieldA” and “fieldB”.
If we would then add $B to the same collection the item in the collection would have an empty value in the field “fieldA” and no field “fieldC” (fieldB would be added normally to the list).
Keep this in mind when adding different types of objects to a collection.

Creating a custom object

Creating a custom object is easy:

This creates an empty System.Object object. This Object has no fields and only has four methods:
bool Equals(System.Object obj)
int GetHashCode()
type GetType()
string ToString()

This makes it an ideal object to start with as we can manually define every field.

So how do we add fields to our empty object?

Like this:

This example create a field named “Field1” with the value “value”, you can also pass a variable as value or even a field of a different object. For adding multiple field just repeat the line with different “Name” values.

This method can also be used to add fields to existing objects. For example you can read a csv file, add fields (for example a calculated field based on values of other fields) to the objects and then add all of those to a new (empty) collection which you can then write to a csv again or process further.

Adding the custom object to the ArrayList

We now have an ArrayList and need to put our custom object in it.

For people who are used to .NET and the way the lists work the method will be mostly unsurprising. There is only one thing to keep in mind, the Add method returns the index for the new item in the array. If you do not need this (and don’t want a series of indexes appearing on the console) you could output the result to null as in below example:

This will add the custom object to our ArrayList and will ignore the returned value.

Putting it all together

For this example I add ten objects to an ArrayList; the ten objects are the same but you can modify this to your own specific situation.

If I would then call $collectionWithItems it will return the collection. This is what the output is of $collectionWithItems when called after the for loop:

Update (2017-06-13): Quicker/dirtier way to create objects with certain fields

Another way (though less pretty) is to do a select statement on any object, this will create a PSCustomObject with only the selected properties. Instead of the above example where it took 4 lines to create an object with 3 properties, this object can be created with all three fields in 1 line. However adding the contents to the fields might still require some additional lines which makes it also end up with 4 lines to create and fill the object.

 

7 thoughts on “PowerShell – Create collections of custom objects

  1. Same for me… Was looking for hours to find a solution !

    All I wanted to do is print in a file table style :

    $collectionWithItems = @()

    For ($i=0; $i -le $dsv.Schema.Tables.Count-1; $i++)
    {
    if ($dsv.schema.Tables[$i].ExtendedProperties[“TableType”] -eq “View”)
    {
    $j++

    $strings1 = $j.ToString()
    $strings2 = $dsv.schema.Tables[$i].tablename
    $strings3 = $dsv.schema.Tables[$i].ExtendedProperties[“FriendlyName”]

    $temp = New-Object System.Object
    $temp | Add-Member -MemberType NoteProperty -Name “No” -Value $strings1
    $temp | Add-Member -MemberType NoteProperty -Name “TableName” -Value $strings2
    $temp | Add-Member -MemberType NoteProperty -Name “FriendlyName” -Value $strings3
    $collectionWithItems += $temp
    }
    }
    Write-Output $collectionWithItems | ft -AutoSize | Out-File $File -append

    Your solution did exactly what I wanted

    Thanks !

  2. This was so valuable as I now can produce object collections easily from my functions to pass all the values I want to the main body of the script and maintain the structure of the object as it passes from the function. Thanks very much for your contribution!

  3. Does this end up allocating a new array each time += is called? Seems like it could get expensive if iterating tens of thousands of objects.

    • You are absolutely right! I usually don’t use this for larger numbers, as this would indeed create a new array every time an item is added. I have changed the article to use an ArrayList instead. This will grow similar to a regular list, doubling in size once it runs out of space; which should offer better performance even when dealing with larger numbers.

Leave a Reply

Your email address will not be published. Required fields are marked *