Search code examples
powershellformattingnewline

PSCustomObject returns with extra return(s)


Using the documentation Everything you wanted to know about PSCustomObject

$myObject = [PSCustomObject]@{
    Name     = 'Kevin'
    Language = 'PowerShell'
    State    = 'Texas'
}

$myObject

Above results with


Name  Language   State
----  --------   -----
Kevin PowerShell Texas


Note the last line is a empty or a blank return. Is there a means to remove that?

If I convert the object to a string with

$myObject | Out-String).TrimEnd("`r`n").Trim()

The returns leave but I think there must be a means to do this without changing to a string ?


Solution

  • The empty line at the end is just the default Table format. Any object be it psobject or not, that is displayed as a table will have that empty line at the end. If you want a workaround for that Out-String with the .TrimEnd, probably the easiest way can be with oss (or Out-String -Stream) and then you can Select-Object -SkipLast 1 to get rid of the last empty line.

    $myObject | oss | Select-Object -SkipLast 1
    

    If you wanna skip also the first line, in PowerShell 7 you can combine -Skip with -SkipLast, in PowerShell 5.1 you will need to pipe into -Skip first and then pipe again into -SkipLast:

    # pwsh 7, this is OK:
    Select-Object -Skip 1 -SkipLast 1
    
    # pwsh 5.1, requires:
    Select-Object -Skip 1 | Select-Object -SkipLast 1
    

    If you wanna create a new function just like oss but that skips this last line by default you can create another steppable pipeline from Out-String that defaults to -Stream (just like oss) but also skips the last item:

    function oss2 {
        [CmdletBinding(HelpUri = 'https://go.microsoft.com/fwlink/?LinkID=2097024')]
        param(
            [ValidateRange(2, 2147483647)]
            [int] ${Width},
    
            [Parameter(ValueFromPipeline = $true)]
            [psobject] ${InputObject})
    
        begin {
            $sb = {
                Microsoft.PowerShell.Utility\Out-String @PSBoundParameters -Stream |
                    Select-Object -SkipLast 1
            }
    
            $pipe = $sb.GetSteppablePipeline($MyInvocation.CommandOrigin)
            $pipe.Begin($PSCmdlet)
        }
    
        process {
            $pipe.Process($InputObject)
        }
    
        end {
            $pipe.End()
        }
    }