PowerShell In GUI Blog

PowerShell GUI Box Just In A Few Clicks

Preventing Problems In Your PowerShell Code

leave a comment »

Last month a wave of using the Set-StrictMode commandlet flooded the PowerShell Internet landscape.

In receiving occasionally a tweet from powershell.com about using it with the -Version Latest parameter, I re-wrote several my old modules, three plus lines each, to meet the requirement. Needless to say that it helped to fix some deep mistakes in code, causing to reduction of code execution. These modules collect information, so that their execution don’t stop, but the data collected are not complete.

The topmost problem was the use of CSharp-like variable checks:

if ($Variable -ne $null){

Owing to a habit of using such a style, I left intact these checks, only outermost try-catch statements were added:

try{$null = $Variable;
if ($Variable -ne $null){

}}catch{}

where catch instruction empty or contains the error-handling function, just depending on a situation. Especialy, if what is meant to be $Variable is something like $Variable.Property.

Bringing the first story to an end, I need to say that my style of error-handling is formed mostly on recommendations given in John Robbins’s book about .NET debugging, the second edition if I recall it right. He insisted on testing return values and input parameters rather than on generating exceptions, so that I picked up this style somewhere in this millennium.

The example above is typical of such an approach: try statement is used as a protection level 1 from error thrown by Set-StrictMode, at the same time, the if statement defends the furthermost code from a useless value of a variable, forming level 2 of protection. In common, it works well, but weights heavy.

Not so much time went out since I finished tayloring mycode to support the Set-StrictMode cmdlet, here came a new issue I must investigate: http://www.windowsitpro.com/blogs/powershell-with-a-purpose/entryid/76307/is-there-an-option-explicit-in-powershell

Don warned on scopes. Personally, someday I had a problem like:

for($i = 0; $i -lt 10; $i++)
{
    #some code
    for($i = 0; $i -lt 10; $i++)
    {
        #some code
    }
}

In this example, the index variable omits several states as a result of being increment in the inner cycle:

for($i = 0; $i -lt 10; $i++)
{
    Write-Host $i;
    for($i = 0; $i -lt 10; $i++)
    {
        Write-Host $i;
    }
}

0

0

1

2

3

4

5

6

7

8

9

The following sample code does the same:

for($private:i = 0; $private:i -lt 10; $private:i++)
{
    Write-Host $private:i;
    for($private:i = 0; $private:i -lt 10; $private:i++)
    {
        Write-Host $private:i;
    }
}

To heal the situation, you need use as many unique names of variables as you can afford. I suppose, you might have tens of cycles in your code. The following example is that you need to cure the preceding one:

for($private:i = 0; $private:i -lt 10; $private:i++)
{
    Write-Host $private:i;
    for($private:i2 = 0; $private:i2 -lt 10; $private:i2++)
    {
        Write-Host $private:i2;
    }
}

There may be offered a dubious solution, that some people used in VBScript programming: to declare ALL the script variables at a begin of every script/module file.

The argument that there is a great memory consumption is not serious due to a usual great memory consumption of many PowerShell scripts callingmodules and gathering some data.

Following the previously mentioned, the protected code is something like:

[int]$private:i = 0;
[int]$private:i2 = 0;
#
#amount of code
#
for($private:i = 0; $private:i -lt 10; $private:i++)
{
    Write-Host $private:i;
    for($private:i2 = 0; $private:i2 -lt 10; $private:i2++)
    {
        Write-Host $private:i2;
    }
}

Along with this ‘scope problem’, there’s another scope problem, namely ’embedded variable problem’. Notice, that variables $_, $Error and several other might contain various values at the execution time.

I saw the code where these variables worked differently on a module load and in time module functions are called. This was because of using Import-Module with the -Force parameter. Global value of $_ can be easily spoilt, so can be spoilt $script:_, but this is observed not so frequently.

The last example of today’s article demonstrates how we can spoil the $global:_ variable. It’s supposed that you have a couple of module *.psm1 files in paths stored in the $PSMOdulePath variable. If you does, let’s see how values of $global:_ and $script:_ are changed:

cls
[int]$counter = 0;
$env:PSModulePath.Split(";") |  %{Get-ChildItem -Path $_ -Include *.psm1 -Recurse | %{Write-Host '1' $_;
        $counter++;
        if ($counter -eq 1)
        {

$module = "${env:temp}\test.psm1"
@'
function Out-Items
{    param([string]$Comment)
    [string]$private:regPath = `
        'Registry::HKCU\Keyboard Layout';
    Get-ChildItem $private:regPath | `
        Select-Object -First 1 | `
        %{Write-Host 'Registry' $Comment '$_ :' $_;
          Write-Host 'Registry' $Comment '$private:_ :' $private:_;
          Write-Host 'Registry' $Comment '$local:_ :' $local:_;
          Write-Host 'Registry' $Comment '$script:_ :' $script:_;
          Write-Host 'Registry' $Comment '$global:_ :' $global:_;};
}
Out-Items 'on loading the module';
Export-ModuleMember -Function Out-Items
'@ > $module

Import-Module $module -Force;            

        }
        Write-Host '2' $_;
        }}

Out-Items "called from the console";

The salvation is in using bracketing with {}.GetNewclosure() method as shown below:

cls
[int]$counter = 0;
$env:PSModulePath.Split(";") |  %{Get-ChildItem -Path $_ -Include *.psm1 -Recurse | %{Write-Host '1' $_;
        $counter++;
        if ($counter -eq 1)
        {

$module = "${env:temp}\test.psm1"
@'
function Out-Items
{    param([string]$Comment)
    [string]$private:regPath = `
        'Registry::HKCU\Keyboard Layout';
    Get-ChildItem $private:regPath | `
        Select-Object -First 1 | `
        %{Write-Host 'Registry' $Comment '$_ :' $_;
          Write-Host 'Registry' $Comment '$private:_ :' $private:_;
          Write-Host 'Registry' $Comment '$local:_ :' $local:_;
          Write-Host 'Registry' $Comment '$script:_ :' $script:_;
          Write-Host 'Registry' $Comment '$global:_ :' $global:_;}.GetNewclosure();
}
Out-Items 'on loading the module';
Export-ModuleMember -Function Out-Items
'@ > $module

Import-Module $module -Force;            

        }
        Write-Host '2' $_;
        }}

Out-Items "called from the console";


Written by Alexander Petrovskiy

April 13, 2011 at 5:17 pm

Source Control, PoshCode or Cloud?

leave a comment »

How do you individual scripters store your scripts at a time they are not finished?

For companies and groups of scripters, undoubtedly, source control systems available across the Internet is the best choice. In case you need to obtain a specific information like who changed particular pieces of the code or have date-time labels set automatically, nobody argues that these systems do it well. But, from the point of view of a script-writing individual, this way requires extra preparations, including source control client being set across the hosts one uses to run and tune a script, sometimes firewall settings should be taylored to allow access to.

When scripts are released, there is no hesitation that global storages like SourceForge, CodePlex or PoshCode are the reasonable choice to share your code. Beforehand their upload there, the question on where do I save a draft is not answered. Maybe, with an exception for portals providing both publishing facilities and source controls ones. With aforementioned restrictions.

Alternatively, geeks might use flash memory, since no one commutes or moves from place to place without a mobile, some media player or even storage embedded in almost anything similarly to represented here http://goo.gl/MmOWD .

Recently, I found one more possibility to get access to my drafts across the Internet. No, this is not my mailbox (though it’s also in use for these purposes). It’s not a box.net, a plug-in I use for this WordPress blog, too. It’s Amazon CloudDrive.

If an ad-blocking system in your browser hasn’t cut off the tail fo this post, I’m glad to drop a couple of words about this free filebox. They give us 5 gigabytes of place gratuitously, we are permitted to upload files as to pre-created folders as well to folders of our choice.

Image

In the picture above, my new personal dropbox is shown. As can be seen, I created the folders structure /Projects/PS for my draft scripts. It will be filling as I change any of my scripts, at least as an additional protected storage in case of emergency like hard drive crash.

If one bought an mp3 album, the place it took are not substituted from yours 5GB. Moreover, you obtain twenty gigabytes on everyday buying only one mp3 album, details of the bargain explained here http://goo.gl/2F8YE .

Not surprisingly, that you now can use this storage for listening to files you bought at the Amazon’s cornershop, by using Cloudplayer. However, if you are an audiobooks consumer like me, not a musician, there is no solution solving the problem how to use the CloudPlayer for enjoying books.

Anyway, this is a perfect storage for quotidian use, even before ou have a plugin to put your files there and back to you directly from Powershell. Has anybody written a sample yet that can be rewritten as a module intended for handling data is this storage?

Written by Alexander Petrovskiy

April 8, 2011 at 7:24 am

Posted in Cloud, CloudDrive, Powershell

Tagged with , ,

WordPress Celebrates The Fools’ Day

leave a comment »

Today our beloved WordPress provides an amazing gift for us bloggers, the extra hits to our blogs!

Image

On the other hand, you dear visitors are given absolutely freely with the tenfold increased opportunity to read, hit and click blogs! Good luck and don’t be fool today! 🙂

Written by Alexander Petrovskiy

April 1, 2011 at 5:06 pm

Posted in WordPress

ObjectBrowser has migrated to Set-StrictMode successfully

leave a comment »

Today, as I sincerely hope, I fixed the last but major bug stemmed from moving to the use of the Set-StrictMode statement. This bug prevented ObjectBrowser GUI from displaying properties, events and fields of classes. A major one, need to admit.

As a result, list of signatures of methods became a simple list of method names, so that all clas members now can be sorted by name, member type (i.e. property, method, etc), and a return value or property, saying about methods and fields.

Also, types of event handlers are shown after this fix.

To conclude, you might now instead of typing something like

[System.Windows.Forms.Form]$frm = 
    New-Object System.Windows.Forms.Form;
#never run it by Ctrl+F7 
#and never expand 
#the $frm variable in the Variables frame

simply navigate to the System.Windows.Forms.dll assembly, through the System.Windows.Forms namespace, after that click on the Form class and get the full list of its members.

Image

Written by Alexander Petrovskiy

March 30, 2011 at 6:55 pm

Which Icons Are Shipped With Object Browser?

leave a comment »

Actually, what is the easiest way to display icons? Create a control like ListView? Maybe. Let’s create a handful of windows, just to observe how short the code might be.

First, import both modules, SuiteCore and ObjectBrowser (here and thereafter the PSDevStudioLite modules set is in use).

After that you are able to use the function set shipped with the package. The following simple code creates windows, which in turn demostrate icons.

cls
function createWindows
{
    for($private:i = 0; $private:i -lt $imagesList.Count; $private:i++)
    {
        $tw2 = New-SEToolWindow -Control (([System.Windows.Forms.ListBox]$lb = New-Object System.Windows.Forms.ListBox) | %{$lb;}) `
            -TitleBarText ("aaa" + $private:i) `
            -WindowName ("aaaaa" + $private:i) `
            -Image $imagesList[$imagesList.Keys[$private:i]] `
            -Visible $false -State TabbedDocument;
        Write-Host $private:i $imagesList.Keys[$private:i]
        $se.ToolWindows[("aaaaa" + $private:i)].Visible = $true;
    }
}

createWindows;

In the GUI you might easily see all of them by clicking a triangle, allowing you to make a list of all open documents:

Image

To clean up the document list is also simply, even somewhat simpler that to fill up:

function removeWindows
{
for($private:i = 0; $private:i -lt $imagesList.Count; $private:i++)
{
Remove-SEToolWindow -WindowName ("aaaaa" + $private:i);
}
}

removeWindows;

 

Requirements: PSDevStudioLite.SuiteCore 1.0.0.4 Beta and higher, PSDevStudioLite.ObjetBrowser 1.0.0.4 Beta ang higher.

http://www.box.net/shared/ot56ct7ngl

Note: all above are never be supported by quest, wasn’t and won’t be.

OB 1.0.0.3

leave a comment »

Object Browser 1.0.0.3 is uploaded to the link http://www.box.net/shared/ot56ct7ngl

This version comprises of two small improvements. The first one is a moving to be used in Strict mode. The second, and resulting the first one, is an improvement in showing private members.

Written by Alexander Petrovskiy

March 21, 2011 at 7:41 pm

OB 1.0.0.2

leave a comment »

As I languidly tested what was released recently as ObjectBrowser 1.0.0.1 July, 12th 2010, I remembered a couple of bugx I always wanted to fix. Today’s 1.0.0.2 shipped with

– search by name

– PleaseWait window

both fixed. As usual, the direct link is the same: ObjectBrowser

Written by Alexander Petrovskiy

March 18, 2011 at 7:49 pm

Direct links also came

leave a comment »

To make downloading as simply as possible, I also give you, who need samples that can be opened in your Powershell IDE, the direct links to the files published since the beginning of this blog.

HowToDealWithAListViewControl.zip described here How to deal with a ListView control

HowToDealWithRoutedEventParameterInWPK.zip illustrating How to deal with -RoutedEvent parameter in WPK

QADinGUI.zip relating to both Using Quest cmdlets from .NET. The complete walkthrough and Using Quest cmdlets from .NET. The complete walkthrough. Part 2

HowToDealWithAComboBoxControl.zip referring to How to deal with a ComboBox control

ObjectBrowser_20100712.zip requested here I’m interested in seeing an Object Explorer…

Hope, that’s all of the mentioned in this blog, otherwise don’t hesitate to write comments to this post asking to add links to something forgotten.

Written by Alexander Petrovskiy

March 15, 2011 at 6:47 pm

Posted in Powershell

Tagged with

For Those Who Wanted to Download Code Samples

leave a comment »

Recently, I’ve been requested to put out a code sample. This blog is meant as dead for almost a year, but I visit its dashboard on a  monthly basis just by a habit.

To fulfill the wish of the requester, I visited http://www.box.net since I almost forgot how to use a file box that is the only way I knew last year to share files on a WordPress blog. To my utter amusement, this blog counting four thousand visits and the most of them are counted after I wrote the last post, this blog has been read but not used as a download place.

The box statistics shows that files weren’t downloaded by anybody except me:

Image

Actually, I’m surprised if people copy/paste code instead of using code samples. Meanwhile, the download is simple, even despite being tricked on the first use, and the steps you need perform as follows:

1. Navigate your mouse’s cursor to the rigth until you find the gray box:

Image

2. Using the triangle arrows at the top and/or the bottom of the box, you may opt the sample you are interested in.

3. Click on the sample chosen. The message appears as shown below:

Image

4. As I may suppose your choise is the Download button. However, the first try is not always successful:

Image

At the same time, the standard Windows File Save dialog appears. Choose the path you want to save a sample and save the sample. If your download was successful, you’ll see the positively-grey message like this:

Image

Otherwise, the message ‘Now downloading…’ is shown endlessly. If so, just close it by clicking into cross at the upper-right corner to close the message and do the same sequence of actions. The second time always finishes with the sample on the your hard drive.

All the steps described above are proceeded in the Firefox 4.0 Beta 12 instance that is set by default and no doubts that you may download samples instead of copying the code from pages.

Written by Alexander Petrovskiy

March 12, 2011 at 7:44 am

Posted in WordPress

Tagged with

How to deal with a ComboBox control

with 6 comments

There is a very simple, but very useful control. It may

– be filled dynamically and manually

– accept user input (to disable user input is also possibly)

– pass its data to another control by user’s choice.

Well, let’s list what we are going to do with a combobox today:

1) accept value from a single textbox (by clicking a button)

