Quantcast
Channel: OS|DC
Viewing all articles
Browse latest Browse all 64

PowerShell: Create Simple GUI without forms or WPF in a minute

$
0
0

Paraphrasing Bill Gates, I will say that laziness sometimes leads to great solution. Perhaps ‘great’ is a bit much for what we will be talking about here, but at least it’s unexpected, geeky and quite useful if you can accommodate with his constrains.

So, the goal here is to build very simple Graphical User interface (GUI) in a few minutes (seconds) without requiring forms or WPF knowledge and without GUI editors like Visual studio either. Everything is done by tricking the PowerShell cmdlet Show-command with specifically formatted function’s parameters.

But make no mistake, this is not the stuff to use if you planned to build a PowerShell application with a full GUI, hell NO!!! Correct use case is when in need a very simple GUI and have no time/resources at your fingers for a nice WPF frontend or moreover, when it’s just not worth the effort!

This solution push a step further what was introduced by Nicholas Getchell and was unintentionally “inceptioned” by my dear co-worker Damien Van Robaeys who told me that there was no need of visual studio to build interfaces (That’s the way he makes his tools!!)… which I tried… and failed… So, with no passion to learn WPF nor to install visual studio, I ended up with Show-command (Million thanks Nicholas)!


What can you Expect?

An (animated) picture is worth a thousand words, this is what I came up with:

As you can see, you can use controls like input box, tabs, check Box and combo box. Now that you’ve seen it, here is how it’s done (Link):

Function Install-WEBService
     {
         [CmdletBinding()]
         Param
         (   
             [Parameter(Position=0, Mandatory=$true, ParameterSetName='1-Settings')]
             [String]$User,
            
             [Parameter(Position=1,Mandatory=$true,ParameterSetName='1-Settings')]
             [String]$Password,
            
             [Parameter(ParameterSetName='1-Settings')]
             [ValidateSet("None", "NTLM/Kerberos")]
             [String]$Authentication = "None",
            
             [Parameter(ParameterSetName='1-Settings')]
             [Alias('Port')]
             [int]${Port    [Default is 8550]} = 8550,
            
             [Parameter(ParameterSetName='1-Settings')]
             [Alias('Url')]
             [String]${Url [Default is OSDInfo]} = "OSDInfo",
            
             [Parameter(ParameterSetName='1-Settings')]
             [ValidateSet("YES", "NO")]
             [Alias('SSL')]
             [String]${Use SSL  [Default is No]} = "NO",
            
             [Parameter(ParameterSetName='2-About')]
             [Switch]${`n`n`n                          Web Service Installer by `n`n                         Diagg/OSD-Couture.com`n`n`n`n`n              OS|DC - Quality Deployment since 1884}
         )
        
         $Port = ${Port    [Default is 8550]}
         $url = ${Url [Default is OSDInfo]}
         $SSL = ${Use SSL  [Default is No]}
        
         Write-Host "User: $User"
         Write-Host "Password: $Password"
         Write-Host "Authentication: $Authentication"
         Write-Host "Port: $Port"
         Write-Host "URL: $url"
         Write-Host "ssl: $ssl"
     }

cls
$RemapAliasTable = @{
         'Url [Default is OSDInfo]' = 'Url'
         'Port    [Default is 8550]' = 'Port'
         'Use SSL  [Default is No]' = 'SSL'    
     }

$Result = Show-Command Install-WEBService -NoCommonParameter -PassThru
If (($Result -like "*-user*") -and ($Result -like "*-password*"))
     {
         Foreach ($Item in $RemapAliasTable.GetEnumerator()){If ($Result -match [Regex]::Escape($item.name)){$Result = $Result -replace [Regex]::Escape($Item.Name), $Item.value}}
         Invoke-Expression $Result
     }
Else
     {Write-Host "Missing parameters, please retry!!"}

Surprisingly, there is no real code here, function’s parameters are the code that the show-command cmdlet will convert into controls. Each control can be used according to a few rules that we will explore here after.

From a processing perspective, the Show-command will only display the function’s parameters without doing any validation. Once the OK button is pushed, it will return the function name with the selected parameters in a string under the $Result variable.

Then we have the (so called) tricky part, where the hash table $RemapAliasTable is parsed in a Foreach loop to convert parameters with spaces in their names to their Alias equivalent (spaces are separators and will break everything when calling the function).

The $Result variable will transition from something like $Result = Install-WEBService -Password truc -User diagg -Authentication None -Port [Default is 8550] 8888 -Url [Default is OSDInfo] toto -Use SSL [Default is No] YES

To something like $Result = Install-WEBService -Password truc -User diagg -Authentication None -Port 8888 -Url toto -SSL YES

And as Show-Command does not execute anything, the $Result output is executed using the Invoke-Expression Cmdlet.  There no much!!!


Rule of thumb

Scientifically selected(?!?!!) and grouped, function’s parameters will produce different graphic elements:

Variables Name are transformed into labels

A string or numeric variable will produce an input box:


Elements grouped under the same ParameterSetName will be displayed in the same tab:


A switch variable will produce a check  box:


A validateSet parameter will produce a combo Box:


This was for the easy part as there are a few other rules that are… less friendly…

  • Mandatory parameters are listed in alphabetic order (position parameter have no effect!).
  • Mandatory parameters will be listed prior to non-mandatory parameters.
  • Mandatory parameters don’t have default value.
  • Mandatory parameters grey out the OK button until filled.
  • Parameters validation is not performed during show time.
  • Default value are not displayed.


Recommended practices:

As we are bending show-command in a way it was not designed for, there are a few things that could be useful to do or to avoid if you don’t want to build something that is too far from user interface standards or something that is just unusable. Note that some recommendation goes in contraction with the interface presented above. Consider it as proof of concept, not as something you should do.


Don’t use tab, they will hardly suit your needs and may break your function!!!

In the GUI world, tabs are used to add options to the main parameters, in function, ParameterSetName (the parameter that produce tab) is used to allow different set of inputs to be used by the function which is not the same. Ex: The Get-service cmdlet can be called with services display name, name or nothing. Each input excludes the two other and this the the way ParameterSetName is designed, something that you probably don’t want when you think about options! Mutually exclusive sets also have problematic side consequences: parameters filled in other tabs won't be transmitted!


Make extensive use of validate set

Use this as much as you can. This is the easiest you can do to pre-stage your UI with values. This is also the only way to validate your parameters within Show-command.


Relax on variable name, we have you covered

As you’ve seen before, variables are used as labels and are displayed alphabetically with higher priority if they are mandatory. This always leads to unexpected results. So, to keep things ordered your way, you can use “relaxed” variable naming like ${_0_User} (yes, this is a valid PowerShell variable). The goal is of course, to keep your interface as user friendly as possible.

And while we are at it, you can even do stupid things like carriage return or multiple space (Ex: ${`n`n`n Web Service Installer by `n`n Diagg/OSD-Couture.com`n`n`n`n`n}) .This last one is probably at bit too much but it works!…

Two important things to notice about variable: Don’t use – character as Powershell interpreter will think it’s a new parameter. (There is also some magic if you use _ character, but I let you try and see by yourself!). As I’ve told before the space character behave similarly and must be replaced by function’s Alias .

To keep variables easy to use after they’ve been filled, you’d better change their name back to something simpler to use, also because Alias parameter does not cast out his own variable when used! Ex: $Port = ${Port [Default is 8550]}

Hope you’ll find something useful to do with it. See you!!


Viewing all articles
Browse latest Browse all 64

Trending Articles