Link to home
Start Free TrialLog in
Avatar of dipersp
diperspFlag for United States of America

asked on

Text/combo box with type-ahead for list of directories

I need to create a vbscript or Powershell script to get input from a user.  I would normally just do a text/input box, but want to allow the user the option to pick an existing subdirectory OR manually type in a new one.  Reason for this is we don't want to have a misspelling and cause a duplication directory.  

So first up the program needs to read in a directory list, then interface with the text/combo box for type-ahead.  Drop-down could be utilized instead of type-ahead if it's easier.  Then allow the user to select the directory OR manually type in the box for a new directory.

Make sense?

Here's the problem - I have very limited knowledge of Powershell or VBS.  I KNOW them both, but have only done very basic scripting.

Doable?
Avatar of Jamie McKillop
Jamie McKillop
Flag of Canada image

Hello,

Yes, this is possible. For an example of this, see my ActiveSync admin tool here:

http://jamiemckillop.wordpress.com/2013/05/30/activesync-power-administrator-2-0-exchange-2010-support/

When you start typing in the email address field, it will start providing suggestions based on a directory lookup. The important parts of the code are the following lines on the combo box:

$EmailAddress.autocompletesource = "customsource"
$EmailAddress.autocompletemode = "suggest"
$EmailAddress.add_textchanged({EmailAddress_textchanged})

Open in new window


That causes the combo box to use autocomplete from a custom source and to call a function as text is typed into the box.

The function (below) then does a wildcard directory lookup on the text that has been typed to find partial matches in the directory and add them as suggestions to the drop-down.

function EmailAddress_textchanged
{
if ($DisableDynamic.checked -eq $false) {
	$emaillist = @()
	Get-QADUser -SizeLimit 0 -LdapFilter "(Name=$($EmailAddress.text)*)" | % {
		if ($_.mail -ne $null) {
			$emaillist += $_.mail
		}
	}
	$EmailAddress.AutoCompleteCustomSource.AddRange($emaillist)
}
}

Open in new window


As you can see, what you are looking to do is beyond basic powershell. Hopefully, you can use my example to create what you want. Let me know if you have any questions.

-JJ
Avatar of dipersp

ASKER

OK, so. . . I've never done a form/gui with Powershell.  I downloaded the Primalforms and made a simple text box.  It generated all the code and I've adjusted/mirrored what you have.  

So the form pops up, I get the single text box, and I start to type in it.  But it never autofills anything in the text box.  Just lets me keep typing.  Thoughts?

Thoughts?  Full code below.

#Generated Form Function
function GenerateForm {
########################################################################
# Code Generated By: SAPIEN Technologies PrimalForms (Community Edition) v1.0.10.0
# Generated On: 1/14/2014 5:31 PM
# Generated By: PDP
########################################################################

#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
$ClientNames = New-Object System.Windows.Forms.TextBox
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.

function ClientNames_textchanged
{
$clientlist = @()
get-childitem -path "d:\" | where-object{($_.PSIsContainer)} | where-object{$_.name -like "*$ClientNames.txt*"} | % {
    $clientlist += $_.name
  }
$ClientNames.AutoCompleteCustomSource.AddRange($clientlist)
}




$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
	$form1.WindowState = $InitialFormWindowState
}

#----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 262
$System_Drawing_Size.Width = 284
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.Name = "form1"
$form1.Text = "Primal Form"

$ClientNames.AutoCompleteMode = "suggest"
$ClientNames.AutoCompleteSource = "customsource"
$ClientNames.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 31
$System_Drawing_Point.Y = 60
$ClientNames.Location = $System_Drawing_Point
$ClientNames.Name = "ClientNames"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 100
$ClientNames.Size = $System_Drawing_Size
$ClientNames.TabIndex = 0
$ClientNames.add_TextChanged({ClientNames_textchanged})

$form1.Controls.Add($ClientNames)

#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

Open in new window

Add this block of code to the top of your script:

if ([threading.thread]::CurrentThread.GetApartmentState() -eq "MTA") {
   & $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe -sta $MyInvocation.ScriptName
   Exit
}

Open in new window


The script may exist right away after running it in the powershell windows. If that happens, just run it again without closing the powershell window.

-JJ
Avatar of dipersp

ASKER

No change.  It did exit just like you said and I ran it again.

As I'm typing in the textbox, it ever so slightly flashes (The textbox), so it's almost like it's doing something. . .
In this line: where-object{$_.name -like "*$ClientNames.txt*"}

.txt should be .text

-JJ
Avatar of dipersp

ASKER

Duh.  But still no dice.
I would test your function to see is it works by itself. Manually set the $ClientNames.text variable and pass it to the function then have it output $clientlist and make sure you get what you expect.

-JJ
Avatar of dipersp

ASKER

Yes, did that first.  It does work when I manually run it at the Powershell prompt.
ASKER CERTIFIED SOLUTION
Avatar of Jamie McKillop
Jamie McKillop
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of dipersp

ASKER

You da man!  

OK - now can you explain that last change/fix to me?

Also, what does the following block do?  I always have to start the file twice now to actually use it.

if ([threading.thread]::CurrentThread.GetApartmentState() -eq "MTA") {
   & $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe -sta $MyInvocation.ScriptName
   Exit
}

Open in new window

When you place a variable inside quotes, you sometime need to put the variable in the format $($variable) in order to escape it otherwise the code interprets your variable as a literal string.

This post explains that block of code:

http://thepip3r.blogspot.ca/2011/06/powershell-gui-errors-referencing-sta.html

-JJ
Avatar of dipersp

ASKER

OK, think it all makes sense.  So if I invoke PS in STA on the command line, I should be good. . .  Anyway, thanks a lot!  I may have other questions for you at some point!