Building Cleaner, Responsive WPF Forms

In my first two posts on this subject, I was just getting started with learning responsive WPF form building. I’m here today to show you a better way to build a responsive WPF using runspaces that will do the exact same thing as my previous uploads showed. Just better.

This time, I won’t be putting the form into its own runspace. As I learnt you didn’t need to from JRV over on the TechNet forums. This has some benefits that I will very helpfully, briefly and probably incorrectly list below:

  • Don’t have to use syncHash when updating the form
  • One less runspace for the form
  • Having a form in its own runspace creates additional overhead and possible errors

So to display the form I would use something like the below:

[xml]$xml = @"
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    Title="Counter" Height="119" Width="351.5" ResizeMode="CanMinimize" WindowStartupLocation="CenterScreen">
    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
        <Label Name="Label" Content="0" HorizontalAlignment="Left" Margin="16.666,9.333,0,0" VerticalAlignment="Top" FontSize="18"/>
        <Button Name="Button" Content="Start" HorizontalAlignment="Center" VerticalAlignment="Top" Width="75" Margin="123.25,63,123.25,0"/>
    </Grid>
</Window>
"@

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

$Label = $Window.FindName("Label")
$Button = $Window.FindName("Button")

$Window.ShowDialog() | Out-Null

Which will give us the below form:

But what if I want the button press to make the label number increase? I would use something like this on the button press:

[xml]$xml = @"
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    Title="Counter" Height="119" Width="351.5" ResizeMode="CanMinimize" WindowStartupLocation="CenterScreen">
    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
        <Label Name="Label" Content="0" HorizontalAlignment="Left" Margin="16.666,9.333,0,0" VerticalAlignment="Top" FontSize="18"/>
        <Button Name="Button" Content="Start" HorizontalAlignment="Center" VerticalAlignment="Top" Width="75" Margin="123.25,63,123.25,0"/>
    </Grid>
</Window>
"@

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

$Label = $Window.FindName("Label")
$Button = $Window.FindName("Button")

$Button.Add_Click({
    $counter = 1 

    do{
        Start-Sleep -Milliseconds 5
        $label.content = $counter
        [System.Windows.Forms.Application]::DoEvents()
        $counter += 1
    }while ($counter -le 5000)

})

$Window.ShowDialog() | Out-Null

This produces a form which increases the label up to 5000 when the button is pressed. You can see this below:

But what if I want to actually run something in a runspace. For example, test the connection to google.com? Then I would use the below code:

[xml]$xml = @"
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    Title="Counter" Height="119" Width="351.5" ResizeMode="CanMinimize" WindowStartupLocation="CenterScreen">
    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
        <Label Name="Label" Content="0" HorizontalAlignment="Left" Margin="16.666,9.333,0,0" VerticalAlignment="Top" FontSize="18"/>
        <Button Name="Button" Content="Start" HorizontalAlignment="Center" VerticalAlignment="Top" Width="75" Margin="123.25,63,123.25,0"/>
    </Grid>
</Window>
"@

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

$Label = $Window.FindName("Label")
$Button = $Window.FindName("Button")

$Button.Add_Click({
    $syncHash = [hashtable]::Synchronized(@{})
    $Runspace = [runspacefactory]::CreateRunspace()
    $Runspace.ApartmentState = "STA"
    $Runspace.ThreadOptions = "ReuseThread"
    $Runspace.Open()
    $Runspace.SessionStateProxy.SetVariable("syncHash",$syncHash)

    $powershell = [powershell]::Create().AddScript({
        $connection = Test-Connection -ComputerName google.com -Count 5
        $syncHash.output = [math]::Round(($connection.ResponseTime | Measure-Object -Average).Average)
    })

    $powershell.Runspace = $Runspace

    $Object = $powershell.BeginInvoke()

    do {
        Start-Sleep -Milliseconds 50
        [System.Windows.Forms.Application]::DoEvents()
    }while(!$Object.IsCompleted)

    $powershell.EndInvoke($Object)
    $powershell.Dispose()

    $label.Content = $syncHash.output
})

