Home > other >  PowerShell Add_Click in foreach loop
PowerShell Add_Click in foreach loop

Time:01-31

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)
}
  •  Tags:  
  • Related