Add to Technorati Favorites
Welcome to ThePowerShellGuy.com Sign in | Join | Help

New-CustomColumn function PowerShell V1.0

In this post  

I got triggered by a question on our MVP maillist, about using HashTables to make Custom columns with Select Object, a technique I use often

'm glad that you don't haev to remember label or name now, but it has always perplexed me why you ever name name,expression at all given that in all these cases you don't have hashtables with many objects, but rather an array of hashtables each with just the single (well two) items in them 

hello"| select-Object length,@{Name="onetoten";Expression = {1..10}},@{Name="thelength";Expression = {$_.length}}

why not just

"hello"| select-Object length,@{onetoten = {1..10};thelength= {$_.length}}

Jeffrey Snover Provided the following list for V2 with his answer ( The only place I found a list before for PowerShell V1.0 is is the "MSH User guide "(from the Beta version, seems to be replaced by the primer where I can't find it) hence I will paste the whole list here for reference)

We can take more than just name and expression:

 

·         Select-Object / -Property:

o   Expression: string / scriptblock

o   Name/Label: string

·         Group-Object / -Property:

o   Expression: string / scriptblock

·         Sort-Object / -Property

o   Expression: string / scriptblock

o   Ascending: bool

o   Descending: bool

·         Format-Wide / -Property

o   Expression: string / scriptblock

o   FormatString: string

·         Format-Custom / -Property

o   Expression: string / scriptblock

o   Depth: int

·         Format-List / -Property

o   Expression: string / scriptblock

o   FormatString: string

o   Label/Name: string

·         Format-Table / -Property

o   Expression: string / scriptblock

o   FormatString: string

o   Label/Name: string

o   Width: int

o   Alignment: string (limited to "left", "center", "right")

·         Format-XXX / -GroupBy

o   Expression: string / scriptblock

o   FormatString: string

o   Label/Name: string

As you can see from the list in the answer is that not only the select-object cmdlet takes a Hashtable as a custom property, but much more cmdlets do support this method amongst them all the Format Cmdlets.This technique can be very powerfull, but as I noted above, it is very hard to find information about this functionaly, or find a list of the possible options you have for the HashTable as in this list above.

Next to the use with Select-Object, the most usefull use of HashTables like this is for the Format-Table cmdlet where it provides a very powerfull way to customize and format the output by creating Custom Columns, and as you can see in the list above it is the Cmdlet that has the most options too.

 So I thought that it would make a good blog topic .and I figured that next to that making a function for this work, would make a good example to show the  use of the advanced function possibilities in parameter handling in PowerShell V2 CTP3 .

But as I did not have Powershell V2 CTP3 installed on the OS I'm currently running, I decided to start out with a PowerShell V1 example to show the Possibilities of Format-Table with Custom Columns and will show how we can improve this function in PowerShell V2 in the next post

 

The Basics :

 

we can use scriptblocks as parameters often in PowerShell and this is a very powerfull concept see for example  /\/\o\/\/ PowerShelled: PowerShell : Advanced renaming of files    

 in a select command we can also use scriptblocks instead of property to select , see for example the following post on my old blog :

/\/\o\/\/ PowerShelled: Report MP3 count and size by User from MSH

but as the complete scripttext becomes the property name, this is very hard to work with, we can solve that by creating a HashTable that has a value for the name and a value for the expression

, so we can give the scriptproperty a name. 

PS E:\PowerShell> dir | select name

Name
----
PowerShellAnalyzer
computers.txt
..


PS E:\PowerShell> dir | select {$_.name.toupper()}

$_.name.toupper()
-----------------
POWERSHELLANALYZER
COMPUTERS.TXT
..


PS E:\PowerShell> dir | select @{n='Name';e={$_.name.toupper()}}

Name
----
POWERSHELLANALYZER
COMPUTERS.TXT
..

for more usage examples and information how to preprepare them see also this post (ignore the topic, half way the post you can find a complete walktrough, explaining how using hashtables with select works and how to create the HashTables in front and store them in variables):

/\/\o\/\/ PowerShelled: PowerShell and Active Directory Part 5

 

Using HashTables with format-table 

 

The first caveat in PowerShell V1 is that with format-table the Name property is not supported but the Label property is used instead, this is very confusing and is solved in PowerShell V2 by supporting both Name as Label.

PS E:\PowerShell> dir | ft @{n='Name';e={$_.name.toupper()}}
Format-Table : Illegal key n
At line:1 char:9
+ dir | ft  <<<< @{n='Name';e={$_.name.toupper()}}

 

PS E:\PowerShell> dir | ft @{label='Name';e={$_.name.toupper()}}

Name
----
POWERSHELLANALYZER
COMPUTERS.TXT

As we have a lot of properties this can get very long and cryptic but we can make the hashTables in front and store them in a variable as shown in detail in the 2th post about select /\/\o\/\/ PowerShelled: PowerShell and Active Directory Part 5:

 PS E:\PowerShell> $name = @{label='Name';e={$_.name.toupper()}}
PS E:\PowerShell> dir | ft $name

Name
----
POWERSHELLANALYZER
COMPUTERS.TXT

But as Format-Object knows more properties I made a function to make even easier to make the Custom Columns

New-CustomColumn

 

 # Function New-CustomColumn for PowerShell V1.0
#
# Helper function to create Custom Columns for select or format cmdlets
# for more info and examples see :
#
http://thepowershellguy.com/blogs/posh/archive/2009/01/26/new-customcolumn-function-powershell-v1-0.aspx
#
# /\/\o\/\/ 2008
#
http://thePowerShellGuy.com

Function New-CustomColumn {
  PARAM (
    $Expression,
    $name,
    $label,
    $FormatString,
    [int]$Width,
    $Alignment
  )

  $column = @{}

  if ($Expression){
    $Column.Expression = $Expression
  } else {
    throw "Expression is mandatory"
  }
  if ($Name) {$Column.Name = $name}
  if ($Label) {$Column.Label = $Label}
  if ($FormatString) {$Column.FormatString = $FormatString}
  if ($Width) {$Column.Width = $Width}
  if ($Alignment) {$Column.Alignment = $Alignment}

  $Column.psobject.baseobject

}

Using the function above to create the HashTables for the Columns, I will show how we can make a completly customized output and cover the extra options we have with Format-Table, by changing the output of the dir command in PowerShell to mimic the DOS dir command.

 PS E:\PowerShell> new-CustomColumn -label Size -expression {$_.Length}

Name                           Value
----                           -----
Label                          Size
Expression                     $_.Length


PS E:\PowerShell> $size = new-CustomColumn -label Size -expression {$_.Length}
PS E:\PowerShell> dir | ft name,$size

Name                                                        Size
----                                                        ----
PowerShellAnalyzer
computers.txt                                               25
getworldtime.ps1                                            1181
HttpRest.ps1                                                17057
podiobooks.txt                                              186
poker.ps1                                                   21340
PowerShellAnalyzer.zip                                      7439208
prun.txt                                                    4048
psghost.zip                                                 3312
spaghetticode-powershell.mp3                                19235007
StartPage.vbs                                               537

in the example above we started with only a label to rename a property (Note that we need to use $_.Length now instead of just the name of the property , in the scriptblock the  $_ variable will contain the original Object that is passed into the select command)

PS E:\PowerShell> $modified = new-CustomColumn -l Modified -expression {$_.LastWriteTime} -formatString "yyyy-MM-dd HH:mm" -Width 20
PS E:\PowerShell> dir | ft $modified,$size,name

Modified                                Size                                    Name
--------                                ----                                    ----
2008-12-20 10:50                                                                PowerShellAnalyzer
2008-12-16 21:28                        25                                      computers.txt
2008-12-31 00:26                        1181                                    getworldtime.ps1
2008-12-18 22:30                        17057                                   HttpRest.ps1
2008-12-15 09:47                        186                                     podiobooks.txt
2009-01-01 23:09                        21340                                   poker.ps1
2008-12-20 10:50                        7439208                                 PowerShellAnalyzer.zip
2009-01-01 23:09                        4048                                    prun.txt
2008-12-18 23:38                        3312                                    psghost.zip
2008-12-20 08:49                        19235007                                spaghetticode-powershell.mp3
2008-12-18 12:16                        537                                     StartPage.vbs

In the next custom column we add "Modified" we used a new option -FormatString to not only rename the LastWriteTime property to Modified but also to display the date in a custom format (year-Month-Day time) and next to that we also set the Modified column to a fixed Width.

In the Following example I will show that as the Expression takes a scriptblock, we can embedd a complete multiline PowerShell script here, giving almost unlimited posibilities, in this case I use an if statement in the $type column to check the type of Object and if it is a directory I return <DIR> to mimic the output of the dos dir command :

PS E:\PowerShell> cmd /c dir
 Volume in drive E has no label.
 Volume Serial Number is DCE7-A82D

 Directory of E:\PowerShell

01-01-2009  23:09    <DIR>          .
01-01-2009  23:09    <DIR>          ..
16-12-2008  21:28                25 computers.txt
31-12-2008  00:26             1.181 getworldtime.ps1
18-12-2008  22:30            17.057 HttpRest.ps1
15-12-2008  09:47               186 podiobooks.txt
01-01-2009  23:09            21.340 poker.ps1
20-12-2008  10:50    <DIR>          PowerShellAnalyzer
20-12-2008  10:50         7.439.208 PowerShellAnalyzer.zip
01-01-2009  23:09             4.048 prun.txt
18-12-2008  23:38             3.312 psghost.zip
20-12-2008  08:49        19.235.007 spaghetticode-powershell.mp3
18-12-2008  12:16               537 StartPage.vbs
              10 File(s)     26.721.901 bytes
               3 Dir(s)   3.077.910.528 bytes free

 To get the  <DIR> before the Directories as we see in the output from the DOS dir command above 

PS E:\PowerShell> $type = new-CustomColumn -label type -Width 5 -expression {
>>   if($_.gettype().fullname -eq 'System.IO.DirectoryInfo'){
>>     '<dir>'
>>   }
>> }
>>
PS E:\PowerShell> dir | format-table $modified,$type,$size,$file

Modified                              type  Size                                  File
--------                              ----  ----                                  ----
2008-12-20 10:50                      <dir>                                       PowerShellAnalyzer
2008-12-16 21:28                            25                                    computers.txt
2008-12-31 00:26                            1181                                  getworldtime.ps1
2008-12-18 22:30                            17057                                 HttpRest.ps1
2008-12-15 09:47                            186                                   podiobooks.txt
2009-01-01 23:09                            21340                                 poker.ps1
2008-12-20 10:50                            7439208                               PowerShellAnalyzer.zip
2009-01-01 23:09                            4048                                  prun.txt
2008-12-18 23:38                            3312                                  psghost.zip
2008-12-20 08:49                            19235007                              spaghetticode-powershell.mp3
2008-12-18 12:16                            537                                   StartPage.vbs

Almost there only I'm not content with the Size yet, when we look at the output of dir in CMD.EXE we see that is looking better as it has thousand separators and it is right alligned, so lets see if we can do the same :

PS E:\PowerShell>  $size = new-CustomColumn -label Size -expression {if($_.length){$_.length / 1kb} } -w 15 -Align 'Right'  -f "#,0.## KB"
PS E:\PowerShell> dir | format-table $modified,$type,$size,$file

Modified             type             Size File
--------             ----             ---- ----
2008-12-20 10:50     <dir>                 PowerShellAnalyzer
2008-12-16 21:28                   0,02 KB computers.txt
2008-12-31 00:26                   1,15 KB getworldtime.ps1
2008-12-18 22:30                  16,66 KB HttpRest.ps1
2008-12-15 09:47                   0,18 KB podiobooks.txt
2009-01-01 23:09                  20,84 KB poker.ps1
2008-12-20 10:50               7.264,85 KB PowerShellAnalyzer.zip
2009-01-01 23:09                   3,95 KB prun.txt
2008-12-18 23:38                   3,23 KB psghost.zip
2008-12-20 08:49              18.784,19 KB spaghetticode-powershell.mp3
2008-12-18 12:16                   0,52 KB StartPage.vbs

I used the Alignment parameter to right align the Size, Converted the size into KB in the Expression and formatted it with 2 decimals, seperators and did place KB behind it.

And with that we covered all the options we can use in the HashTable for the Format-Table Cmdlet, below you find the complete code for the examples above  : 

 $modified = new-CustomColumn -label Modified -expression {$_.LastWriteTime} -f "yyyy-MM-dd HH:mm" -w 20

$type = new-CustomColumn -label type -Width 5 -expression {
  if($_.gettype().fullname -eq 'System.IO.DirectoryInfo'){
    '<dir>'
  }
}

$size = new-CustomColumn -label Size -expression {if($_.length){$_.length / 1kb} } -w 15 -Align 'Right'  -f "0.00 KB"

dir | format-table $modified,$type,$size,$file

That is it for now, it has become a long post but I hope it was usefull, In next post I will show how you can improve on the function using the CTP3 build 

Enjoy,

Greetings /\/\o\/\/  

 

Published Monday, January 26, 2009 3:54 PM by MoW
Filed under: ,

Comments

# The PowerShell Guy : New-CustomColumn function PowerShell V1.0

# New-CustomColumn function PowerShell V1.0

In this post I got triggered by a question on our MVP maillist, about using HashTables to make Custom

Monday, January 26, 2009 8:53 PM by The PowerShell Guy

# re: New-CustomColumn function PowerShell V1.0

Awesome post!!! thank you!!

Wednesday, February 11, 2009 2:55 PM by St Louis Rams

# re: New-CustomColumn function PowerShell V1.0

wow major eyeopener.. thanks for the great post

Friday, May 08, 2009 12:46 AM by Charter Communications

# Mailbox Database Sizes &laquo; The PoSH Student

Friday, June 26, 2009 1:09 PM by Mailbox Database Sizes « The PoSH Student

# re: New-CustomColumn function PowerShell V1.0

What do you do if you are inheriting property names from an external source like a .CSV file that has spaces in the heading names?

Can you change a NoteProperty -name after it has already been created by import-csv?

Saturday, March 06, 2010 9:03 PM by zardos42
Anonymous comments are disabled