I was working at a script where I created a custom object, and I wanted to to change the default properties shown when the object where written to the host. Easy enough, right? I have done this before of course, but this time I started thinking if it were possible to have the headings be different when using the default view, as opposed to, let’s say when shown using Format-List.

So, consider we have an object with the following properties: ‘FirstName’, ‘LastName’ and ‘Email’.

When called, it would display like this:

FirstName       LastName     Email
---------       --------     -----
John            Michaelson   jm@email.com

And using Format-List:

FirstName : John
LastName  : Michaelson
Email     : jm@email.com

But this is what I wanted my output to be when calling the object:

First Name      Last Name    E-mail
---------       --------     -----
John            Michaelson   jm@email.com

This is just an example of course, and could easily have been achieved using Select-Object with a custom expression.

So why didn’t I just name my properties this way when I defined the object in the script you might ask? I asked myself the same thing, but I like a challenge, ok? Besides, what I wanted was that the heading when used with Format-Table was for the headings to be ‘First Name’, ‘Last Name’ and ‘E-mail’, while when used with Format-Table * or Format-List, they should show as ‘FirstName’, ‘LastName’, and ‘Email’. Makes sense right?

After doing a little research I decided that I needed to define a format.ps1xml file to make this happen. After a lot of trial-and-error I got it working as I wanted. Was I happy now? No, of course not. There had to be a better way! Back to Google with me, and after a while I came over a link to Windows PowerShell Cookbook by Lee Holmes, at Google Books. I actually own this book, and see that in it, he have actually written a function called Add-FormatData that let’s you add a table formatting definition for a specific type name. His function didn’t solve my little problem though, but I had enough information now to build upon his function.

I ended up with two functions; New-FormatTableItem and Add-FormatTable, which let’s you perform what I wanted like this:

@(
  (New-FormatTableItem 'First Name' 'FirstName' 20),
  (New-FormatTableItem 'Last Name' 'LastName' 20),
  (New-FormatTableItem 'E-mail' 'Email' 20)
) | Add-FormatTable -TypeName 'Custom.UserType'

The New-FormatTableItem functions are used to create an array of Table Items, which I then pipe into Add-FormatTable. I don’t know how useful this is going to be for you guys, but it was a fun exercise for me, so I wanted to share it. Here is the code:


function New-FormatTableItem {
<#
.SYNOPSIS
Create new format Table Item
.DESCRIPTION
Create new format Table Item for use with Add-FormatTable
.EXAMPLE
Assuming you have a custom object with a type name of 'Custom.UserType':
@(
(New-FormatTableItem 'First Name' 'FirstName' 20),
(New-FormatTableItem 'Last Name' 'LastName' 20),
(New-FormatTableItem 'Sex' 'Sex' 10),
(New-FormatTableItem 'E-mail' 'Email' 20)
) | Add-FormatTable -TypeName 'Custom.UserType'
This will add a custom table formatting definition for the specified type name.
.NOTES
Based on a function by Lee Holmes in his excellent Windows PowerShell Cookbook (O'Reilly)
Author: Øyvind Kallstad
Date: 09.11.2014
Version: 1.0
#>
[CmdletBinding()]
param (
[Parameter()]
[string] $Label,
[Parameter(Mandatory)]
[string] $PropertyName,
[Parameter()]
[int] $Width = 20,
[Parameter()]
[System.Management.Automation.Alignment] $Alignment = 'Undefined'
)
$tableControlColumnHeader = New-Object TypeName System.Management.Automation.TableControlColumnHeader $Label, $Width, $Alignment
$tableControlColumn = New-Object TypeName System.Management.Automation.TableControlColumn $Alignment, (New-Object TypeName System.Management.Automation.DisplayEntry $PropertyName, 'Property')
Write-Output ([PSCustomObject] @{
TableControlColumnHeader = $tableControlColumnHeader
TableControlColumn = $tableControlColumn
})
}
function Add-FormatTable {
<#
.SYNOPSIS
Add table formatting definition for the specified type
.EXAMPLE
Assuming you have a custom object with a type name of 'Custom.UserType':
@(
(New-FormatTableItem 'First Name' 'FirstName' 20),
(New-FormatTableItem 'Last Name' 'LastName' 20),
(New-FormatTableItem 'Sex' 'Sex' 10),
(New-FormatTableItem 'E-mail' 'Email' 20)
) | Add-FormatTable -TypeName 'Custom.UserType'
This will add a custom table formatting definition for the specified type name.
.NOTES
Based on a function by Lee Holmes in his excellent Windows PowerShell Cookbook (O'Reilly)
Author: Øyvind Kallstad
Date: 09.11.2014
Version: 1.0
#>
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string] $TypeName,
[Parameter(ValueFromPipelineByPropertyName)]
[System.Management.Automation.TableControlColumnHeader[]] $TableControlColumnHeader,
[Parameter(ValueFromPipelineByPropertyName)]
[System.Management.Automation.TableControlColumn[]] $TableControlColumn
)
BEGIN {
$table = New-Object System.Management.Automation.TableControl
$row = New-Object System.Management.Automation.TableControlRow
}
PROCESS {
foreach($item in $TableControlColumn) {
$row.Columns.Add($item)
}
foreach($header in $TableControlColumnHeader) {
$table.Headers.Add($header)
}
}
END {
$table.Rows.Add($row)
$formatView = New-Object System.Management.Automation.FormatViewDefinition 'TableView', $table
$extendedType = New-Object System.Management.Automation.ExtendedTypeDefinition $TypeName
$extendedType.FormatViewDefinition.Add($formatView)
[Runspace]::DefaultRunspace.InitialSessionState.Formats.Add($extendedType)
Update-FormatData
}
}

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s