2) accept values from multiple textboxes (from two of them by clicking a button)

3) accept user input and add it to the list (and discuss how to disable user input)

4) clear the list

5) use a value of user’s choise to set a value of one another control (the caption of the form)

6) Intellisense on user input

7) sorting items

If it’s enough, now turn to coding. Traditionally, the code bundle is attached in the box at right and it’s named, not surprisingly, HowToDealWithAComboBoxControl.zip.

The first our topic is how to accept user input. The following lines of code are taken from the $handler_button1_Click eventhandler:

    $comboBox1.Items.Add($textBox1.Text);
    $comboBox1.Items.AddRange(($textBox1.Text, $textBox2.Text));
    $comboBox1.Items.Add($comboBox1.Text);

In all three cases, data, usually of string type, is added by using such methods as Add(item) or AddRange(array of items). As can be seen, both methods are very easy to use.

Next, how we can prevent typing into a combobox? The answer is to set the DropDownStyle property:

$comboBox1.DropDownStyle =
    [System.Windows.Forms.ComboBoxStyle]::DropDownList;
   

After that, how to clean up our combobox?

$comboBox1.Items.Clear();
   
Next, how to grab a value from inside the user input?

$form1.Text = $comboBox1.Text;

How to sort data?

$comboBox1.Sorted = $true;