$Window.ShowDialog() | Out-Null

All the above examples will stay responsive whilst the action is performed. There are a couple of different methods to do this as you can see above, for anything that takes some time to complete, a runspace is needed. But when you are updating the form quickly, like the counter, then no runspace is needed. 

Enjoy!

Launching a Remote Console, the Smart Way

Today, I kind of stumbled across a way of connecting to a remote host quite a bit more sophisticated. Basically, the difference is that it will check to see if the connection was successful or not.

This still works off the basic premise of opening a new PowerShell process and using the -ArgumentList parameter to instantly connect to a remote system. This is the command I use (THIS IS JUST FOR CLEARER EXPLANATION, USE THE ONE-LINER BELOW):

Start-Process PowerShell -ArgumentList "-noexit -command Clear-Host; 
    try{ 
        Enter-PSSession -ComputerName $COMPUTERNAMEHERE -ErrorAction Stop; 
        Write-Host 'You should now be connected to the remote host, check below...' -ForeGroundColor Green 
    
    }catch{
        Write-Host 'Could not perform action - most likely that access is denied for the invoke' -ForeGroundColor Red 
    
    } 
"

Or as a one-liner:

Start-Process PowerShell -ArgumentList "-noexit -command Clear-Host; try{ Enter-PSSession -ComputerName $COMPUTERNAMEHERE -ErrorAction Stop; Write-Host 'You should now be connected to the remote host, check below...' -ForeGroundColor Green }catch{Write-Host 'Could not perform action - most likely that access is denied for the invoke' -ForeGroundColor Red } "

This is what the command does

  • Starts a new powershell console
  • clears the host
  • tries to the connection
  • writes output to console

Enjoy!

Handling Textbox Keydown Events

Welcome to another instalment of “how much can I confused myself today…”

Here, I will you how to recognise a keydown event on a textbox and also how to “identify” which key was pressed. This was useful to me because I wanted a button to be pressed when the user pressed the enter key whilst typing in a textbox. Similar to when you type a question into Google and press enter instead of pressing the search button.

First, I found what control I want the event to handle and added a raiseevent onto the button I wanted pressing. You can see this below:

$syncHash.Textbox.Add_KeyDown({
    if ($args[1].key -eq 'Enter'){
        $syncHash.Button.RaiseEvent((New-Object -TypeName System.Windows.RoutedEventArgs -ArgumentList $([System.Windows.Controls.Button]::ClickEvent)))
    }
})

So in this scenario, when the user wants to search they can just press enter in the textbox and the button will be pressed. You can also do this for the entire form. Meaning that if you have multiple textboxes and want an enter in any of them to press a button, you can just put the handler onto the entire form. You can see this below:

$syncHash.Window.Add_KeyDown({
    if ($args[1].key -eq 'Enter'){
        $syncHash.Button.RaiseEvent((New-Object -TypeName System.Windows.RoutedEventArgs -ArgumentList $([System.Windows.Controls.Button]::ClickEvent)))

    }
})

Enjoy!

Adding an BASE64 Icon to a WPF GUI

Nice and simple one today. I’m going to show you how to add an icon to a WPF GUI in PowerShell using BASE64 data.

I won’t be putting my BASE64 data into this post since its a MASSIVELY long string of characters but it should look something like this ” iVBORw0KG…”

First, we need to create a new variable to hold the data and then use the bitmapimage object to convert the data into a usable icon. You can see this below:

[string]$script:base64=@"
iVBORw0KGgo...
"@

$script:bitmap = New-Object System.Windows.Media.Imaging.BitMapImage
$bitmap.BeginInit()
$bitmap.StreamSource = [System.IO.MemoryStream][System.Convert]::FromBase64String($base64)
$bitmap.EndInit()
$bitmap.Freeze()

After this we can simply assign the new icon to the form using the code below:

$window.Icon = $bitmap

Enjoy!

