Owain Esau
Owain Esau

Reputation: 1922

Write-Host into columns (formatted output)

I am trying to use Write-Host to output data into columns. I have found a way to do this, but it is quite messy:

Firstly, I set the console size using the following function:

function fn_SetConsoleSize {
    param ([int]$height, [int]$width, [string]$title)

    $bheight = $height
    if ($height -le 50) { 
        $bHeight = 51
    }

    $bwidth = $width
    if ($width -le 150) { 
        $bwidth = 150
    }

    $pshost = Get-Host
    $pswindow = $pshost.ui.rawui
    $newsize = $pswindow.buffersize
    $newsize.height = $bHeight
    $newsize.width = $bwidth
    $pswindow.buffersize = $newsize

    <# Window Size #>
    $newsize = $pswindow.windowsize
    $newsize.height = $height
    $newsize.width = $width
    $pswindow.windowsize = $newsize

    <# Other Console Changes #>
    $pswindow.windowtitle = $title
    $pswindow.foregroundcolor = "Yellow"
    $pswindow.backgroundcolor = "Black"
}

Then I just set the column sizes using whitespaces:

Write-Host ( " " * 20 ) "Candidates        = $($Counts[0])" -nonewline
Write-Host (" " * ( 32 - $($Counts[0]).tostring().length)) "Candidates        = $($Counts[0])"

Write-Host ( " " * 20 ) "Contacts          = $($Counts[1])" -nonewline
Write-Host (" " * ( 32 - $($Counts[1]).tostring().length))  "Contacts          = $($Counts[1])"

This does output how I want it to, but this part of my project is going to be quite long, so I would like to simplify this quite a lot if possible.

Here is an example of the output:

Enter image description here

Upvotes: 3

Views: 19639

Answers (3)

StephenP
StephenP

Reputation: 4081

While I would generally refrain from using Write-Host at all you may be able to simplify things with some here-strings.

Example:

# Some setup - this would obviously come from your data layer
$candidates = 12345
$contacts = 4444
$clients = 1234
$jobs = 12
$contracts = 555
$pplacements = 42

# Create the here-string
$here_string = @"
                ------------------------------------------------------------
                Record Counts
                ------------------------------------------------------------
                Candidates          = $candidates
                Contacts            = $contacts
                Clients             = $clients
                Jobs                = $jobs
                Contracts           = $contracts
                Perm Placements     = $pplacements
"@

# Clear the console and write the string
Clear-Host
$here_string

This is sample output

                ------------------------------------------------------------
                Record Counts
                ------------------------------------------------------------
                Candidates          = 12345
                Contacts            = 4444
                Clients             = 1234
                Jobs                = 12
                Contracts           = 555
                Perm Placements     = 42

The here-string will preserve your formatting and spacing and is far easier to read and maintain than the current way you are writing output, but it still allows you to use variables to retrieve data.

Upvotes: 2

Owain Esau
Owain Esau

Reputation: 1922

So, I decided to keep using Write-Host as I am just conveying results and don't need to do anything more with the data once it has been written to the console. I ended up writing a function to do this as i couldn't get the correct output from a here-string, here it is:

function fn_OutputColumns {
    param ( $columnCount, $outputData )

    $outputDataLength = @()
    $increase = [math]::Round($outputData.count / 2, [System.MidpointRounding]::AwayFromZero)

    if ( $outputData.Count % 2 -ne 0 ) { $oddColumn = 1 } else { $oddColumn = 0 }

    foreach ( $item in $outputData ) {
        $outputDataLength += $item.Length
    }

    for ( $i = 0; $i -lt $increase; $i++ ) {
        if ( $oddColumn -eq 1 ) {
            do {
                    Write-Host ( " " * 20 ) "$($outputData[$i][1])" ( " " * ( 20 - $($outputData[$i][1]).length ) ) "   = $($outputData[$i][0])" -nonewline
                    Write-Host ( " " * ( 24 - $($outputData[$i + $increase][0]).tostring().length ) ) $($outputData[$i + $increase][1]) ( " " * ( 15 - $($outputData[$i + $increase][1]).length ) ) "   = $($outputData[$i][0])"         
                    $i++
            } while ( $i -ne $increase - 1 )
            Write-Host ( " " * 20 ) "$($outputData[$i][1])" ( " " * ( 20 - $($outputData[$i][1]).length ) ) "   = $($outputData[$i][0])"
            $i++
        }
        else {
            Write-Host ( " " * 20 ) "$($outputData[$i][1])" ( " " * ( 20 - $($outputData[$i][1]).length ) ) "   = $($outputData[$i][0])" -nonewline
            Write-Host ( " " * ( 24 - $($outputData[$i + $increase][0]).tostring().length ) ) $($outputData[$i + $increase][1]) ( " " * ( 15 - $($outputData[$i + $increase][1]).length ) ) "   = $($outputData[$i][0])"
        }
    }
}

This way I can just call a function with an array of data whenever I want to display results in this format (also accounts for an odd amount of results).

Upvotes: 0

postanote
postanote

Reputation: 16096

StephenP is on point for the direction he's giving you.

As for this...

it does help but I wouldn't be able to keep the colours using here-strings, but that's not really an issue. Out of interest, why would you avoid using Write-Host?

Using Write-Host has been a hotly debated topic for a long while. Even by the inventor / author of PowerShell.

Write-Host Considered Harmful - by PowerShell founder Jeffrey Snover

http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful

When you are writing or reviewing PowerShell scripts, I’d like you to remember the following rule of thumb:

◾Using Write-Host is almost always wrong.

Write-Host is almost always the wrong thing to do because it interferes with automation. There are typically two reasons why people use Write-Host:

Lot's of other articles exist on the topic. In earlier versions of PoSH, Write-Host could not be used in pipeline, as the moment yo use it the data is gone from the buffer.

However, in PoSHv5 Jeffrey Snover now says...

With PowerShell v5 Write-Host no longer "kills puppies". data is captured into info stream https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Write-Information?view=powershell-5.1

Description

The Write-Information cmdlet specifies how Windows PowerShell handles information stream data for a command.

Windows PowerShell 5.0 introduces a new, structured information stream (number 6 in Windows PowerShell streams) that you can use to transmit structured data between a script and its callers (or hosting environment). Write-Information lets you add an informational message to the stream, and specify how Windows PowerShell handles information stream data for a command.

You can still use colors, without using Write host, by doing this ...

PowerTip: Write PowerShell Output in Color Without Using Write-Host

https://blogs.technet.microsoft.com/heyscriptingguy/2012/10/11/powertip-write-powershell-output-in-color-without-using-write-host

Summary: Write colorized output to the Windows PowerShell console without using the Write-Host cmdlet.

Hey, Scripting Guy! Question How can you write output to the Windows PowerShell console without using the Write-Host cmdlet?

Hey, Scripting Guy! Answer Set ForegroundColor to a different color by using $host.Ui.RawUi, and then use the Write-Output cmdlet to write the output. When you are finished, set the ForegroundColor back to its original color.

$t = $host.ui.RawUI.ForegroundColor

$host.ui.RawUI.ForegroundColor = "DarkGreen"

Write-Output "this is green output"

this is green output

$host.ui.RawUI.ForegroundColor = $t

...but it's a bit more cumbersome IMHO.

I wrote a function called Set-TextColor that I keep in my profile for easy access and use.

Upvotes: 2

Related Questions