问题
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