HOWTO: Fastest Possible Way to Make Custom Objects in PowerShell

I make use of custom objects constantly in PowerShell.  Having the ability to easily combine and present data is incredibly powerful.  Since I use them so much, I’ve found myself wanting to make them as fast and easy as possible to create. After much research and experimentation, I think I have created one of the single fastest and easiest ways of making custom objects in PowerShell – and I wanted to share with you.  Ready?


$C=@("Column1 Column2 ColumnXX Column99")
$myObj=@();Function Add-ToObject{$C=($C -split ' ');$i=0;ForEach($R in $C){$P+=@{$R=$Args[$i]};$i++;};$Script:myObj+=[pscustomobject]$P}

Update: I managed to shrink this function down even further by collapsing some functions into others and making some other tweaks.  If you think you can get this shorter, (even by a single character!), please share how in the comments:

$C="User ComputerName Email OS"
Function Add-ToObject{$args|%{$i++;$P+=@{$C.split(" ")[$i-1]=$_}};$Script:myObj+=@([pscustomobject]$P)}

To make the script a little easier to understand, here it is again, but this time in its full expanded form:

I’ve effectively gotten the process down to 2 lines for any number of custom properties! But it’s even better than that.  You can ignore the second line entirely.  Instead just concentrate on the first line where you define the columns you want in your custom object.  If you want to add another column, just add it to the end separated by a space.  If you want to remove a column, delete the name.  That’s it!  Let’s look at a real world example.

Imagine a scenario where you need to identify all of the users running Windows XP in your environment and send them an email saying you need to upgrade.  To do this, you need to produce a list of all of the computers in your network, the operating system they run as well as the user that manages/owns it along with their email address.  This information must come from two different cmdlets (Get-ADComputer and Get-ADUser).  How can we combine these results into a single object for easy output?

Step 1) Copy and paste the two lines above at the top of your script and modify the column names and quantity to match your needs

Step 2) Write the code that generates the data that you need

Step 3) Once you have the data gathered, call the function Add-ToObject and pass in all the data you data you want.  Since these are objects, this can be any kind of data

Step 4) Output the results from the variable $myObj.  (You can change this if you want but I often find for quick work I’m doing, I just need a single object so sticking with a standard name is useful for smaller projects)


But it gets better.  Let’s say after building this you realize you need to add more data, aka another column.  Let’s say you wanted include the time of the scan.  How could you do that?Simply add the new “DateScanned” column in the first line and then add the data to your script.  Note in this case, we are wrapping the command in round brackets.  This tells PowerShell to run the commands between the brackets first.  This means you can run any set of commands (or other cmdlets!) and return the data directly into your object!


If you’re curious how this magic works, here is the code broken apart and explained:

# $C = ColumnNames = Each of the columns (1 to many) that you want in your object, separated each by a space
$C=@("User ComputerName Email OS")

# Create a new custom array that will store our our custom object details

# Create a new function that we'll later call to add data to our object
Function Add-ToObject {

# We need to separate out the column names we provided into 1 per line so we can associate them with the custom data
$C=($C -split " ")

# We are going to take advantage of a reserved variable in Powershell called "$args"
# Each element in $args includes whatever data is passed in in order from left to right
# So the first element is $args[0], the second is $args[1] and so on
# We need to use this $i variable to increment through all of the arguments passed in
# This is the magic sauce that allows us to define any number of properties

# For each row in the specified columns (ie the User, ComputerName, Email and OS in this case), complete the following steps
ForEach($R in $C)
    # $P = $Params and represents the params we are going to pass in
    # We are then creating and appending to $P a custom hash table that contains the Rowname (ie "Computername") with a value that was passed in
    # The secret here is that thanks to the ForEach, $R will automatically loop through all columns specified
    # The $i in Args ensures that we are grabbing the matching data for each of these columns

    # Now that we've grabbed the first argument passed in, loop to the next one so we can grab that

# As we are in a function, the variable will only be scoped (aka available) inside the function
# That doesn't help us so we need to scope it (aka define it) as available to the entire script so we can access it later
# We reference our array we created earlier and append to it a new custom object (as defined through the [pscustomobject] type accelerator
# We pass into this the $Params that we defined which is a hash table that contains all of the key value pairs that we want to add to the object
$Script:myObj+=[pscustomobject]$P }

ForEach($Computer in $Computers)
        # Now that the hard work is done, simply add the data that you want to your object with each property separated by a space
        Add-ToObject $ $ $Temp.mail $Computer.OperatingSystem

# When you want to view your results, you can output the object to the screen or can even perform additional work with it
$myObj | ft -AutoSize

1 pings

  1. […] Thanks again to Robbie Vance for helping me with Custom Objects ( […]

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.