Wednesday, September 03, 2014

PowerShell + WPF + GUI : Hide (Use) background PowerShell Console

Few years back, I had started wrapping my PowerShell scripts with some sort of GUI built using Windows Forms (used Primal Forms CE mostly). Things went fine for a while but then I stumbled across awesome posts by MVP Boe Prox on using WPF with PowerShell to do the same. (check Resources section)

I had been procrastinating the idea of playing with WPF for a while but then had a great discussion with MVP Chendrayan (Chen) and got inspired to do it.

One can use Visual Studio (Express Edition - which is free) to design the UI and then consume the XAML in PowerShell script...Isn't that Cool ! See resources section for links on that.

Often when we write the Code to present a nice UI to the end user there is a PowerShell console running in the background. In this post I would like to share a trick to hide/show the background console window. This trick works with both Winforms and XAML.

Note - PowerGUI & Visual Studio Express are absolutely FREE !

For the demo of this post I have a GUIdemo.ps1 script with below contents :


001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
[xml]$xaml= @"
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="HideWindow" Title="Initial Window" WindowStartupLocation = "CenterScreen"
    Width = "335" Height = "208" ShowInTaskbar = "True" Background = "lightgray">
    <Grid Height="159" Name="grid1" Width="314">
        <TextBox Height="46" HorizontalAlignment="Left" Margin="44,30,0,0" Name="textBox" VerticalAlignment="Top" Width="199" />
        <CheckBox Content="Show PS Windpw" Height="52" HorizontalAlignment="Left" Margin="34,95,0,0" Name="checkBox" VerticalAlignment="Top" Width="226" FontSize="15" />
    </Grid>
</Window>
"@

Add-Type -AssemblyName PresentationFramework
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load( $reader )

#Tie the Controls
$CheckBox = $Window.FindName('checkBox')
$textbox = $Window.FindName('textBox')


$CheckBox.Add_Checked({$textbox.text = "Showing PS Window"Show-Console})
$CheckBox.Add_UnChecked({$textbox.text = "Hiding PS Window"Hide-Console})
$Window.ShowDialog()


Save the above contents in a file and right click on it select "Run with PowerShell".


This will open up a PowerShell console window and our simple UI , right now if you check the checkbox it writes to the textbox but later on we will be able to toggle the background PowerShell Window on and off.


One of the simplest ways to hide this window as I have shown in one of my earlier post is by using PowerGUI to wrap it as an exe 

Open the Script in PowerGUI Script Editor and then go to Tools > Compile Script




This will open up another window where you can select to not show the PowerShell console.



But this option will either permanently hide the window or show it. What if I wanted to give the end users an option to toggle the background PowerShell window on and off. You would ask what purpose would it serve ?

Well I have been using this technique for a while to see various verbose messages being generated by my backend PowerShell functions.


In addition to that we can use write-host to highlight few key things in the console (Write-Host is perfect candidate here cause we just want to show stuff on the host).

So let's add the code which will provide the functionality to toggle the background PowerShell console.

Re-used the code provided at PowerShell.cz to P/Invoke.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021

#Function Definitions
# Credits to - http://powershell.cz/2013/04/04/hide-and-show-console-window-from-gui/
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();

[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'


function Show-Console {
$consolePtr = [Console.Window]::GetConsoleWindow()
[Console.Window]::ShowWindow($consolePtr, 5)
}

function Hide-Console {
$consolePtr = [Console.Window]::GetConsoleWindow()
[Console.Window]::ShowWindow($consolePtr, 0)
}


Now time to bind the functions above to the checkbox control and use few Write-Host statements in the code to make my case.


001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
[xml]$xaml= @"
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="HideWindow" Title="Initial Window" WindowStartupLocation = "CenterScreen"
    Width = "335" Height = "208" ShowInTaskbar = "True" Background = "lightgray">
    <Grid Height="159" Name="grid1" Width="314">
        <TextBox Height="46" HorizontalAlignment="Left" Margin="44,30,0,0" Name="textBox" VerticalAlignment="Top" Width="199" />
        <CheckBox Content="Show PS Windpw" Height="52" HorizontalAlignment="Left" Margin="34,95,0,0" Name="checkBox" VerticalAlignment="Top" Width="226" FontSize="15" />
    </Grid>
</Window>
"@

Add-Type -AssemblyName PresentationFramework
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load( $reader )

Write-Host -ForegroundColor Cyan -Object "Welcome to the Hide/Show Console Demo"
Write-Host -ForegroundColor Green -Object "Demo by DexterPOSH"
#Tie the Controls
$CheckBox = $Window.FindName('checkBox')
$textbox = $Window.FindName('textBox')


#Function Definitions
# Credits to - http://powershell.cz/2013/04/04/hide-and-show-console-window-from-gui/
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();

[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'


function Show-Console {
$consolePtr = [Console.Window]::GetConsoleWindow()
[Console.Window]::ShowWindow($consolePtr, 5)
}

function Hide-Console {
$consolePtr = [Console.Window]::GetConsoleWindow()
[Console.Window]::ShowWindow($consolePtr, 0)
}

Hide-Console # hide the console at start
#Events
Write-host -ForegroundColor Red "Warning : There is an issue"
$CheckBox.Add_Checked({$textbox.text = "Showing PS Window"Show-Console})
$CheckBox.Add_UnChecked({$textbox.text = "Hiding PS Window"Hide-Console})
$Window.ShowDialog() | Out-Null


Now copy the above code in PowerGUI and wrap it as an exe. Once done open the exe . Below is an animated GIF showing it in action (at the end it's a bit blurry cause of low FPS capture in gifcam). 




5 comments:

  1. Thanks for sharing, Its help me :)

    ReplyDelete
    Replies
    1. :) Let me know if you need more info on the GUI creation

      Delete
  2. Hi, This tutorial was my base knowledge when making powershell + wpf application, thanks for this post it gives me a place to start learning it. Right now I am in the middle of creating an application (ps + wpf). I wanna turn my form into Metro theme style which i did when i was using singe xaml page. But how to do it when using resource dictionary? (External xaml source file) Here is my code:

    #build the GUI
    Clear-host
    cd "D:\powershell\Lesson\metro"
    Add-Type –assemblyName PresentationFramework
    Add-Type –assemblyName PresentationCore
    Add-Type –assemblyName WindowsBase
    [xml]$xaml = @"
















    "@

    $reader = (New-Object System.Xml.XmlNodeReader $xaml)
    $Window = [Windows.Markup.XamlReader]::Load($reader)


    $Window.ShowDialog()


    ******i hope someone will email me Lumus_maxima@rocketmail.com

    ReplyDelete
    Replies
    1. Hey there,

      To be honest , I have never used Resource dictionary myself.
      But look at the below post on the PowerShell.com forum :

      http://powershell.com/cs/forums/t/15267.aspx

      Cheers

      Delete