1

Last time I ran this script was 2 years ago, and I thought maybe I'm not transferring $userInput back to main program, but even the function doesn't read $userInput.

How to troubleshoot?

function getValues($formTitle, $textTitle){


    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 


    $objForm = New-Object System.Windows.Forms.Form
    $objForm.Text = $formTitle
    $objForm.Size = New-Object System.Drawing.Size(300,200)
    $objForm.StartPosition = "CenterScreen"

    $objForm.KeyPreview = $True
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter") {$x=$objTextBox.Text;$objForm.Close()}})
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") {$objForm.Close()}})

    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Size(75,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = "OK"
    $OKButton.Add_Click({$userInput=$objTextBox.Text;$objForm.Close()})
    $objForm.Controls.Add($OKButton)

    $CANCELButton = New-Object System.Windows.Forms.Button
    $CANCELButton.Location = New-Object System.Drawing.Size(150,120)
    $CANCELButton.Size = New-Object System.Drawing.Size(75,23)
    $CANCELButton.Text = "CANCEL"
    $CANCELButton.Add_Click({$objForm.Close()})
    $objForm.Controls.Add($CANCELButton)

    $objLabel = New-Object System.Windows.Forms.Label
    $objLabel.Location = New-Object System.Drawing.Size(10,20)
    $objLabel.Size = New-Object System.Drawing.Size(280,30)
    $objLabel.Text = $textTitle
    $objForm.Controls.Add($objLabel)

    $objTextBox = New-Object System.Windows.Forms.TextBox
    $objTextBox.Location = New-Object System.Drawing.Size(10,50)
    $objTextBox.Size = New-Object System.Drawing.Size(260,20)
    $objForm.Controls.Add($objTextBox)

    $objForm.Topmost = $True

    $objForm.Add_Shown({$objForm.Activate()})

    [void] $objForm.ShowDialog()

    write-host user Input is $userInput
    return $userInput


}


$schema = getValues "Database Schema" "Enter database schema"
$db_IP = getValues "Database Server" "Enter IP address where database is located"
$init_cat = getValues "Database Name" "Enter database name "
$userID = getValues "Database Administrator Username" "Enter username of database administrator"

Output is

user Input is
user Input is
user Input is
user Input is

UPDATE

When I try code from https://technet.microsoft.com/en-us/library/ff730941.aspx and add write-host $x, there is no output

PowerShell version 4.0

2
  • Try Write-Host "User input is $userInput" Commented May 21, 2015 at 17:05
  • @Erti-ChrisEelmaa No luck. And worse part is, I am trying code from technet.microsoft.com/en-us/library/ff730941.aspx and when I add write-host $x, nothing is output Commented May 21, 2015 at 17:08

2 Answers 2

3

Last time I ran this script was 2 years ago

As of PowerShell version 3.0, the scope of the delegate invoked by an event handler such as

$OKButton.Add_Click({$userInput=$objTextBox.Text;$objForm.Close()})

is distinct from the containing script, meaning that when you assign something to $userInput inside the Add_Click scriptblock, you're actually assigning something to a variable that is local to that scriptblock.

The fix is to explicitly state a parent-scope, like this:

$OKButton.Add_Click({$Script:userInput=$objTextBox.Text;$objForm.Close()})

It's the same behavior that causes the TechNet example to not run correctly in PowerShell 4.0 - unless you substitute all inline mentions of $x with $Script:x or $Global:x

You can read more about the dynamic scoping model in PowerShell (and how variables initialized in a child scope may end up hiding variables sharing their name in a parent scope) in the about_Scopes helpfile:

Get-Help about_Scopes -Full
Sign up to request clarification or add additional context in comments.

1 Comment

Yes. I believe this change in behavior is actually a "fix", and that the authors of the original WinForm snippet in TechNet magazine may have been a little too excited about their cool working example to check whether they were abusing something in PowerShell 1.0
1

I've never done anything with forms before, but making the $userInput assignment to $objTextBox.Text after the ShowDialog() worked for me:

[void] $objForm.ShowDialog()
$userInput = $objTextBox.Text
write-host user Input is $userInput

5 Comments

It works, but I'm wondering, why didn't previous code work. Even script on MS's official website is not working???
My educated guess here is that something has changed since Powershell 1.0 that broke their sample script.
@TonyHinkle yup, he's been "scoped" ;)
@MathiasR.Jessen Thanks for taking the time to give us the scoop on the scope. I suspected something like that, but I don't know Powershell well enough to know how to use the $Script:variable trick. I've used globals before, but that's a new one I learned today.
My pleasure :) I think the most "correct" way would be to access the direct parent scope from the event delegate, like: Set-Variable -Name userInput -Scope 1 -Value $objTextBox.Text, but it becomes unreadable really fast. I think the Script scope is a sensible boundary for what OP describes

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.