Creating your first Powershell GUI – Part 3

Getting caught up?

  • Part 1 – Creating a simple GUI
  • Part 2 – Adding variables, added functionality
  • Part 3 – (that’s where we are)

In this post, I’ll be adding some error checking in the form of a function. In a late article, I may revisit this and re-write some of these functions to clean up the code.

For now, we’ll focus on the following:

The Form should look something similar based on the code provided in Part 2

In Part 2, we used

  • Textbox1
  • Button1
  • Datagridview1

I’ll be covering element 3 (Button2) – “Search output to out-gridview” in this post. I’ll also be doing some error-checking in the event that there are no results to display.

In Part 2, we used this piece of code to output the results of the query into the datagridview:

Function ADSearch {
$wc = ‘*’ 
$Namesearch = $wc + $textbox2.text + $wc 
$results= get-Aduser -Filter {name -like $Namesearch} -Server $Server -Credential $Credential 
$DataGridView1.DataSource = [System.Collections.ArrayList]([System.Object[]](,$results | Sort-Object SamAccountName, Name))
}

Now, we’re going to configure that button to use the powershell utility out-gridview. If you’re not familiar with this command, it’s super handy for many reasons.

Below is the code, with the highlighted portions that pertain to the functionality of Button2, and  function ADSearch2.

$results = $null #reset the $results variable each run 
$server = "10.0.0.101"
$Credential = "dtab\administrator"

Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

$Form                            = New-Object system.Windows.Forms.Form
$Form.ClientSize                 = New-Object System.Drawing.Point(400,389)
$Form.text                       = "Form"
$Form.TopMost                    = $false

$Button1                         = New-Object system.Windows.Forms.Button
$Button1.text                    = "Search for User"
$Button1.width                   = 124
$Button1.height                  = 30
$Button1.location                = New-Object System.Drawing.Point(41,52)
$Button1.Font                    = New-Object System.Drawing.Font('Microsoft Sans Serif',10)
<#-----Calls a function 'ADSearch'-------#>
$Button1.Add_MouseClick({ADSearch($Textbox2.text)}) 

$TextBox2                        = New-Object system.Windows.Forms.TextBox
$TextBox2.multiline              = $false
$TextBox2.text                   = "Enter User to search here"
$TextBox2.width                  = 247
$TextBox2.height                 = 20
$TextBox2.location               = New-Object System.Drawing.Point(91,23)
$TextBox2.Font                   = New-Object System.Drawing.Font('Microsoft Sans Serif',10)

$DataGridView1                   = New-Object system.Windows.Forms.DataGridView
$DataGridView1.width             = 376
$DataGridView1.height            = 282
$DataGridView1.location          = New-Object System.Drawing.Point(12,94)

$Button2                         = New-Object system.Windows.Forms.Button
$Button2.text                    = "Search output to out-gridview"
$Button2.width                   = 206
$Button2.height                  = 30
$Button2.location                = New-Object System.Drawing.Point(182,52)
$Button2.Font                    = New-Object System.Drawing.Font('Microsoft Sans Serif',10)
$Button2.Add_MouseClick({ADSearch2($Textbox2.text)}) 

$Form.controls.AddRange(@(
        $TextBox2
        $Button1,
        $Button2,
        $DataGridView1
        ))

[system.windows.forms.application]::run($form) #Runs form with runtimes - this is a trial and error thing

Function ADSearch {
        <#------function 'ADSearch' runs Get-ADUser query, stores into $results variable------#>
        $wc = '*' #Wildcard character to assist with the text search
        $Namesearch = $wc + $textbox2.text + $wc #appends the wildcard characters to the search, infront and behind, stores into the $NameSearch Variable
        $results= get-Aduser -Filter {name -like $Namesearch} -Server $Server -Credential $Credential #This is the Query itself

        $number = $results.count #Count the number of results found
        display_results($results) #call function with results found
}

Function ADSearch2{
        $wc = '*' #Wildcard character to assist with the text search
        $Namesearch = $wc + $textbox2.text + $wc #appends the wildcard characters to the search, infront and behind, stores into the $NameSearch Variable
        $results= get-Aduser -Filter {name -like $Namesearch} -Server $Server -Credential $Credential #This is the Query itself

        $number = $results.count #Count the number of results found
        display_results2($results) #call function with results found
}

function display_results{
        if ($results -ne $null){
            #if results found, display in out-grid
            $DataGridView1.DataSource = [System.Collections.ArrayList]([System.Object[]](,$results | Sort-Object SamAccountName, Name))
        }
        else{
            #if no results found, display error message
            [System.Windows.MessageBox]::Show('No results found')
        }
}

function display_results2{
        if ($results -ne $null){
            #if results found, display in out-grid
            $results | out-gridview
        }
        else{
            #if no results found, display error message
            [System.Windows.MessageBox]::Show('No results found')
        }
}

