Working With Custom Types of Custom Objects In PowerShell

Building custom object with PowerShell is a great way to quickly put together output for use with reporting or pipelining into another cmdlet.  It is also very simple to put together a quick object such as this:

$Object = New-Object PSObject -Property @{
    Name = 'Boe'
    Country = 'USA'
}
$Object

image

Now lets look at the Type of the object.

$Object | Get-Member

image

As you can see, the object type is System.Management.Automation.PSCustomObject which is a default type when creating a custom object using the New-Object PSObject method.

What you may know is that there is one of 5 hidden member sets that you can view:

pstypenames                                                                   
psadapted                                                                     
psbase                                                                        
psextended                                                                    
psobject

The only one that I will be talking about here is the pstypenames code property.

Looking at the pstypenames code property of $Object we can see 2 different types in the collection:

System.Management.Automation.PSCustomObject
System.Object

The types in the collection are in an inheritance order, meaning that the PSCustomObject  would be first in line for any type formatting that is specified in an PS1XML file. A better example would be to look at the pstypenames collection from a process object.

$proc = Get-Process -Name PowerShell
$proc.pstypenames

System.Diagnostics.Process
System.ComponentModel.Component
System.MarshalByRefObject
System.Object

In this example, the System.Diagnostics.Process type is at the top of the inheritance chain, thus why you see the specific output when viewing the properties of the $proc variable via Format-List and Format-Table (default view).

Back to working with the pstypename code property.

Lets look at the type of methods we can use with this code property:

$Object.pstypenames.psbase | Get-Member -Type Method

image

 

This allows us to do one of the following things:

  • Clear all typenames associate with the custom object
  • Insert a custom typename anywhere within the current collection of  typenames
  • Add a custom typename to the bottom of the stack;not really useful if you have other typenames above it

For fun, lets clear out the typenames for the process and see what happens.

$proc.pstypenames.clear()
$proc

image

Now that is a lot of information. Not exactly what you are used to seeing as a default view for processes. This is because we have removed all types associated with this object. Now this only applies to this specific object, if I were to run Get-Process again, the results would be back to the normal view we are used to seeing.

Lets use the Add() method to add a custom type to my custom object now.

$object.pstypenames.Add('System.Example.Custom')
$object.pstypenames

image

As you can see, the custom type was added at the bottom of the stack, this means that it would be the last in line for any kind of formatting. It becomes more clear when you use Get-Member:

$object | Get-Member

image

How can we overcome this? Simple, we can use the Insert() method and specify the top of the stack to place our custom type on.

$object.pstypenames.Insert(0,'System.NewCustomType.Example')
$object.pstypenames

image

Looking at the object using Get-Member, we will also see that my type I inserted is now considered to be the main type on this object.

$object | Get-Member

image

That looks a lot better now. If we were using a format file against this type name, it would apply to this object based on what we defined in the file.

So far you have seen me use New-Object with a hash table to create a custom object and set up the custom type names, but that doesn’t mean it is the only way to accomplish this. You can also use Select-Object to set up a custom object and still set a custom type on it as well.

$test = "" | Select Name, Title
$test.Name = 'Boe'
$Test.title = 'System Administrator'
$test

image

Currently, it is being registered as a string, which is not too exciting by any means. We can easily switch that up to something a little better.

$test.pstypenames.insert(0,'System.Example.StringObject.Custom')
$test.pstypenames

image

$test | Get-Member

image

We have now updated the type of this object to something other than being a string.

The last thing to remember is just because to update the type of an object, it does not become the object. For example, I cannot turn this into a hashtable magically with all of the associated methods.

$test.pstypenames.insert(0,'System.Collections.Hashtable')
$test.pstypenames
$test | Get-Member

image

Looks like it might be a hashtable looking at the typename, but the methods do not lie. This is not what it claims to be.

So there you go! You can now get started on creating your own objects and adding your own custom object types!

This entry was posted in powershell and tagged , , , . Bookmark the permalink.

2 Responses to Working With Custom Types of Custom Objects In PowerShell

  1. Pingback: Naming PowerShell custom objects and setting their default display properties « prgmr.io

  2. Pingback: PowerShell Magazine » My 10 best practices leading to the Scripting Games 2012 – Part II

Leave a comment