How to specify computed property in Select-Object

After a week in the wild (~ without Internet) I quickly skimmed through blog posts and noticed something like this: Get-ChildItem |... | Select-Object {(gci $_.FullName).CreationTime}. Did you notice the script block {(gci $_.FullName).CreationTime}?

What does the script block mean?

When I begun with PowerShell it was quite hard to find something about the syntax or how to use it. For someone who tries to get into PowerShell, here is just a quick review:

  • Get-ChildItem | Select-Object Name,Length
    This command simply selects Name and Length properties from passed objects – System.IO.FileInfo and System.IO.DirectoryInfo
  • Get-ChildItem | Select-Object {[int]($_.Length/1mb)},Name
    The property Length is replaced by a script block that gets the value from pipeline and returns something. Note that the script block may do whatever you want, e.g. run a SQL query (hm, silly) or get your Twitter timeline. The point is that the column is computed.
  • Get-ChildItem | Select-Object @{"Name"="Size (MB)"; "Expression"={[int]($_.Length/1mb)}},Name
    Where is the change? We don't pass script block as parameter value, we pass a hashtable. There are two pairs – first one with a key "Name" that specifies the name of the resulting property and second one with the key "Expression" that specifies the value of the property.
    Note that the value for "Expression" si the same script block that was supplied in the command #2.
  • Get-ChildItem | Select-Object @{"N"="Size (MB)"; "E"={[int]($_.Length/1mb)}},Name
    The last command is the same as #3 but the keys are shortened to "N" (insted of "Name") and "E" (instead of "Expression"). The keys are not case sensitive, so you can use "n" and "e" as well.

Other command lets

If you are interested in other command lets that support this type of syntax, go to the New-CustomColumn function PowerShell V1.0 post by The PowerShell Guy. Then you might end up with something like this:

Get-ChildItem | Format-Table @{
    Label="Full name"; 
    Expression={$_.FullName}; 
    FormatString="$((Get-Date)) {0}"; 
    Alignment="right" 
}

One last note: if you use Select-Object don't expect that the properties are evaluated every time you access them. Consider them as fields (their name in PowerShell is NoteProperty). They are evaluated at the time when they are created.

Meta: 2009-09-21, Pepa