Line 41, this calls the ADSearch2 function, with the input from textbox2.

$Button2.Add_MouseClick({ADSearch2($Textbox2.text)})

Lines 62 – 69, this is the ADSearch2 function. Notice though, how it only captures it into the $result variable. We also count the number of results found and store that into $Number. This is where error-checking comes in.

Function ADSearch2{
        $wc = '*' #Wildcard character to assist with the text search
        $Namesearch = $wc + $textbox2.text + $wc #appends the wildcard characters to the search, infront and behind, stores into the $NameSearch Variable
        $results= get-Aduser -Filter {name -like $Namesearch} -Server $Server -Credential $Credential #This is the Query itself
 
        $number = $results.count #Count the number of results found
        display_results2($results) #call function with results found
}

Lines 82 – 90, is the function that checks the amount of results and either shows the results, or displays ‘No results found’ in a popup box. That ‘if’ statement below looks at the number of results. If it’s Zero, it’s a Null Value. If it’s a Null Value, it goes into the ‘Else’ portion.

function display_results2{
        if ($results -ne $null){
            #if results found, display in out-grid
            $results | out-gridview
        }
        else{
            #if no results found, display error message
            [System.Windows.MessageBox]::Show('No results found')
        }
}

This line does the output into that out-gridview I mentioned earlier.

    $results | out-gridview

The out-gridview displays into it’s own separate window. Now, the beauty of this window is that it can be resized, filtered, copied and sorted.

Now, this code is not complete by any means. But it’s working and suits our needs for now. Ideally, the functions can be rewritten with more efficient code, perhaps a case statement. But for now, we have a working GUI that can do a simple search of users within an AD environment, output to an embedded Grid, or output to an external powershell utility in gridviewer. If there’s any improvements, I’m certainly open to doing more, or seeing what the I.T Blogging community has in store.

[ivory-search 404 "The search form 3350 does not exist"]

Creating your first Powershell GUI – Part 2

Already seen this part? Check out Part 1, Part 2, and Part3

In part 1, we covered the very basics. A one-line Get-ADUser query, a simple form with one button and output textbox.

In this entry, we’ll add more functionality that:

  • Captures input from the GUI
  • Outputs specific information
  • Makes use of variables

If you remember, we started off with this form:

Form 
Search up "Rick" 
Results show up here

Simple winform with a button, a textbox, and a function.

Now, we’re going to take input from a user, and display the output to a datagridview instead of a textbox. A textbox is usually fine for output, but with a Get-ADUser query, there are multiple fields we usually want to look at. Text boxes don’t do text wrapping very well, and the output is kind of messy. Also in using a grid, it neatly sorts everything based on some criteria we create.

Here’s a sample of what the box looks like afterwards in PoshGUI:

ο υ1ρυ1 to

I’ve labelled each major component, and listing the names in the Powershell code for easier reference:

  1. Textbox1 = This is the input from the end user. Or more accurately, we’ll be capturing the ‘text’, in the form of $textbox1.text into a variable, and using that in our Get-ADUser search parameter.
  2. Button1 = This executes the search query with the captured text from textbox1. The output from this will go into the 4th component: the datagridview.
  3. Button2 = This will execute the exact same search, but outputs it to an external gridviewer. I’ll go through some of the pro’s and con’s of this method later.
  4. Datagridview1 = output of Get-Aduser shows up here.

As I stated earlier, a textbox is usually fine for some simple output. A datagridview is handy since it puts all the results into columns that are resizable, sortable and we can copy directly from it. I listed two different ways to use grid form with Button 2 and the Datagridview1. I’ll cover more about what each does soon.

Below is the completed source code that:

  • Makes use of the “search for User” button (AKA, ‘$button1’)
  • Takes input from the textbox (AKA, ‘$Textbox2.text’)
  • Uses a function ‘ADSearch’ which we defined the parameters
  • Ouputs the result to a gridview embedded into the form.

I’ll go into more detail about the Gridviewer output, the variables, then we’ll create some code for error checking.

$results = $null #reset the $results variable each run
$server = “10.0.0.101”
$Credential = “contoso.com\administrator”

Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

$Form = New-Object system.Windows.Forms.Form
$Form.ClientSize = New-Object System.Drawing.Point(400,389)
$Form.text = “Form”
$Form.TopMost = $false

$Button1 = New-Object system.Windows.Forms.Button
$Button1.text = “Search for User”
$Button1.width = 124
$Button1.height = 30
$Button1.location = New-Object System.Drawing.Point(41,52)
$Button1.Font = New-Object System.Drawing.Font(‘Microsoft Sans Serif’,10)
<#—–Calls a function ‘ADSearch’——-#>
$Button1.Add_MouseClick({ADSearch($Textbox2.text)})