At last, how to use Intellisense? Please note, the DropDownStyle property should be set to System.Windows.Forms.ComboBoxStyle]::DropDown.

$comboBox1.AutoCompleteCustomSource.Add("System.Windows.Forms");
$comboBox1.AutoCompleteCustomSource.AddRange(("System.Data", "Microsoft"));
$comboBox1.AutoCompleteMode =
    [System.Windows.Forms.AutoCompleteMode]::SuggestAppend;
$comboBox1.AutoCompleteSource =
    [System.Windows.Forms.AutoCompleteSource]::CustomSource;

To test the Intellisense that is tuned above, type m or s in the combobox.

The whole sample is below:

#Generated Form Function
function GenerateForm {
########################################################################
# Code Generated By: SAPIEN Technologies PrimalForms (Community Edition) v1.0.8.0
# Generated On: 21.07.2010 1:32
# Generated By: Administrator
########################################################################

#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion

#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$button1 = New-Object System.Windows.Forms.Button
$button2 = New-Object System.Windows.Forms.Button
$textBox2 = New-Object System.Windows.Forms.TextBox
$textBox1 = New-Object System.Windows.Forms.TextBox
$comboBox1 = New-Object System.Windows.Forms.ComboBox
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
    #region $handler_comboBox1_SelectedIndexChanged
$handler_comboBox1_SelectedIndexChanged=
{
#TODO: Place custom script here
    try{
    if ($comboBox1.Text.Length -gt 0)
    {
        $form1.Text = $comboBox1.Text;
    }
    }catch{} #in case no items are available
}
    #endregion $handler_comboBox1_SelectedIndexChanged
    #region $handler_button1_Click
$handler_button1_Click=
{
#TODO: Place custom script here
    try{
    #How to add one item
    #$textBox1.Text
    if ($textBox1.Text.Length -gt 0 -and `
        $textBox2.Text.Length -eq 0)
    {
        $comboBox1.Items.Add($textBox1.Text);
        Write-Host "Added " $textBox1.Text "from `$textBox1";
    }
    #$textBox2.Text
    elseif ($textBox1.Text.Length -eq 0 -and `
        $textBox2.Text.Length -gt 0)
    {
        $comboBox1.Items.Add($textBox2.Text);
        Write-Host "Added " $textBox2.Text "from `$textBox2";
    }
    #$textBox1.Text and $textBox2.Text
    elseif ($textBox1.Text.Length -gt 0 -and `
        $textBox2.Text.Length -gt 0)
    {
        $comboBox1.Items.AddRange(($textBox1.Text, $textBox2.Text));
        Write-Host "Added " $textBox1.Text "from `$textBox1";
        Write-Host "Added " $textBox2.Text "from `$textBox2";
    }
    else
    {
        #Nothing to add
        #$textBox1.Text.Length -eq 0
        #$textBox2.Text.Length -eq 0
    }
    #At last, if the user typed something
    if ($comboBox1.Text.Length -gt 0)
    {
        $comboBox1.Items.Add($comboBox1.Text);
        Write-Host "Added " $comboBox1.Text "from `$comboBox1";
    }
    }catch{} #for example, no data in the both textboxes
}
    #endregion $handler_button1_Click
    #region $handler_button2_Click
$handler_button2_Click=
{
#TODO: Place custom script here
    try{
    #Clean up the combo box
    $comboBox1.Items.Clear();
    $comboBox1.Text = "";
    }catch{}
}
    #endregion $handler_button2_Click
$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
    $form1.WindowState = $InitialFormWindowState
}

