User Rating: 4 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Inactive
 

After many years of writing scripts for the Windows PowerShell console, I’m now learning the next level of automation — writing GUI applications that run Windows PowerShell commands. PowerShell Studio forms provide a gentle and well-guided introduction to GUI applications, but it’s still taken me some time to break old habits.

I constantly need to remind myself that things that “just work” in the console don’t make any sense in a GUI. Writing output is one of them.

Writing Output to the Console

When you generate output in the Windows PowerShell console, the output appears as text strings in the console window.

PS C:> Get-Date
Wednesday, December 3, 2014 7:16:38 AM

Behind the scenes, Windows PowerShell silently appends an Out-String command to the pipeline and sends the results to “standard output” (“stdout”). The process that hosts Windows PowerShell handles the standard output, almost always by writing the output to the console (host behavior might vary).

So, if you run a cmdlet that returns objects, such as the Get-Process cmdlet, (string representations of) the objects appear in the console.

If you format objects, such as by using Format-List or Format-Table, (string representations of) the formatted objects appear in the console.

If you run Write-Host or Write-Output, Out-Host or Out-String, the output strings appears in the console.

And even if you send the output to an alternate output stream by using Write-Warning, Write-Verbose, or Write-Error, by default, the output appears in the console.

But GUI application don’t have a console. What happens to the output that would otherwise go to the console when there is no console? And, more importantly, how do I manage output without a console?

Where is my output?

GUI applications, like the cool ones that you write in PowerShell Studio, don’t have a console. There is no standard output. There is no auto-appended Out-String.

So, when you generate output and don’t save it to a file or a variable, the output is just lost.

Get-Process | ... <Nowhere> ...

It’s like a pitcher throwing a baseball when there’s no catcher on the field. The ball just falls to the ground and rolls to a stop .. ignored.

Baseball on the ground

So, in a GUI application, you can’t just write output and hope for the best. If you want to display cmdlet output or save it, you need to do it explicitly.

Display output in a text box

A GUI application is a collection of controls. To display output, you need to assign the output to a control, such as text box, rich text box, or a data grid.

For example, to display the name of the local computer in the console, you run an $env:ComputerName command.

PS C:> $env:ComputerName
JUNEB-TESTBOX

When I try the same thing in a GUI application where there is no console, I don’t see any result at all. In this example, I created a form with a button that, when clicked, runs the $env:ComputerName expression.

$buttonComputerName_Click = {
    <b>$env:ComputerName</b>
}

But, when I click the button, nothing happens, even if I have a console window open.

Get-ComputerName - no response on click

To display the computer name in a GUI application, I add a display control to my form and assign the output of the command to a method of the display control.

For example, I can add a Textbox control to the form and use the assignment operator (=) to assign the result of the expression to the Text property of the TextBox. Now, when you click the button, you see the output in the TextBox.

$buttonComputerName_Click = {
    $textboxResults.Text = $env:ComputerName
}

Here’s the result:

Get-ComputerName Result

Display Output in a Different Program

You can also display the output of commands in objects that are not part of your program. GUI professionals think that this approach is sloppy and not a best practice, but you might find it useful for testing or debugging.

For example, you can pipe the output to the Out-GridView cmdlet.

$buttonComputerName_Click = {
    $env:ComputerName | Out-GridView
}

Here’s the result:

Out-GridView Result

You can also write to a file and open the file. These sample commands create a temporary file, write to the file, and then use Notepad to display the file. Again, this makes real programmers cringe, but it works, at least for testing.

$buttonComputerName_Click = {
    $TmpFile = [System.IO.Path]::GetTempFileName
    $env:COMPUTERNAME | Set-Content -Path $TmpFile
    Notepad $TmpFile
}

Here’s the result:

GetTempFileName() Result

Convert to Strings

Another task you need to manage in a GUI application is converting objects to text strings. Usually, this just means piping your output to an Out cmdlet, such as Out-String. Out cmdlets, including Out-GridView, convert objects to string data.

