Creating Custom Objects in PowerShell from Scratch

Welcome back to our four-part series on creating custom objects in PowerShell! In part one, I discussed the basics of creating custom objects in PowerShell to meet your needs; however, in this version, we lost the original object. In part two, I showed you how to modify and create the custom object while retaining the original. Today we’ll learn how to create a custom object from scratch.
Later, in part four I’ll go deeper and include the enhancements found in PowerShell 3.0.

Creating Custom Objects Using Add-Member

First, let’s use Add-Member to create our objects.

​$obj=New-Object PSObject
$obj | Add-Member Noteproperty -Name Name -value "Jeff Hicks"
$obj | Add-Member Noteproperty -Name Memory -value ((Get-WMIObject
win32_computersystem).TotalPhysicalMemory/1gb -as [int])
$obj | Add-Member Noteproperty -Name Title -value "PowerShell Pro"
$obj | Add-Member Noteproperty -Name MVP -value $True
$obj | Add-Member Noteproperty -Name Blog -value http://jdhitsolutions.com/blog

I create an empty object and pipe it to Add-Member, adding new items. When I write $obj to the pipeline, I end up with this:

​PS C:\> $obj
Name : Jeff Hicks
Memory : 8
Title : PowerShell Pro
MVP : True
Blog : http://jdhitsolutions.com/blog

This is a reasonable solution if you are gathering values to assign to your custom object throughout the script. I’ve also seen the following approach – which, although it does work, it is really more of a kludge.

​$obj = "" | Select Name,Memory,Title,MVP,Blog
$obj.Name="Jeff Hicks"
$obj.Memory=(Get-WMIObject win32_computersystem).TotalPhysicalMemory/1gb -as [int]
$obj.Title="PowerShell Pro"
$obj.MVP=$True
$obj.Blog=http://jdhitsolutions.com/blog

Select-Object automatically creates the property names which are saved to $obj. You can then set each property. The end result is the same.

​PS C:\> $obj
Name : Jeff Hicks
Memory : 8
Title : PowerShell Pro
MVP : True
Blog : http://jdhitsolutions.com/blog

…well, almost. If I pipe the first example to Get-Member, my object type is System.Management.Automation.PSCustomObject. In the latter it is a Selected.System.String. Granted, this is a subtle distinction, but it could affect how items are formatted for display. It is possible to create your own formatting files and types, but that’s a whole ‘nother kettle of fish (or rather, series of articles). This second approach has some merits in an interactive session, but if you are creating custom objects in your scripts or functions, I think there is a better way to go about this in PowerShell 2.0.

Creating Custom PowerShell Objects Using New-Object

Since we’re talking about objects, let’s use a cmdlet that creates them: New-Object. You briefly saw this in the first example. With New-Object, you can create a blank custom object using the PSObject type. And while you could use the Add-Member technique, if you are only defining properties you can define them all at once by using a hash table, also known as an associative array.
You might start with something like this:

​$hash=@{
Name="Jeff Hicks"
Memory=(Get-WMIObject win32_computersystem).TotalPhysicalMemory/1gb -as [int]
Title="PowerShell Pro"
MVP=$True
Blog="http://jdhitsolutions.com/blog"
}


If you put all the elements on one line, you will need to separate them with a semicolon. But because each entry is on its own line, PowerShell knows where to separate them. I typically use this technique collecting new property names. I can even add to the hash table.

​$hash.Add("Help","http://bit.ly/AskJeffHicks")
$hash.Add("Book","PowerShell in Depth: An Administrator's Guide")

When I’m ready, I can call New-Object and use this hash table for all of my property values.

​New-Object -TypeName PSObject -Property $hash

This object is written to the pipeline.

​Help : http://bit.ly/AskJeffHicks
Name : Jeff Hicks
MVP : True
Book : PowerShell in Depth: An Administrator's Guide
Blog : http://jdhitsolutions.com/blog
Memory : 8
Title : PowerShell Pro

One potential downside in the second version is that you can’t predict in what order the properties will be displayed. You could create a custom format file, or if you’re in for really quick and dirty scripting, you could create something like this:

​New-Object -TypeName PSObject -Property $hash | Select Name,Title,MVP,Help,Book,Blog,Memory

In my example, I’m creating a one-off kind of object. But this approach works very well when working with objects in the pipeline.

​Function Get-SysInfo {
[cmdletbinding()]
Param(
[Parameter(Position=0,ValueFromPipeline=$True)]
[ValidateNotNullorEmpty()]
[string]$Computername
)
Process {
$os=Get-WmiObject Win32_OperatingSystem -ComputerName $computername
$cs=Get-WmiObject Win32_ComputerSystem -ComputerName $computername
$running=Get-Service -ComputerName $computername | where {$_.Status -eq "Running"}
$procs=Get-Process -ComputerName $computername
New-Object -TypeName PSObject -Property @{
Computername=$os.CSName
OS=$os.Caption
System=("{0} {1}" -f $cs.Manufacturer.Trim(),$cs.Model.Trim())
Services=$Running.Count
Processes=$Procs.count
}
} #close Process
} #close function

This function creates an entirely new object that pulls information from a variety of sources on a remote computer. Instead of creating a hash table in advance, I define one as the value for the –Property parameter. You can see the results of my efforts below in Figure 1.
Creating Custom Objects in Windows PowerShell
Figure 1: The custom object in action
This I can pipe to any other cmdlet, such as Export-CSV because it is an object. You can download Get-Sysinfo from the site.
Have I hit you over the head enough with my mantra that PowerShell is “all about the objects”? We’ll wrap up this series with part four, in which we’ll look at some new ways of creating objects in PowerShell 3.0.