#----------------------------------------------
#region Generated Form Code
    #region $form1
$form1.Text = "Primal Form"
$form1.Name = "form1"
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 282
$System_Drawing_Size.Height = 220
$form1.ClientSize = $System_Drawing_Size
    #endregion $form1
    #region $button1
$button1.TabIndex = 3
$button1.Name = "button1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 70
$System_Drawing_Size.Height = 30
$button1.Size = $System_Drawing_Size
$button1.UseVisualStyleBackColor = $True
$button1.Text = "button1"
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 195
$System_Drawing_Point.Y = 160
$button1.Location = $System_Drawing_Point
$button1.DataBindings.DefaultDataSourceUpdateMode = 0
$button1.add_Click($handler_button1_Click)
$form1.Controls.Add($button1)
    #endregion $button1
    #region $button2
$button2.TabIndex = 4
$button2.Name = "button2"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 70
$System_Drawing_Size.Height = 30
$button2.Size = $System_Drawing_Size
$button2.UseVisualStyleBackColor = $True
$button2.Text = "button2"
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 15
$System_Drawing_Point.Y = 160
$button2.Location = $System_Drawing_Point
$button2.DataBindings.DefaultDataSourceUpdateMode = 0
$button2.add_Click($handler_button2_Click)
$form1.Controls.Add($button2)
    #endregion $button2
    #region $textBox1
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 250
$System_Drawing_Size.Height = 20
$textBox1.Size = $System_Drawing_Size
$textBox1.DataBindings.DefaultDataSourceUpdateMode = 0
$textBox1.Name = "textBox1"
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 15
$System_Drawing_Point.Y = 70
$textBox1.Location = $System_Drawing_Point
$textBox1.TabIndex = 1
$form1.Controls.Add($textBox1)
    #endregion $textBox1
    #region $textBox2
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 250
$System_Drawing_Size.Height = 20
$textBox2.Size = $System_Drawing_Size
$textBox2.DataBindings.DefaultDataSourceUpdateMode = 0
$textBox2.Name = "textBox2"
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 15
$System_Drawing_Point.Y = 120
$textBox2.Location = $System_Drawing_Point
$textBox2.TabIndex = 2
$form1.Controls.Add($textBox2)
    #endregion $textBox2
    #region $comboBox1
