Setting default formatting of PSCustomObjects from script

Hi,

Take the following demo script:

foreach ($value in @(0, 1.2, 0.5))
{
    [PSCustomObject] @{
        Property0 = (Get-Date).AddDays($value * 100)
        Property1 = $value
        Property2 = $value * $value
        Property3 = $value * $value * $value
        Property4 = "{0:0000.000000}" -f $value
    }
}
When run, the output is:
Property0 : 2020-01-15 11:33:43
Property1 : 0
Property2 : 0
Property3 : 0
Property4 : 0000.000000

Property0 : 2020-05-14 11:33:43
Property1 : 1.2
Property2 : 1.44
Property3 : 1.728
Property4 : 0001.200000

Property0 : 2020-03-05 11:33:43
Property1 : 0.5
Property2 : 0.25
Property3 : 0.125
Property4 : 0000.500000

I would like that the default display formatting when running the script be:
  • as if piped through Format-Table -Autosize
  • with the numbers formatted with a prescribed format
For instance, I'd like the following display:
Property0           Property1 Property2 Property3 Property4
---------           --------- --------- --------- ---------
2020-01-15 11:35:31 0.00      0.00      0.000     0000.000000
2020-05-14 11:35:31 1.20      1.44      1.728     0001.200000
2020-03-05 11:35:31 0.50      0.25      0.125     0000.500000
Can this be done (preferably without .ps1xml files, only from the script)?

Thanks in advance for your help.

To make this appear visually for reporting or output to an end-user, especially with numbers typically requires conversion to a string with string format or the .ToString() method.

$results = foreach ($value in @(0, 1.2, 0.5))
{
    [PSCustomObject] @{
        Property0 = (Get-Date).AddDays($value * 100)
        Property1 = '{0:F2}' -f $value
        Property2 = '{0:F2}' -f ($value * $value)
        Property3 = '{0:F3}' -f ($value * $value * $value)
        Property4 = "{0:0000.000000}" -f $value
    }
}

$results

If the goal of the script is to output to a user and is not being consumed further, why not just use Format-List? Powershell chooses the format based on the number of properties, four (4) or greater and it displays in Table format, see if you just remove a single property:

$results = foreach ($value in @(0, 1.2, 0.5))
{
    [PSCustomObject] @{
        Property0 = 1
        Property1 = 2
        Property2 = '{0:F2}' -f ($value * $value)
        Property3 = '{0:F3}' -f ($value * $value * $value)
        #Property4 = "{0:0000.000000}" -f $value
    }
}

$results

As you’ve eluded, you can override this with a PS1XML, but Format-Table can format it “pretty” for reporting purposes.

Thanks for your response.

Maybe my questioning was not precise enough, but the point is that the script’s output is not restricted to being consumed “visually.” For instance, I might want to pipe it through Where-Object, or Group-Object, whatever. This requires preserving the types (in the real script, there are double’s, datetime’s…).

I just want that if I just display the output, it looks nicely formatted.

I have a vague memory of encountering “properties attached to properties” (or whatever the proper wording should be) that determine the preferred formatting, but I can’t remember where…

 

Properties can be set to default and you can hide properties, as seen here:

https://poshoholic.com/2008/07/05/essential-powershell-define-default-properties-for-custom-objects/

Outside of that, I am not aware of how Powershell would know what you intend to do with an object such as display or use it to pass along and format it differently.

PS C:\Users\rasim> $results[1].Property2
1.44

PS C:\Users\rasim> $results[2].Property2
0.25

PS C:\Users\rasim> $results[1].Property2 + $results[2].Property2
1.440.25

PS C:\Users\rasim> [double]$results[1].Property2 + [double]$results[2].Property2
1.69

The strings do break things, took me a minute to realize that 1.440.25 is just the string concatenated. If you are writing the functions, then you would define the type to do the conversion, like so:

$results = foreach ($value in @(0, 1.2, 0.5))
{
    [PSCustomObject] @{
        Property0 = (Get-Date).AddDays($value * 100)
        Property1 = '{0:F2}' -f $value
        Property2 = '{0:F2}' -f ($value * $value)
        Property3 = '{0:F3}' -f ($value * $value * $value)
        Property4 = "{0:0000.000000}" -f $value
    }
}

function Test-It {
    param (
       [Parameter(
            Mandatory=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [double]$Property2
    )
    begin{}
    process {
         $temp += $Property2
    }
    end {
        $temp
    }
}

$results | Test-It

Then you can get the best of both worlds where things would display nicely and you convert back to required types for math operations.