Responsive PowerShell WPF Form Introduction #2

Following on from my last post, I’m going to show you how to update a textbox using a button on the same form. I will be adding the following code starting on line 38:

#BUTTON LOGIC
$syncHash.Button.Add_Click({

    $syncHash.Window.Dispatcher.Invoke(
        [action]{
            $syncHash.TextBox.AppendText("This is a test")
        }
    )
})

This is fairly basic in what it does. It just adds “This is a test” to the textbox. Say if I want the button to run a task and then update the textbox with the results, but the results took a long time to come, the form would freeze. This is because whatever command you run in the same runspace as the GUI, takes controls and stops the GUI being responsive.

So, what I’m going to do is ping google 5 times, get the average from all of those and then update the textbox without the GUI becoming unresponsive. To do this, I’m going to create a new runspace and add the code I want to run. You can see this below:

#BUTTON LOGIC
$syncHash.Button.Add_Click({
    #ASSIGNING HOST VARIABLE
    $syncHash.host = $Host
    #CREATING NEW RUNSPACE
    $pingrunspace = [runspacefactory]::CreateRunspace()
    $pingrunspace.ApartmentState = "STA"
    $pingrunspace.ThreadOptions = "ReuseThread"
    $pingrunspace.Open()
    #PUTTING THE SYNCHASH VARIABLE INSIDE THE NEW RUNSPACE
    $pingrunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)

    #THIS IS THE CODE THAT WILL BE EXECUTED IN THE NEW RUNSPACE
    $code = {

        #CONNECTION TO GOOGLE AND CALCULATING AVERAGE IN NEW RUNSPACE
        $connection = Test-Connection -ComputerName google.co.uk -Count 5
        $average = [math]::Round(($connection.responsetime | Measure-Object -Average).Average)
        #UPDATING THE TEXTBOX WITH CONNECTION AVERAGE IN NEW RUNSPACE
        $syncHash.Window.Dispatcher.Invoke(
            [action]{
                $syncHash.TextBox.AppendText($average)
            }
        )

    }
        
    #ADDING AND RUNNING THE CODE IN THE NEW RUNSPACE
    $PSInstance = [powershell]::Create().AddScript($code)
    $PSinstance.Runspace = $pingrunspace
    $job = $PSinstance.BeginInvoke()
    
})

This will run the code in a separate runspace to the GUI and allow you to interact with it whilst the commands complete in the background.

Just in case you want the entire this, this is what the whole file looks like 🙂

#CREATE HASHTABLE AND RUNSPACE FOR GUI
$syncHash = [hashtable]::Synchronized(@{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"         
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)      
#BUILD GUI AND ADD TO RUNSPACE CODE
$psCmd = [PowerShell]::Create().AddScript({   
    [xml]$xaml = @"
    <Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    Name="Window" Height="400" Width="600">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <Button Name="Button" Content="Press" Height="200" Width="580" Grid.Row="0" Grid.Column="0" />
        <TextBox Name="Textbox" Height="200" Width="580" Grid.Row="1" Grid.Column="0" />
    </Grid>
</Window>
"@
  
    #INTERPRET AND LOAD THE GUI
    $reader=(New-Object System.Xml.XmlNodeReader $xaml)
    $syncHash.Window=[Windows.Markup.XamlReader]::Load( $reader )

    #EXTRACT THE CONTROLS FROM THE GUI
    $syncHash.TextBox = $syncHash.window.FindName("Textbox")
    $syncHash.Button = $syncHash.Window.FindName("Button")

    #BUTTON LOGIC
    $syncHash.Button.Add_Click({

        $syncHash.host = $Host
        $pingrunspace = [runspacefactory]::CreateRunspace()
        $pingrunspace.ApartmentState = "STA"
        $pingrunspace.ThreadOptions = "ReuseThread"
        $pingrunspace.Open()
        $pingrunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)

        $code = {

            $connection = Test-Connection -ComputerName google.co.uk -Count 5
            $average = [math]::Round(($connection.responsetime | Measure-Object -Average).Average)
            $syncHash.Window.Dispatcher.Invoke(
                [action]{
                    $syncHash.TextBox.AppendText($average)
                }
            )

        }

        $PSInstance = [powershell]::Create().AddScript($code)
        $PSinstance.Runspace = $pingrunspace
        $job = $PSinstance.BeginInvoke()
    })


    #FINALISE AND CLOSE GUI RUNSPACE UPON EXITING
    $syncHash.Window.ShowDialog() | Out-Null
    $syncHash.Error = $Error
    $Runspace.Close()
    $Runspace.Dispose()
    
})
#LOAD RUNSPACE WITH GUI IN
$psCmd.Runspace = $newRunspace
$data = $psCmd.BeginInvoke()

