PowerShell – Create collections of custom objects


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:

$collectionVariable = New-Object System.Collections.ArrayList

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:

$item = New-Object System.Object

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:

$item | Add-Member -MemberType NoteProperty -Name "Field1" -Value "value"

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:

$collectionVariable.Add($object) | Out-Null

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.

$collectionWithItems = New-Object System.Collections.ArrayList
for($i = 0; $i -lt 10; $i++)
    $temp = New-Object System.Object
    $temp | Add-Member -MemberType NoteProperty -Name "Field1" -Value "Value1"
    $temp | Add-Member -MemberType NoteProperty -Name "Field2" -Value "Value2"
    $temp | Add-Member -MemberType NoteProperty -Name "Field3" -Value "Value3"
    $collectionWithItems.Add($temp) | Out-Null

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:

Field1                      Field2                      Field3
------                      ------                      ------
Value1                      Value2                      Value3
Value1                      Value2                      Value3
Value1                      Value2                      Value3
Value1                      Value2                      Value3
Value1                      Value2                      Value3
Value1                      Value2                      Value3
Value1                      Value2                      Value3
Value1                      Value2                      Value3
Value1                      Value2                      Value3
Value1                      Value2                      Value3

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.

$collectionWithItems = New-Object System.Collections.ArrayList
for($i = 0; $i -lt 10; $i++)
    $temp = "" | select "Field1", "Field2", "Field3"
    $temp.Field1 = "Value1"
    $temp.Field2 = "Value2"
    $temp.Field3 = "Value3"
    $collectionWithItems.Add($temp) | Out-Null


CSS element selection

Most of the time when applying stylesheets it is not the toughest to create the right style, it often is more difficult to apply the style to the right area, and the right area only!
That’s why in this post I want to elaborate on the css selection syntax (this is the same used with jQuery also).
With examples of html and css I want to illustrate different ways to select the right element inside css (or jQuery).
First of lets start with the basics:
To select all of the same element you can simply use the name of the element. With this example all paragraphs (p) get a black color.

p { color: black; }

Links (a) are special is the way that they can have different states.

a:link { color: blue; }
a:hover { color: red; }
a:active { color: orange; }
a:visited { color: purple; }

How about selecting only links within paragraphs and giving them a different font-weight?

p a { font-weight: bold; }

“p a” means: all “a” elements who are inside a “p” element

<a>not bold</a>
<p><a>bold</a> not bold</p>

With this html and the previous css the first a would have a normal font-weight, the second however would be bold.
When a certain style applies to multiple elements you can use a comma to seperate several elements

p, a { background-color: yellow; }

In this example all “p” elements and “a” elements will have a yellow background.
It is also possible to combine different of the above methods:

p, a:active, p a {color: red; }

This means that all “p” elements, all “a” elements with status “active” and all “a” elements inside “p” elements have a red color.
This already provides a lot of possibilities to style a page. However this will mostly not be enough, you are bound to have different types of paragraphs or links. For this there are classes and ID’s to give to elements.
General rule is that an ID must be unique, which means that on every page not double ID’s are present. If multiple elements need the same style it is better to use classes.
In HTML and ID looks like this:

<p id="special">special text</p>

In css this element can be reached in one of the following ways:

#special {font-size: 110%; }
p#special {font-size: 110%; }

The first line means that all elements with ID “special” get a font-size of 110%. The second line means all paragraphs with ID “special” get a font-size of 110%.
In HTML a class looks like this:

<p class="underline">underlined text</p>

In css this element can be reached in on of the following ways:

.underline {text-decoration: underline;}
p.underline {text-decoration: underline; }

The first line means that all elements with class “underline” get an underline. the second line means that only paragraphs with class “underline” get an underline.
In my next post about CSS I will elaborate in what happens it one element is selected in multiple ways and which CSS style will be dominant.