A PowerShell Script to Find System Uptime: Formatting Results

Posted on February 16, 2015 by Jeff Hicks in PowerShell with

I think we’re almost finished with our PowerShell scripting journey. We started with a one-line PowerShell command and we ended up with an advanced PowerShell function to check system uptime that’s complete with help and examples. If you’re joining us at the end of the journey, then take a few minutes to retrace our steps. All set? This looks like a nice place to end our journey.

The original command included a formatting cmdlet to properly display the uptime information. As I noted, you should not include formatting in your scripts and functions, as this limits you. Instead, your command should write objects to the pipeline and  then use the format cmdlets if you need anything formatted. This is the default output:

The default output without any formatting. (Image Credit: Jeff Hicks)

The default output without any formatting. (Image Credit: Jeff Hicks)

 

It works, but it would probably be nice to have this formatted as a table.

Using the format-table cmdlet to format our results into a nice table in PowerShell. (Image Credit: Jeff Hicks)

Using the format-table cmdlet to format our results into a nice table in PowerShell. (Image Credit: Jeff Hicks)

 

This is much better. But I don’t want to have to always remember to pipe to Format-Table or have  to explain this process to anyone running my command. Instead, I want to have the display always formatted as a table, unless I specify otherwise. Here’s how we can achieve this goal.

PowerShell has an extensible type system, which means that you can customize the design of different object types and how they are formatted. I’m going to show you how to create a custom formatting extension so that the result is automatically displayed as a table when I run Get-MyUptime. Here’s the latest version of my function.

Right now, my function is writing a Selected.System.TimeSpan object to the pipeline.

Our function is writing a Selected.System.TimeSpan object to the pipeline. (Image Credit: Jeff Hicks)

Our function is writing a Selected.System.TimeSpan object to the pipeline. (Image Credit: Jeff Hicks)

 

I need to define my own type name for each object I write to the pipeline. To do that, I need to hold on to the object for a moment.

Next, I need to insert my property name into the collection of inherited type names.

You can use whatever naming convention you prefer. My object will have a typename of My.Uptime. Once that is added, I can write the object to the pipeline.

When I load this version into my session, nothing changes other than the object type.

The object type is now different in this version. (Image Credit: Jeff Hicks)

The object type is now different in this version. (Image Credit: Jeff Hicks)

 

That’s because I haven’t told PowerShell how to handle a My.Uptime object. This is accomplished with formatting directives stored in a ps1xml file. PowerShell ships with several if you want to take a look.

Just be careful not to make any changes to the file. I’m going to show you how to create your own. Your file will take a structure like this:

You can define as many table and list views as you need. Although this  sample isn’t complete by any means, it should provide guidance. If you are writing something like this by hand, note that tag names are case-sensitive.

Sponsored

Thus something like <Tablecontrol>…</tablecontrol> will cause errors. What I recommend is find something in an existing ps1xml file that is close to what you want and edit that. But let’s jump right to the end and look at my format file for My.Uptime objects.

My file has two views, which includes a table and a list. PowerShell will process them in order so the first one it finds will be the default. In my case this will be the table. The tricky part of creating a formatting file is that there is some trial and error, especially with tables to align everything the way you want. In my file the labels for each column will be the same as the property name, but they don’t have to be. I’ve also defined a list view. This view is defining three lines.

The first line is the Computername property. The second line is the LastRebootTime property but I’m going to display LastBoot. The last line will be called Uptime and its value will be the result of a scriptblock that will display the uptime timespan as a string.

I save the file in my Scripts directory as MyUptime.Format.ps1xml. To load the settings into PowerShell I’ll use the Update-FormatData cmdlet.

Because this is a new type, it doesn’t really matter if I append or prepend. It only makes a difference if you are loading a type definition that might already exist. Append or prepend determines if your definition is applied first or last. As I mentioned, there might be some trial and error in getting your formatting just right. Fortunately starting in PowerShell 3, you can run Update-Format data as often as you need to in the same session. You can verify with Get-FormatData.

Using Get-FormatData in Windows PowerShell. (Image Credit: Jeff Hicks)

Using Get-FormatData in Windows PowerShell. (Image Credit: Jeff Hicks)

 

You can drill down the FormatViewDefinition property to see the settings.

The FormatViewDefinition property lets us see different settings. (Image Credit: Jeff Hicks)

The FormatViewDefinition property lets us see different settings. (Image Credit: Jeff Hicks)

 

Now let’s see what happens when I run Get-MyUptime.

Running Get-MyUptime in PowerShell again. (Image Credit: Jeff Hicks)

Running Get-MyUptime in PowerShell again. (Image Credit: Jeff Hicks)

 

PowerShell looked at the object coming out of the pipeline and checked its type, My.Uptime. It then found a formatting directive for that type and used it. It’s like magic! Nothing changes as far as the underlying object is concerned.

Sponsored

The only thing that changes is how it is formatted by default. But you can still override the default formatting. Remember my list view?

The list view for Get-MyUptime. (Image Credit: Jeff Hicks)

The list view for Get-MyUptime. (Image Credit: Jeff Hicks)

 

In order for all of this to work, I need to remember to use Update-FormatData to load my ps1xml file. You could add the command after your function definition in the script file that you are dot sourcing. Or you can take the final step and package all of this as a module. We’ll look at that next time.

Sponsored

Tagged with , , , ,