Enjoy!

Responsive PowerShell WPF Form Introduction #1

Hooooly jebus chwist! This took a LONG time for me to get my head around and an even longer time to implement and get working (still breaking it every minute!). I used this website and this website to help me learn the basics.

Today, I’m going to show you how to create a responsive WPF from using PowerShell. This utilises runspaces and a synchronised hashta… never mind the technical stuff!

This is the code that I used:

#CREATE HASHTABLE AND RUNSPACE FOR GUI
$syncHash = [hashtable]::Synchronized(@{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"         
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)      
#BUILD GUI AND ADD TO RUNSPACE CODE
$psCmd = [PowerShell]::Create().AddScript({   
    [xml]$xaml = @"
    <Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    Name="Window" Height="400" Width="600">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <Button Name="Button" Content="Press" Height="200" Width="580" Grid.Row="0" Grid.Column="0" />
        <TextBox Name="Textbox" Height="200" Width="580" Grid.Row="1" Grid.Column="0" />
    </Grid>
</Window>
"@
  
    #INTERPRET AND LOAD THE GUI
    $reader=(New-Object System.Xml.XmlNodeReader $xaml)
    $syncHash.Window=[Windows.Markup.XamlReader]::Load( $reader )

    #EXTRACT THE CONTROLS FROM THE GUI
    $syncHash.TextBox = $syncHash.window.FindName("Textbox")
    $syncHash.Button = $syncHash.Window.FindName("Button")

    #FINALISE AND CLOSE GUI RUNSPACE UPON EXITING
    $syncHash.Window.ShowDialog() | Out-Null
    $syncHash.Error = $Error
    $Runspace.Close()
    $Runspace.Dispose()
    
})
#LOAD RUNSPACE WITH GUI IN
$psCmd.Runspace = $newRunspace
$data = $psCmd.BeginInvoke()

Using this, you can then use the same command prompt used to launch the script to change the form. E.g. to change the text in the textbox we would use:

$syncHash.Window.Dispatcher.Invoke(
    [action]{$syncHash.TextBox.Text = "Updated text here"}
)

In another post, I’ll show you how to update the textbox using a button on the same form. Exciting stuff, right?

Leave a comment if you have any questions or issues. Enjoy!

MAC Address Lookup API Using PowerShell

Meet macvendors.com! I’ve used this website quite a bit in the past and recently saw that they have an API. This means I can query MAC address vendors using PowerShell instead of loading the site every time.

So I quickly threw together a small test to see if this would work using Invoke-WebRequest. You can see this below:

$mac_example = "3C-07-71-75-BC-32"
Invoke-WebRequest -Uri "https://api.macvendors.com/$mac_example"

This returns the following information:

StatusCode        : 200
StatusDescription : OK
Content           : Sony Corporation
RawContent        : HTTP/1.1 200 OK
                    Connection: keep-alive
                    x-request-id: lhgjrrs7mf0desm40sifji9reoehi08b
                    Content-Length: 16
                    Cache-Control: max-age=0, private, must-revalidate
                    Content-Type: text/plain; charset=utf-8...
Forms             : {}
Headers           : {[Connection, keep-alive], [x-request-id, lhgjrrs7mf0desm40sifji9reoehi08b], [Content-Length, 16],
                    [Cache-Control, max-age=0, private, must-revalidate]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 16

This provides with a lot of useless information. All I really want is the content field which contains the manufacturer information. So what I’m going to do is wrap the Invoke-WebRequest in brackets and select the content field as shown below:

(Invoke-WebRequest -Uri "https://api.macvendors.com/$mac_example").content

Which simple returns “Sony Corporation”. Perfect. Enjoy!

LAPS WinForm 2

New and improved LAPS WinForm because the original one, found here, was kind of crap. It didn’t handle exceptions very well and I don’t think the group policy update worked at all after some further debugging.

I am please to present the new GUI for LAPS:

The best place to download this from would be my TechNet gallery

Enjoy!

Linux Directory Checking Script

Morning! Oh wait, it’s the afternoon…

Today, I finally got around to making a script that will run automatically on my network storage server (Raspberry Pi with a dinky USB hard drive) and check if the USB HDD is accessible.

This issue started a couple of weeks ago where I was getting weird IO errors on the USB disk about every 2 weeks. Instead of buying a new drive, creating a RAID array or anything else equally as intelligent and appropriate, I decided to just reboot my Raspberry Pi every time this happened. Now, I don’t want to do this manually every time so I finally created a script and added it to my cron jobs.

You can see the script I used below:

#!/bin/bash

if [ ! -d "path/to/check" ]; then
    #Directory is not found and HDD is not okay, do whatever is below
    uptime=$(uptime)
    currenttime=$(date)
    echo "Host rebooted at $currenttime. Uptime was$uptime" >> /path/to/output.txt
    sudo reboot
fi

My crontab job is running as root because the sudo reboot part was giving me a couple of issues. This is the entry in the root crontab:

@hourly /path/to/sh/file

Enjoy!

SharePoint Group Membership WinForm

This is a little WinForm I created that would output the group membership for a domain user or FBA (Forms-Based Authentication) user on SharePoint.

This is what the form looks like, it gives the option for a domain or FBA user and also checked if the user exists before trying to get the relevant information:

The form first checks if CredSSP is configured on your machine to delegate your credentials to the SharePoint server. The form then loads, waits for your input, validates your input and finally collects the group information for your input.

And finally, this is the code for the Winform. I’ve removed some details as they need to be filled in by you. Enjoy!

#CHECKING CREDSSP SETTINGS
if ((Get-Item  WSMan:\localhost\Client\Auth\CredSSP).value -eq $false){
    #CREDSSP NOT CONFIGURED, EXITING
    Write-Host @"
    
CredSSP is not configured!

Please open an elavated PowerShell prompt and run:

Enable-WSManCredSSP -Role client -DelegateComputer sandsharepointf

"@
    Exit
}else{}

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

#ICON FOR THE FORM
[string]$icon64=@"
#base64data
"@

#CONVERTING BASE 64 ICON INTO GRAPHIC
$iconstream = [System.IO.MemoryStream][System.Convert]::FromBase64String($icon64)
$iconbmp = [System.Drawing.Bitmap][System.Drawing.Image]::FromStream($iconstream)
$iconhandle = $iconbmp.GetHicon()
$icon = [System.Drawing.Icon]::FromHandle($iconhandle)

#FORM
$SharePoint_Membership_Form                 = New-Object system.Windows.Forms.Form
$SharePoint_Membership_Form.ClientSize      = '400,278'
$SharePoint_Membership_Form.text            = "SharePoint Membership"
$SharePoint_Membership_Form.TopMost         = $false
$SharePoint_Membership_Form.StartPosition   = "centerscreen"
$SharePoint_Membership_Form.Icon            = $icon
$SharePoint_Membership_Form.FormBorderStyle = "Fixed3D"

#USERNAME LABEL
$Username_Label                  = New-Object system.Windows.Forms.Label
$Username_Label.text             = "Enter a username:"
$Username_Label.AutoSize         = $true
$Username_Label.width            = 25
$Username_Label.height           = 10
$Username_Label.location         = New-Object System.Drawing.Point(146,12)

#USERNAME TEXTBOX
$Username_Textbox                = New-Object system.Windows.Forms.TextBox
$Username_Textbox.multiline      = $false
$Username_Textbox.width          = 175
$Username_Textbox.height         = 20
$Username_Textbox.location       = New-Object System.Drawing.Point(115,33)

#VARIABLE FOR KEYDOWN
$Username_Textbox_keydown = {}

#KEYDOWN ASSIGNED
$Username_Textbox_keydown = [System.Windows.Forms.KeyEventHandler]{
    if ($_.keycode -eq 'Enter'){
        $Search_Button.PerformClick()
    }
}

#REGISTER KEYDOWN HANDLER TO USERNAME TEXTBOX
$Username_Textbox.add_keydown($Username_Textbox_keydown)

#DOMAIN RADIO BUTTON
$Domain_User_RB                  = New-Object system.Windows.Forms.RadioButton
$Domain_User_RB.text             = "Domain User"
$Domain_User_RB.AutoSize         = $true
$Domain_User_RB.width            = 104
$Domain_User_RB.height           = 20
$Domain_User_RB.location         = New-Object System.Drawing.Point(120,64)
$Domain_User_RB.Checked          = $true

#SHAREPOINT FBA USER RADIO BUTTON
$FBA_User_RB                     = New-Object system.Windows.Forms.RadioButton
$FBA_User_RB.text                = "FBA User"
$FBA_User_RB.AutoSize            = $true
$FBA_User_RB.width               = 104
$FBA_User_RB.height              = 20
$FBA_User_RB.location            = New-Object System.Drawing.Point(215,64)

#SEARCH BUTTON
$Search_Button                  = New-Object system.Windows.Forms.Button
$Search_Button.text             = "Search"
$Search_Button.width            = 60
$Search_Button.height           = 30
$Search_Button.location         = New-Object System.Drawing.Point(171,89)

#SEPERATOR LINE
$Seperator_Label                 = New-Object system.Windows.Forms.Label
$Seperator_Label.text            = ""
$Seperator_Label.AutoSize        = $false
$Seperator_Label.BorderStyle     = "Fixed3D"
$Seperator_Label.width           = 390
$Seperator_Label.height          = 2
$Seperator_Label.location        = New-Object System.Drawing.Point(5,124)

#OUTPUT TEXTBOX
$Output_Textbox                 = New-Object System.Windows.Forms.TextBox
$Output_Textbox.Multiline       = $true
$Output_Textbox.Width           = 390
$Output_Textbox.Height          = 142
$Output_Textbox.Location        = New-Object System.Drawing.Point(5,131)
$Output_Textbox.ReadOnly        = $true
$Output_Textbox.ScrollBars      = "vertical"

#ADDING CONTROLS TO FORM
$SharePoint_Membership_Form.controls.AddRange(@($Domain_User_RB,$FBA_User_RB,$Seperator_Label,$Username_Label,$Username_Textbox,$Search_Button,$Output_Textbox))

$Search_Button.add_click({

    $Output_Textbox.Text = ""

    #DATE FOR OUTPUT
    $date = Get-Date    
    $username_value = $Username_Textbox.Text
    $Username_Prefix = $null
    $location = #base location

    #SETTING SEARCH VALUES BACK TO FALSE
    $Search_On_AD_User = $false
    $Search_On_FBA_User = $false

    #CHECKING IF USERNAME TEXTBOX IS EMPTY
    if ($Username_Textbox.Text.Length -le 0){
        #IF EMPTY, VARIABLE IS FALSE
        $Output_Textbox.AppendText("$date - $Username cannot be empty! `n")
        $Username_Not_Empty = $false
    }else{
        $Username_Not_Empty = $true
        $Output_Textbox.Text = ""
    }

    #RUNS IF DOMAIN USER RADIO BUTTON IS CHECKED
    if ($Domain_User_RB.Checked -and $Username_Not_Empty){
        try{
            $Output_Textbox.AppendText("$date - Searching for $username_value `n")
            Get-ADUser -Identity $username_value

            $Output_Textbox.AppendText("$date - Found user! `n")

            $Search_On_AD_User = $true
            $Search_On_FBA_User = $false

            $Username_Found = $true

        }catch{
            $Output_Textbox.AppendText("$date - Cannot find domain user `n")
            $Username_Found = $false
        }
    }

    #RUNS IF FBA USER RADIO BUTTON IS CHECKED
    if ($FBA_User_RB.Checked -and $Username_Not_Empty){
        
        $SPAdmin = "sharepoint_admin_user"
        $credential = New-Object System.Management.Automation.PSCredential $SPAdmin,  (Get-Content "$location\sharepoint_admin_user_encrypted_password.txt" | ConvertTo-SecureString )

        $sb = {
            $username = $args[0]
            Add-PSSnapin microsoft.sharepoint.PowerShell
            $user = Get-SPUser -Limit All -Web http://SHAREPOINTSERVER | 
                Where-Object {$_.loginname -like "i:0#.f|fbamembershipprovider|$username"}

            return $user
        }

        $Output_Textbox.AppendText("$date - Trying to find $username_value... `n")

        $invokeoutputfbasearch = Invoke-Command -ScriptBlock $sb -ComputerName SHAREPOINTSERVER -Authentication Credssp -Credential $credential -ArgumentList $username_value

        if ($invokeoutputfbasearch){
            #FOUND USER
            $Username_Found = $true
            $Search_On_FBA_User = $true
            $Search_On_AD_User = $false
            $Output_Textbox.AppendText("$date - Found FBA user!`n")
        }else{
            #NOT FOUND USER
            $Username_Found = $false
            $Output_Textbox.AppendText("$date - Cannot find FBA user `n")
        }
    }

    #ONLY RUNS IF BELOW CONDITIONS ARE MET
    if ($Username_Found -and $Username_Not_Empty){
        #ASSIGNING THE RIGHT USERNAME FORMAT
        if ($Search_On_AD_User){
            $Username_Prefix = "*|DOMAIN_NAME\"
        }else{
            $Username_Prefix = "i:0#.f|fbamembershipprovider|"
        }

        $SPAdmin = "sharepoint_admin_user"
        $credential = New-Object System.Management.Automation.PSCredential $SPAdmin,  (Get-Content "$location\sharepoint_admin_user_encrypted_password.txt" | ConvertTo-SecureString )

        $sb = { 
            $groups = $null
            $prefix = $args[0]
            $username = $args[1]
            Add-PSSnapin Microsoft.SharePoint.PowerShell
            $user = get-SPUser -limit all -web http://SHAREPOINTSERVER | 
                Where-Object { $_.loginname -like "$prefix$username" }
                $SPGroups = get-spsite -limit all | 
                    Select-Object -ExpandProperty rootweb | 
                    Select-Object -ExpandProperty siteusers | 
                    Where-Object { $user.userlogin -eq $_.loginname } | 
                    Select-Object -ExpandProperty groups | 
                    Select-Object -ExpandProperty name
            foreach ($i in $SPGroups){
                $groups = $groups + "     - $i `r`n"
            }
        return $groups
        }

        $Output_Textbox.AppendText("$date - Collecting group info on $username_value... `n")

        $InvokeOutputfinal = Invoke-Command -ScriptBlock $sb -ComputerName SHAREPOINTSERVER -Authentication Credssp -Credential $credential -ArgumentList $Username_Prefix,$username_value

        $Output_Textbox.AppendText("`n")
        $Output_Textbox.AppendText("$InvokeOutputfinal")

    }else{#THIS SERVES ONLY AS A TRAP TO STOP ANYTHING RUNNING
    }
})

#DISPLAYING FORM
[void]$SharePoint_Membership_Form.ShowDialog()