$comboBox1.FormattingEnabled = $True
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 250
$System_Drawing_Size.Height = 21
$comboBox1.Size = $System_Drawing_Size
$comboBox1.DataBindings.DefaultDataSourceUpdateMode = 0
$comboBox1.Name = "comboBox1"
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 15
$System_Drawing_Point.Y = 20
$comboBox1.Location = $System_Drawing_Point
$comboBox1.TabIndex = 0
$comboBox1.add_SelectedIndexChanged($handler_comboBox1_SelectedIndexChanged)

$comboBox1.DropDownStyle =
    [System.Windows.Forms.ComboBoxStyle]::DropDown;
$comboBox1.Sorted = $true;

$comboBox1.AutoCompleteCustomSource.Add("System.Windows.Forms");
$comboBox1.AutoCompleteCustomSource.AddRange(("System.Data", "Microsoft"));
$comboBox1.AutoCompleteMode =
    [System.Windows.Forms.AutoCompleteMode]::SuggestAppend;
$comboBox1.AutoCompleteSource =
    [System.Windows.Forms.AutoCompleteSource]::CustomSource;

$form1.Controls.Add($comboBox1)
    #endregion $comboBox1
#endregion Generated Form Code

#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null

} #End Function

#Call the Function
GenerateForm
Design a site like this with WordPress.com
Get started