$TextBox2 = New-Object system.Windows.Forms.TextBox
$TextBox2.multiline = $false
$TextBox2.text = “Enter User to search here”
$TextBox2.width = 247
$TextBox2.height = 20
$TextBox2.location = New-Object System.Drawing.Point(91,23)
$TextBox2.Font = New-Object System.Drawing.Font(‘Microsoft Sans Serif’,10)

$DataGridView1 = New-Object system.Windows.Forms.DataGridView
$DataGridView1.width = 376
$DataGridView1.height = 282
$DataGridView1.location = New-Object System.Drawing.Point(12,94)

$Button2 = New-Object system.Windows.Forms.Button
$Button2.text = “Search output to out-gridview”
$Button2.width = 206
$Button2.height = 30
$Button2.location = New-Object System.Drawing.Point(182,52)
$Button2.Font = New-Object System.Drawing.Font(‘Microsoft Sans Serif’,10)

$Form.controls.AddRange(@(
			$TextBox2
			$Button1,
			$Button2,
			$DataGridView1
))

[system.windows.forms.application]::run($form) #Runs form with runtimes – this is a trial and error thing

Function ADSearch {
<#——function ‘ADSearch’ runs Get-ADUser query, stores into $results variable——#>
$wc = ‘*’ #Wildcard character to assist with the text search
$Namesearch = $wc + $textbox2.text + $wc #appends the wildcard characters to the search, infront and behind, stores into the $NameSearch Variable
$results= get-Aduser -Filter {name -like $Namesearch} -Server $Server -Credential $Credential #This is the Query itself
<#—–Display output to the embedded DataGridView——-#>
$DataGridView1.DataSource = [System.Collections.ArrayList]([System.Object[]](,$results | Sort-Object SamAccountName, Name))
}

Let’s look at the variables:

$results = $null #reset the $results variable each run
$server = "10.0.0.101"
$Credential = "contoso.com\administrator"

This will come in handy later when we call the Get-ADUser query. By passing variables, it becomes a little easier to change the script to fit our needs. Especially if you’re dealing with credentials or domains.

Now let’s look at the datagridview:

$DataGridView1.DataSource = [System.Collections.ArrayList]([System.Object[]](,$results | Sort-Object SamAccountName, Name))

Breaking down each component:

$DataGridView1.DataSource

This is the datagriviewd itself. By default it’s already in a neatly arranged set of columns and rows. Makes sense when we use it for a large amount of data with multiple fields. Makes for easier parsing if we’re looking for something.

[System.Collections.ArrayList]([System.Object[]]

Since the Datagrid arranges the data, we need to store the information into an array. If we didn’t, it would all be string information. Some data does not translate into string information nicely (such as ‘account enabled’, which would just translate to a 1 or a 0).

(,$results

An array by default starts with a ‘0’ (zero) value. To display the results of the AD search, we stored it into the $results variable. By putting the comma in front “,” this tells the array to display all the contents from the beginning of the array.

| Sort-Object SamAccountName, Name))

The Pipe and Sort-Object commands sort the values accordingly by SamAccountName, then by Name. These values were imported by the original get-aduser command. You could actually list this by any value that get-Aduser is able to pull, such as ‘displayname’, ’email’, etc…

Read up on Part3 of this tutorial, where I’ll be adding an error checking ability, as well as using the other button for a different style of output.

[ivory-search 404 "The search form 3350 does not exist"]

Creating your first Powershell GUI – Part 1

Already seen this part? Check out Part 1, Part 2, and Part3

Powershell, while a powerful tool can sometimes lack that person touch that a GUI interface offers. Console output is fine and dandy, but there are times when parsing through a large amount of data can be done with a GUI and some simple commands.

From here, I’m going to assume you know the basics. Such as awareness of the get-executionpolicy and set-executionpolicy commands, and a little knowledge of PowerShell ISE.

The Setup

I’m doing this with my home lab from a non-domain computer. Which means I’ll be using some credential switches you may not need.

For this example, we’ll take something simple, like

Get-ADUser

Get-ADUser gets a user object or searches to get multiple user objects from Active Directory. To keep this simple, we’ll have it search up a name. You’ll get the idea of what I’m doing and how we can keep it somewhat simple.

First, we’ll get a simple query working. Let’s search for a user named ‘Rick’

get-Aduser -Filter {name -like '*rick*' } -Server 10.0.0.101 -Credential "contoso.com\administrator"

Explanation of the above query:

-Filter {name -like '*rick*'}

Search for a username using wildcards in-front and behind of name we’re looking for.

-Server 10.0.0.101

Look at a specific Domain controller. Since this is on a different subnet for me, I’m specifying it by IP. You can simply use the hostname of the domain controller, or you can use “-SearchBase” and plug in the domain name itself.

