Navigate / search

PowerShell – How to build a GUI with Visual Studio

Sometimes PowerShell scripts are a way to comlicated to present your hardly gathered data to end users that are not familiar with the command line. Therefore I recommend to present data by Windows WPF forms that could be achived without being a coding expert.

With the help of Visual Studio everyone is able to build WPF forms even without coding expertise. In this tutorial I will show you how to generate a User Information script displaying Hostname, Username and Domainname. This is a basic tutorial showing how to build a graphical user interface within minutes. The script can be extended easily, for example you can display “Model Type” of your Hardware, “Network Drives” connected, “Outlook Profile” size, installed software and a lot more!

Visual Studio can be downloaded for free at Microsoft – https://www.visualstudio.com/downloads/

 

home Start a Project

Start Visual Studio (Express / Community / Professional) and open a “New Project …

Visual Studio – New Project

Select “WPF Appplication” and confirm with “OK“.

Visual Studio – WPF Application

Result:

The result is an empty WPF form that will be extended within the next steps.

Visual Studio – Workspace

plus Add Labels, Textboxes and Close Button

Add four labels to your form as in the picture below. If the Toolbox on the left side isn’t available on your Visual Studio installation you could reopen this element by clicking “View –> Toolbox“.

Visual Studio – Add Label

Add three textboxes to your form.

Visual Studio – Add Textboxes

Add a close button to your form.

Visual Studio – Add Button

Result:

Visual Studio will automatically generate the following XAML code that can be used in PowerShell.

<Window x:Class="WpfApplication9.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication9"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Label x:Name="label" Content="Hostname" HorizontalAlignment="Left" Margin="38,84,0,0" VerticalAlignment="Top" Width="132"/>
        <Label x:Name="label1" Content="User" HorizontalAlignment="Left" Margin="38,115,0,0" VerticalAlignment="Top" Width="132"/>
        <Label x:Name="label1_Copy" Content="Domain" HorizontalAlignment="Left" Margin="38,146,0,0" VerticalAlignment="Top" Width="132"/>
        <Label x:Name="label2" Content="Headline" HorizontalAlignment="Left" Margin="38,51,0,0" VerticalAlignment="Top" Width="132" FontWeight="Bold"/>
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="170,87,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="170,118,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <TextBox x:Name="textBox2" HorizontalAlignment="Left" Height="23" Margin="170,148,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <Button x:Name="button" Content="Close" HorizontalAlignment="Left" Margin="38,197,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>

To generate a WPF in PowerShell we can use the following script as a good start.

[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = @"

<-- PASTE VISUAL STUDIO XML CODE HERE -->

"@
#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader"; exit}

# Store Form Objects In PowerShell
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}

#Show Form
$Form.ShowDialog() | out-null

Before we can paste our Visual Studio XAML code into the PowerShell script we have to perform some small modifications:

  • Change line 1 from <Window x:Class=”WpfApplication9.MainWindow”  to <Window
  • Remove line 6 and 7
  • Line 10 to 17 – Rename x:Name=  to Name=

After modification just paste the XAML code to your PowerShell script in line 4.

Result:

[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = @"

<Window 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"


        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Label Name="label" Content="Hostname" HorizontalAlignment="Left" Margin="38,84,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label1" Content="User" HorizontalAlignment="Left" Margin="38,115,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label1_Copy" Content="Domain" HorizontalAlignment="Left" Margin="38,146,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label2" Content="Headline" HorizontalAlignment="Left" Margin="38,51,0,0" VerticalAlignment="Top" Width="132" FontWeight="Bold"/>
        <TextBox Name="textBox" HorizontalAlignment="Left" Height="23" Margin="170,87,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <TextBox Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="170,118,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <TextBox Name="textBox2" HorizontalAlignment="Left" Height="23" Margin="170,148,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <Button Name="button" Content="Close" HorizontalAlignment="Left" Margin="38,197,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>


"@
#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader"; exit}

# Store Form Objects In PowerShell
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}

#Show Form
$Form.ShowDialog() | out-null

Save your PowerShell script and execute it. If you used PowerShell ISE to built your script just press F5 and you will see the following result.

Your Application – Main Window

check Congratulations you built your own PowerShell GUI!


plus Add Close Event

Now that we are able to display our form we should get the close button running first. We just have to assign a event to our button that is named “button” by default.

