Using PowerShell’s Help Window for General Output

by May 29, 2015

To display text information, you can of course launch notepad.exe, and use the editor to display the text. Displaying text in an editor is not such a good idea, though, if you want to make sure the text cannot be changed.

PowerShell comes with a great window to display small and medium size texts: the built-in Help window.

With a little tweaking, this window can be reprogrammed to display just about any kind of text information. What's more, you can use the built-in full text search capabilities to navigate in your text, and even set foreground and background color as you like.

Just pipe any text you want displayed to Out-Window, and optionally specify colors, search word, and title. Here is the Out-Window function:

function Out-Window
{
  param
  (
    [String]
    $Title = 'PowerShell Output',

    [String]
    $FindText = '',

    [String]
    $ForegroundColor = 'Black',

    [String]
    $BackgroundColor = 'White'
  )
  
  # take all pipeline input:
  $allData = @($Input)
  
  if ($allData.Count -gt 0)
  {
    # open window in new thread to keep PS responsive
    $code = {
      param($textToDisplay, $FindText, $Title, $ForegroundColor, $BackgroundColor)

      $dialog = (New-Object TypeName Microsoft.Management.UI.HelpWindow($textToDisplay))
      $dialog.Title = $Title
      $type = $dialog.GetType()
      $field = $type.GetField('Settings', 'NonPublic,Instance')
      $button = $field.GetValue($dialog)
      $button.Visibility = 'Collapsed'
      $dialog.Show()
      $dialog.Hide()
      $field = $type.GetField('Find', 'NonPublic,Instance')
      $textbox = $field.GetValue($dialog)
      $textbox.Text = $FindText
      $field = $type.GetField('HelpText', 'NonPublic,Instance')
      $RTB = $field.GetValue($dialog)
      $RTB.Background = $BackgroundColor
      $RTB.Foreground = $ForegroundColor
      $method = $type.GetMethod('MoveToNextMatch', [System.Reflection.BindingFlags]'NonPublic,Instance')
      $method.Invoke($dialog, @($true))
      $dialog.ShowDialog()
    }
      
    $ps = [PowerShell]::Create()
    $newRunspace = [RunSpaceFactory]::CreateRunspace()
    $newRunspace.ApartmentState = 'STA'
    $newRunspace.Open()
      
      
    $ps.Runspace = $newRunspace
    $null = $ps.AddScript($code).AddArgument(($allData | Format-Table -AutoSize -Wrap | Out-String -Width 100)).AddArgument($FindText).AddArgument($Title).AddArgument($ForegroundColor).AddArgument($BackgroundColor)
    $null = $ps.BeginInvoke()      
  }
}

This is what a sample call could look like:

Get-Content C:\Windows\windowsupdate.log  |  
  # limit to first 100 lines (help window is not designed to work with huge texts)
  Select-Object -First 100 |
  Out-Window -Find Success -Title 'My Output' -Background Blue -Foreground White

Keep two things in mind:

  • The help window is not designed to display huge texts. Make sure you use this approach for texts that do not exceed a couple of kilobytes
  • This is just experimental code. There is no clean up of the PowerShell thread spawned to display the window. When you close the window, the PowerShell thread will stay around until you close PowerShell. What needs to be added is an event handler that fires when the help window closes. This event handler could then clean up the PowerShell thread.

 

Twitter This Tip! ReTweet this Tip!