For the last few months or so I’ve been doing more and more work in regards to providing support and code towards the Rubrik SDK for PowerShell. Now I most certainly wouldn’t say I’m well versed in PowerShell – sure I’ve used it for the last 7 years or so to author a number of scripts and custom modules around various IT Operational challenges, however, I’ve always just gone deep enough to get the job done, never really caring about the most efficient way to get there! Today I want to share a little bit around custom objects, and more specifically how to limit their output/display with custom TypeNames – again, something I’ve never so much cared about until there are users actually consuming my code 🙂 So with that, let’s dive in…

So – What are TypeNames?

Basically, everything we do inside PowerShell revolves mostly around an object – and every object we create, delete, or manipulate has what is called a TypeName, or more descriptive, an Object Type. Take for instance a simple string – using the Get-Member cmdlet we can see that our string below has a TypeName of System.String

"Go Habs Go" | Get-Member
System.String TypeName

Let’s do the same thing, this time using Get-Process instead…

Get-Process | Get-Member
System.Diagnostics.Process

As we can see, we are now dealing with an object with a TypeName of System.Diagnostics.Process.

So what do this TypeName definition even do?

To help illustrate this, let’s go ahead and run the Get-Process cmdlet to retrieve the Idle process.

Get-Process Idle
Get-Process Idle

As we can see, the process name, id and a handful of other metrics and properties are returned by default – but we know for a fact that Get-Process returns much more data that that – simply piping a ‘Select *’ to our cmdlet proves just that…

Get-Process Idle | Select *
Get-Process Idle | Select *

It’s the TypeName definition that actually limits, formats, and controls what data we see by default when we simply just execute the Get-Process command. In this case, it makes it much more readable and returns the most utilized or common information which we might need. These TypeName definitions are stored within ps1xml files, and basically define the default formats to display results. We can find the exact file and line number declaring the Process TypeName by executing the following

dir $pshome\*types.ps1xml -Recurse | Select-String System.Diagnostics.Process

Within that file, there are a number of displays for the Process TypeName, with the default matching to what we saw when calling the basic cmdlet earlier…

Declared Members and Properties

So with a little understanding of what TypeNames are and how they are defined let’s see how we can apply them to our custom objects we build within PowerShell…

Applying TypeNames to Custom Objects

Playing around with Get-Process and basic strings super fun and all – but let’s dive into some more real-world scenarios where custom TypeNames actually help us out. For example, let’s look at the TypeName for the Get-RubrikDatabase results.

Get-RubrikDatabase | Get-Member
System.Management.Automation.PSCustomObject

As we can see, we are dealing with a plain old CustomObject here – and if we execute the cmdlet we basically get back all the information associated with, well, databases which Rubrik knows about…

Get-RubrikDatabase
Get-RubrikDatabase

As shown there is a ton of information returned. Now, having only one or two databases added to a system this may be ok, but when we run this cmdlet with 1000 databases getting crammed into the results, well, it’s not pretty and requires either more code or lengthy scrolling to find the desired data.

So, to help alleviate this let’s go ahead and build a custom TypeName for the Rubrik Database in order to better format and filter what output is shown by default.

The first step to doing this is to build out our own custom .ps1xml file containing the ViewDefinitions we want. Sometimes it’s easier just to see the completed product and then walk through – so without further ado, here’s what I came up with for a definition of a Rubrik.MSSQLDatabase Object TypeName.

<?xml version="1.0" encoding="utf-8" ?>
<Configuration>
    <ViewDefinitions>
        <View>
            <Name>Default</Name>
            <ViewSelectedBy>
                <TypeName>Rubrik.MSSQLDatabase</TypeName>
            </ViewSelectedBy>
            <TableControl>
                <TableHeaders>
                    <TableColumnHeader>
                        <Label>Name</Label>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>Instance Name</Label>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>Recovery Model</Label>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>SLA Domain</Label>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>ID</Label>
                    </TableColumnHeader>                    
                </TableHeaders>
                <TableRowEntries>
                    <TableRowEntry>
                        <TableColumnItems>
                            <TableColumnItem>
                                <PropertyName>name</PropertyName>
                            </TableColumnItem>
                            <TableColumnItem>
                               <PropertyName>instanceName</PropertyName>
                            </TableColumnItem>                            
                            <TableColumnItem>
                               <PropertyName>recoveryModel</PropertyName>
                            </TableColumnItem>
                            <TableColumnItem>
                                <PropertyName>effectiveSlaDomainName</PropertyName>
                            </TableColumnItem>
                            <TableColumnItem>
                                <PropertyName>id</PropertyName>
                            </TableColumnItem>                            
                        </TableColumnItems>
                    </TableRowEntry>
                </TableRowEntries>
            </TableControl>
        </View>
    </ViewDefinitions>
</Configuration>

As we can see in the above ps1xml file, rather than displaying a ton of information at once, we limit the Rubrik.MSSQLDatabase object to only showing Name, Instance Name, Recovery Model, SLA Domain and ID by default.

But, before any of this will actually work we need to instruct our module to read this information – this is done within our modules definition file and is easily defined with the addition of the following code…

FormatsToProcess = @('ObjectDefinitions/Rubrik.MSSQLDatabase.ps1xml')              

Once our module is aware of our new definition file, the last step is to apply the definition to our returned results. Within the Rubrik module the results of a cmdlet are always stored within a variable named $result – so in our case, we just need to do the following before returning our $result variable

 $result | ForEach-Object {
    $_.PSObject.TypeNames.Insert(0, "Rubrik.MSSQLDatabase")
 }

 return $result

Now if we run a Get-Member on our database cmdlet again we will see the following…

Get-RubrikDatabase | Get-Member

And if we initiate the cmdlet by itself to return all the databases known to the Rubrik cluster we can see that our default view is most certainly applied…

Get-RubrikDatabase

So there we have it! A pretty cool way to better display your custom objects through your code. No more should your end-users have to sift through tons and tons of properties and attributes looking for the most commonly sought after property names. And of course, if they are missing something they need, the can always pipe to “| Select *” to see the complete object. Thanks for reading! MP