So, it looks like you’re trying to store the output of a scriptblock inside an .Add_Click() event into the $selection variable (line 23, 41), but this doesn’t really work in this way. One thing you should be aware of is that when you implement a scriptblock like this it executes as a child of the parent script, which means that you need to deal with scopes. Also, the attempt to assign to a variable on those lines is what’s preventing the dialog from closing.
Instead, what you can do is assign the output value that you want to the variable inside the scriptblock, like this:
#add assemblies
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
#define the form
$form = New-Object System.Windows.Forms.Form
$form.Text = 'One or Another?'
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'
#define the One button
$OneButton = New-Object System.Windows.Forms.Button
$OneButton.Location = New-Object System.Drawing.Point(75,120)
$OneButton.Size = New-Object System.Drawing.Size(75,23)
$OneButton.Text = 'One'
$OneButton.Add_Click({
New-Variable -Name selection -Value $($OneButton.Text) -Scope Script -Force
$form.Close()
})
#define the Another button
$AnotherButton = New-Object System.Windows.Forms.Button
$AnotherButton.Location = New-Object System.Drawing.Point(150,120)
$AnotherButton.Size = New-Object System.Drawing.Size(75,23)
$AnotherButton.Text = 'Another'
$AnotherButton.Add_Click({
New-Variable -Name selection -Value $($AnotherButton.Text) -Scope Script -Force
$form.Close()
})
#add the buttons to the form
$form.Controls.Add($OneButton)
$form.Controls.Add($AnotherButton)
#display the form
$form.ShowDialog()
#display the result
"Button $selection was pressed"
Note the use of -Scope Script when the selection variable is defined (lines 18, 29 above) - this assures that the variable will be available to the parent script (otherwise the variable will be set only inside the scriptblock and then destroyed when the scriptblock finishes).
Also note that the buttons still behave as they’re designed to within the normal functions of the Form Class. Specifically, the buttons still produce a DialogResult when clicked because that’s how System.Windows.Forms Buttons are designed to work. The default value is “None”, but it can be set to any of these values. The point is, you are adding an extra feature to the button click (setting the value of a variable) but you aren’t replacing the normal behavior of the button.
You should also be aware that PowerShell is really .NET under the hood - all PowerShell cmdlets are just implementations of .NET classes (hence the term cmdlet rather than command). Essentially PowerShell is a scripting language that makes operating .NET a little easier/more straightforward than typing out .NET class instructions, but it is also an abstraction. Sometimes to get specific functionality you may need to use .NET directly (for example).
There is another discussion of custom buttons in this thread which has some useful links and other information in it. In particular, Anybox looks really nice if you want a feature-rich dialog box creation tool. Also, here is a custom function called New-WPFMessageBox which implements some XML to control the message box design.
You don’t have to re-invent the wheel to get this kind of functionality in PowerShell, but if you’re doing it for your own edification then take a look at the script for those examples to learn some new tricks. Finally, here is a short wiki article about GUI event handling with PowerShell: How to Add a PowerShell GUI Event Handler (Part 1).