What I am trying to accomplish is to create buttons that launch exe files in a certain directory when clicked, but when I try using a foreach loop to create a few buttons, all of the buttons just launch the file the last button is supposed to launch.
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Main Window'
$form.Size = New-Object System.Drawing.Size(600,400)
$flp = New-Object System.Windows.Forms.FlowLayoutPanel
$flp.Location = New-Object System.Drawing.Point(0,0)
$flp.Height = $form.Height
$flp.Width = $form.Width
$form.Controls.Add($flp)
$files = Get-ChildItem "$home\Downloads" -Include *.exe -Name
foreach ($file in $files){
$button = New-Object System.Windows.Forms.Button
$flp.Controls.Add($button)
$button.Width = 100
$button.Height = 50
$button.Text = $file
$button.Add_Click{
Start-Process -FilePath "$home\Downloads\$file"
}
}
$form.Topmost = $true
$form.ShowDialog()
Whatever I'm doing is probably pretty stupid, so I was just looking for any alternatives or solutions to this other than to just hard code everything.
CodePudding user response:
It is likely that you need to use .GetNewClosure()
ScriptBlock method so that each script block (button click event) holds the current value of the $file
variable at the moment of enumeration.
Example of what this means:
$blocks = foreach($i in 0..5) {
{ "hello $i" }
}
& $blocks[0] # => hello 5
& $blocks[1] # => hello 5
$blocks = foreach($i in 0..5) {
{ "hello $i" }.GetNewClosure()
}
& $blocks[0] # => hello 0
& $blocks[1] # => hello 1
In that sense, and assuming this is the issue, the following should work:
foreach ($file in $files) {
$button = New-Object System.Windows.Forms.Button
$flp.Controls.Add($button)
$button.Width = 100
$button.Height = 50
$button.Text = $file
$thisEvent = { Start-Process -FilePath "$home\Downloads\$file" }.GetNewClosure()
$button.Add_Click($thisEvent)
}