PowerShell ISE sometimes behaves unpredictably after code changes

I am using PowerShell ISE (PS version 5.0). If I run this code:

Write-Host "This" 

It outputs:

 This 

If I change the script as follows:

 Write-Host "That" 

It outputs:

 That 

Great. As expected. Now, if I have this code:

 $Form = New-Object System.Windows.Forms.Form $Timer = New-Object System.Windows.Forms.Timer $Timer.Add_Tick( { &{ Write-Output "Here" $Form.Close()} | Write-Host }) $Timer.Interval = 3000 $Timer.start() $result = $Form.ShowDialog() 

It outputs:

 Here 

If I changed something in a script, for example. "Here" to "There" or $Timer.Interval = 3000 to $Timer.Interval = 4000 and run it, it will do two unexpected things: 1.) instead of showing the form for the proper length of time, it blinks briefly on screen, and 2.) instead of There displays the original Here . If I close ISE and open it again, the script will work as expected.

What's happening?

+5
source share
2 answers

t; dr :

  • A timer instance is created in the session area ,

    • Do you run your script in ISE,
    • and are there any variables that reference it are in scope.
  • Always use a timer (or at least turn it off) so that it does not generate more events.

  • In general - although this is not the cause of the problem at hand - keep in mind that executing the script in ISE implicitly sets its point sources , so that repeated executions are performed in the same scope with delayed variable values ​​from the previous ones, which can lead to unexpected behavior.


Your code never uses (or disables) a timer, which is why:

  • remains valid throughout the session, regardless of whether the variable refers to it

  • continues to generate events

  • but they only shoot while the form is being displayed.

This explains your symptom: queued source events fire immediately as soon as you display the form again.

The solution is to get rid of the timer as soon as it has done its duty and triggered the event (once):

 Add-Type -AssemblyName System.Windows.Forms $Form = New-Object System.Windows.Forms.Form $Timer = New-Object System.Windows.Forms.Timer $Timer.Add_Tick({ & { Write-Output "Here" $Form.Close() } | Write-Host }) $Timer.Interval = 3000 $Timer.Start() $result = $Form.ShowDialog() $Timer.Dispose() # IMPORTANT: Dispose of the timer so it won't generate more events. 

Even with the implicit ISE source behavior described above, repeated calls to this code work as expected.

+2
source

I think this is due to the way the variables in ISE are still in memory even after the script completes. If you add

 $Timer.Stop() 

into the last line of the script, then close and run ISE again and it will work.

+1
source

Source: https://habr.com/ru/post/1268438/


All Articles