-Credential "contoso.com\Administrator" 

Provide a specific set of credentials with read access to the domain. Since I’m issuing these commands from an non-domain machine, this is handy for me in the testing phase.

Put this or something very close to this into PowerShell ISE. Highlight the code and hit F8 to run the selection. This just ensures you have something to search for. Obviously, I chose ‘Rick’ because that name exists in my Domain, you’ll have to pick or create one to search.

So now we have the format of the query, how can we turn it into a GUI?

Visit POSHGUI.com. This is a free website that creates the Powershell forms for you. All you need to do is create the code to plunk in. Goto WinForms Designer.

Now on the form drag a button and a text box. For this example, we’ll want the text box a little bigger – which means in the ‘behavior’ section, we need multi-line. You should have something similar to the below:

ön

I kept the default values for each. They should be button1 and textbox1 respectively from here on.

What we want to happen: When pressing ‘Search Up “Rick”‘ button, the results should show in the text box below.

In PoshGUI click on the ‘Code’ button. This creates the entire form with coordinates, arguments and ranges.

1 • This form was created using POSÆU1.co• 
. NAME 
unti t led 
Add-Type -AssemblyNsme System Windous.Forns 
a free online gui designer for Power-shell 
[System. Windows . Forms . Application] : : EnableVisuaIStyIes() 
SForn. Clientsize 
SFcrn. text 
11 
SFcrn. Topmost 
12 
S Buttonl 
14 
ss uttcnl. text 
IS 
SS uttcnl.nidth 
IS 
SSuttcn1. height 
17 
SButtcn1. location 
IS 
SButtcn1. Font 
19 
STexteox1 
21 
SText20x1. multi line 
22 
STexteox1. text 
23 
STexteox1. nidth 
24 
SText20x1. height 
STexteox1. location 
STexteox1. Font 
27 
29 
Object 
Yeu Object 
- "Form" 
Sfalse 
Object 
"Search up 
Object 
Object 
Object 
St rue 
system .Windous . Forms . Form 
system. Windows . Forms . Button 
'"Rick' 
System. Drawing. Point(é2, 14) 
System.orauing. Font( •microsoft Sans Serif' , le) 
system. Windows . Forms . TextBox 
"Results show up here" 
Object System.orawing. 
Object System.orauing. Font( •microsoft Sans Serif' , le) 
ST extBox1

The above is a screenshot, I’ve added my code below with some additional explanation in between the comments.

$results = $null #reset the $results variable each run

Add-Type -AssemblyName System.Windows.Forms

[System.Windows.Forms.Application]::EnableVisualStyles()
$Form = New-Object system.Windows.Forms.Form
$Form.ClientSize = New-Object System.Drawing.Point(400,324)
$Form.text = “Form”
$Form.TopMost = $false

$Button1 = New-Object system.Windows.Forms.Button
$Button1.text = “Search up `”Rick`””
$Button1.width = 253
$Button1.height = 30
$Button1.location = New-Object System.Drawing.Point(62,14)
$Button1.Font = New-Object System.Drawing.Font(‘Microsoft Sans Serif’,10)
<#—–Calls a function ‘ADSearch’——-#>
$Button1.Add_MouseClick({ADSearch})

$TextBox1 = New-Object system.Windows.Forms.TextBox
$TextBox1.multiline = $true
$TextBox1.text = “Results show up here”
$TextBox1.width = 338
$TextBox1.height = 261
$TextBox1.location = New-Object System.Drawing.Point(26,57)
$TextBox1.Font = New-Object System.Drawing.Font(‘Microsoft Sans Serif’,10)

$Form.controls.AddRange(@($Button1,$TextBox1))

[system.windows.forms.application]::run($form) #Runs form with runtimes – this is a trial and error thing

Function ADSearch {
<#——function ‘ADSearch’ runs Get-ADUser query, stores into $results variable——#>

$results= get-Aduser -Filter {name -like ‘*rick*’ } -Server 10.0.0.101 -Credential “contoso.com\administrator”

<#—–Display output to $Textbox1.text——-#>
$TextBox1.text = $results

}

Copy and paste that code, edit the query to whatever name exists in your Domain, and the IP to match whatever domain IP you have. Hit F5 to run the script, and you should see something similar.

Form 
Search up "Rick" 
Results show up here

Click the Mouse Button, enter your domain credentials and the results display:

Form 
Search up "Rick" 
CN=Rick

And that’s about it! It’s a simple script, and shows some of the very simple ways to display information in a GUI. This only needs PowerShell ISE, PoshGUI, and some curiosity.

If you want to make this a little fancier, take input from a user, and display specific information, join me for Part 2.

[ivory-search 404 "The search form 3350 does not exist"]