2

I guess this is a newbie question. Yet I did not find anything online...

I'm creating a small powershell script with a very simple gui.

This is the relevant part of the script:

foreach ($script in $scripts){
  $btn = New-Object System.Windows.Forms.Button  
  #Text, Location, Size omitted

  #Add clickhandler
  $btn.Add_Click(
    {    
      Write-Host "Clicked on Btn $script"
      Start-Process -FilePath "powershell" -ArgumentList "-command", "`"$script`""
      Write-Host "finished"
      $Form.Close();
    }
  )
  $Form.Controls.Add($btn)
}

Obviously $scripts contains paths pointing towards other powershell scripts. Being a Java developer I was naiv enough to suspect every click handler to be created with its own reference to a script location ($script).

But of course powershell does not evaluate $script until the handler is invoked. Thus, every button will call the last element in my array $scripts since $script will reference the last element in $scripts after the loop completes.

How can I create a click handler inside a foreach-loop based on the loop-variable itself?

Solution

Mathias R. Jessen pointed me to a working solution. .GetNewClosure() called on the handler worked.

Working Code:

foreach ($script in $scripts){
  $btn = New-Object System.Windows.Forms.Button  
  #Text, Location, Size omitted

  #Add clickhandler
  $btn.Add_Click(
    {    
      Write-Host "Clicked on Btn $script"
      Start-Process -FilePath "powershell" -ArgumentList "-command", "`"$script`""
      Write-Host "finished"
      $Form.Close();
    }.GetNewClosure()
  )
  $Form.Controls.Add($btn)
}
5
  • $using:script Commented Aug 18, 2017 at 5:14
  • Thanks for your input. But I get an error saying $using:var does neither work with Write-Host nor Start-Process Commented Aug 18, 2017 at 5:57
  • stackoverflow.com/questions/30329856/… - from what I can see this answers your question. Commented Aug 18, 2017 at 7:13
  • 1
    AddClick({...}.GetNewClosure()) Commented Aug 18, 2017 at 9:41
  • .GetNewClosure() did the trick. Thanks you Commented Aug 21, 2017 at 5:36

1 Answer 1

1

Solution

Mathias R. Jessen pointed me to a working solution. .GetNewClosure() called on the handler worked.

Working Code:

foreach ($script in $scripts){
  $btn = New-Object System.Windows.Forms.Button  
  #Text, Location, Size omitted

  #Add clickhandler
  $btn.Add_Click(
    {    
      Write-Host "Clicked on Btn $script"
      Start-Process -FilePath "powershell" -ArgumentList "-command", "`"$script`""
      Write-Host "finished"
      $Form.Close();
    }.GetNewClosure()
  )
  $Form.Controls.Add($btn)
}
Sign up to request clarification or add additional context in comments.

Comments

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.