[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = @"

<Window 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"


        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Label Name="label" Content="Hostname" HorizontalAlignment="Left" Margin="38,84,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label1" Content="User" HorizontalAlignment="Left" Margin="38,115,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label1_Copy" Content="Domain" HorizontalAlignment="Left" Margin="38,146,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label2" Content="Headline" HorizontalAlignment="Left" Margin="38,51,0,0" VerticalAlignment="Top" Width="132" FontWeight="Bold"/>
        <TextBox Name="textBox" HorizontalAlignment="Left" Height="23" Margin="170,87,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <TextBox Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="170,118,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <TextBox Name="textBox2" HorizontalAlignment="Left" Height="23" Margin="170,148,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <Button Name="button" Content="Close" HorizontalAlignment="Left" Margin="38,197,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>


"@
#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader"; exit}

# Store Form Objects In PowerShell
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}

#Assign event
$button.Add_Click({
    $form.Close()
})

#Show Form
$Form.ShowDialog() | out-null

You are now able to close you application by clicking 


plus Add System Variables

To receive the Hostname, Username and the Domain we can use the following commands:

Write-Output $env:COMPUTERNAME
Write-Output $env:USERNAME
Write-Output $env:USERDOMAIN

Just add the following marked lines to your code and you are done with your first PowerShell WPF Form.

[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = @"
<Window 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Label Name="label" Content="Hostname" HorizontalAlignment="Left" Margin="38,84,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label1" Content="User" HorizontalAlignment="Left" Margin="38,115,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label1_Copy" Content="Domain" HorizontalAlignment="Left" Margin="38,146,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label2" Content="Headline" HorizontalAlignment="Left" Margin="38,51,0,0" VerticalAlignment="Top" Width="132" FontWeight="Bold"/>
        <TextBox Name="textBox" HorizontalAlignment="Left" Height="23" Margin="170,87,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <TextBox Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="170,118,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <TextBox Name="textBox2" HorizontalAlignment="Left" Height="23" Margin="170,148,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <Button Name="button" Content="Close" HorizontalAlignment="Left" Margin="38,197,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>
"@
#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader"; exit}

# Store Form Objects In PowerShell
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}

#Assign system variables
$textBox.text = $env:COMPUTERNAME
$textBox1.text = $env:USERNAME
$textBox2.text = $env:USERDOMAIN

#Assign event
$button.Add_Click({
    $form.Close()
})

#Show Form
$Form.ShowDialog() | out-null

Result:

Your Application – Working Variables

Feel free to modify your XAML code in Visual Studio to get better user experiences. As an example I’ve created the following XAML code.

[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = @"
<Window 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow" Height="192.937" Width="417.383" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" WindowStyle="None" Background="White">
    <Grid HorizontalAlignment="Left" Width="407" Height="187" VerticalAlignment="Top">
        <Label Name="label" Content="Hostname" HorizontalAlignment="Left" Margin="10,56,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label1" Content="User" HorizontalAlignment="Left" Margin="10,87,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label1_Copy" Content="Domain" HorizontalAlignment="Left" Margin="10,118,0,0" VerticalAlignment="Top" Width="132"/>
        <Label Name="label2" Content="User Information" HorizontalAlignment="Left" Margin="10,12,0,0" VerticalAlignment="Top" Width="387" FontSize="14" FontWeight="Bold"/>
        <TextBox Name="textBox" HorizontalAlignment="Left" Height="23" Margin="142,59,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="252" BorderThickness="0" FontWeight="Bold"/>
        <TextBox Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="142,90,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="252" BorderThickness="0" FontWeight="Bold"/>
        <TextBox Name="textBox2" HorizontalAlignment="Left" Height="23" Margin="142,120,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="252" BorderThickness="0" FontWeight="Bold"/>
        <Button Name="button" Content="Close" Margin="149,156,149,0" VerticalAlignment="Top"/>
    </Grid>
</Window>
"@
#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader"; exit}

# Store Form Objects In PowerShell
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}

#Assign system variables
$textBox.text = $env:COMPUTERNAME
$textBox1.text = $env:USERNAME
$textBox2.text = $env:USERDOMAIN

#Assign event
$button.Add_Click({
    $form.Close()
})

#Show Form
$Form.ShowDialog() | out-null

As you can see the result looks different to the form before and it just took a few minutes to achive this result in Visual Studio.

Your Application – Final Result

Leave a comment

name*

email* (not published)

website

This site uses Akismet to reduce spam. Learn how your comment data is processed.