The PowerShell ISE sometimes behaves unpredictably after code changes are made

牧云@^-^@ 提交于 2019-12-22 07:13:27

问题


I'm using the PowerShell ISE (PS version 5.0). If I run this code:

Write-Host "This"

It outputs:

This

If I modify the script like this:

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 change anything in the script, e.g. "Here" to "There" or $Timer.Interval = 3000 to $Timer.Interval = 4000 and run it, it does two unexpected things: 1.) instead of showing the form for the proper duration of time, it briefly flashes it on the screen, and 2.) it outputs the original Here instead of There. If I close the ISE and re-open it, the script runs as expected.

What is going on?


回答1:


tl;dr:

  • The timer instance is created in the session scope,

    • whether or not you run your script in the ISE,
    • and whether or not any variables that reference it are in scope.
  • Always dispose of a timer (or at least disable it) to prevent it from generating more events.

  • Generally - although that is not the cause of the problem at hand - be aware that running a script in the ISE implicitly dot-sources it, so that repeated executions run in the same scope, with variable values from previous ones lingering, which can lead to unexpected behavior.


Your code never disposes of (or disables) the timer, which therefore:

  • stays alive for the entire session, whether or not a variable references it

  • continues to generate events,

  • but they only fire while a form is being displayed.

This explains your symptom: The queued up, original events fire instantly as soon as you display the form again.

The solution is to dispose of the timer once it has done its duty and fired 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 sourcing behavior of the ISE described above, repeated invocations of this code work as expected.




回答2:


I think it has to do with how variables in the ISE are still in memory even after the script ends. If you add

$Timer.Stop() 

to the last line of the script then close and reopen the ISE it will work.



来源:https://stackoverflow.com/questions/44308958/the-powershell-ise-sometimes-behaves-unpredictably-after-code-changes-are-made

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!