When you write output to the console, Windows PowerShell automatically appends an Out-String command to the pipeline. But, there is no console and no automatic Out-String in a GUI application.

When you assign non-string objects to a string object or to a control that takes string objects, such as a TextBox, Windows PowerShell calls the toString() method of the object. (In other languages, the assignment would just fail, but it’s trying to help.) With some objects, such as DateTime and ErrorRecord objects, toString() works just fine, but, in many cases, it produces odd-looking results.

For example, this command assigns the results of a Get-Process command to a text box. Windows PowerShell recognizes that you need text and calls the toString() method of Process objects, but the result is not useful.

$buttonGetProcess_Click = {
    $textboxResults.Text = Get-Process
}

Get-Process

To get a string representation of the default process table, pipe the output to the Out-String cmdlet and then assign it to the text box.

$buttonGetProcess_Click = {
    $textboxResults.Text = Get-Process | Out-String
}

OutString

TIP: To make the output easy to read, set the text box (or rich text box) to use a monospace font. In PowerShell Studio, right click the text box, click Apply Property Set, and then click Apply Console Font.

Don’t avoid toString() completely. There are a few objects where the toString() method produces a useful result. DateTime objects are the classic example. The toString() method of a DateTime object returns a “short-date/long-time” format string. Out-String returns a “long-date/long-time” format.

PS C:> (Get-Date).ToString()
12/6/2014 10:42:24 AM

PS C:> Get-Date | Out-String
Saturday, December 6, 2014 10:42:37 AM
#Uses toString()
$buttonGetDate_Click = {
    $textboxDate.Text = Get-Date
}

Get-Date

#Uses toString()
$buttonGetDate_Click = {
    $textboxDate.Text = Get-Date | Out-String
}

Get-Date OutString

You can also use the Format and UFormat parameters of the Get-Date cmdlet to get a formatted date string in almost any configuration. For example, to get a date in RFC1123 format, use -Format R (or “r”). No need to pipe to Out-String when you use Format or UFormat, because these parameters force the cmdlet to return a string.

PS C:> Get-Date -Format R
Tue, 09 Dec 2014 10:46:41 GMT

Get-Date Format

Converting Formatted Objects

In the console, Format cmdlets, such as Format-Table, are usually the last element in a pipeline. The output looks great in the console, because Windows PowerShell appends an Out-String command to the pipeline before sending it to the console.

PS C:> Get-HotFix | Format-Table -Property HotFixID, InstalledOn -AutoSize

HotFixID     InstalledOn
--------     -----------
KB2693643    10/7/2014 12:00:00 AM
KB2769299    9/5/2014 12:00:00 AM
KB2883200    10/7/2013 12:00:00 AM
KB2883684    9/5/2014 12:00:00 AM
...

But, in a GUI application, by default, you get the result of calling the toString() method of the format objects that the Format cmdlets return.

$buttonGetHotfix_Click = {
    $textboxHotFix.Text = Get-HotFix |
    Format-Table -Property HotFixID, InstalledOn -AutoSize
}

Get-Hotfix

To get a more usable display in your GUI application, pipe the format objects to the Out-String cmdlet before assigning them to the Text property of the TextBox.

$buttonGetHotfix_Click = {
    $textboxHotFix.Text = Get-HotFix |
    Format-Table -Property HotFixID, InstalledOn -AutoSize |
    Out-String
}

Get-Hotfix Format-Table Out-String

That’s better!

After a while, the task of managing the output display in your GUI applications become as natural as typing a cmdlet name, but while you’re learning, be sure to test and make sure that all of your output is captured and displayed in a usable format.

June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at This email address is being protected from spambots. You need JavaScript enabled to view it. or follow her on Twitter at @juneb_get_help.

If you have questions about our products, please post in our support forum.
For licensed customers, use the forum associated with your product in our Product Support Forums for Registered Customers.
For users of trial versions, please post in our Former and Future Customers - Questions forum.
Copyright © 2024 SAPIEN Technologies, Inc.