I’m troubleshooting the logic of a script that does some long BG operation. I need user to be able to abort it in GUI. Here’s a simplified version, the script sleeps 3 sec in a runspace, then returns “OK” that is picked up by a Winform timer event. If user aborts it by pressing ‘Stop’ button which calls $Powershell.Stop() method it works fine, but if hes then re-initiates the job - $AsyncResult returns nothing. If you press ‘Do’ button one more time - it gets back to normal.
That’s how it works on PS 5.0. I’ve checked it on 2.0 - it works as expected there, it returns result every time, no matter if previous job finished normally or was forced quited. What am I missing here?
Add-Type -AssemblyName System.Windows.Forms
$form = New-Object 'System.Windows.Forms.Form'
$buttonDo = New-Object 'System.Windows.Forms.Button'
$buttonStop = New-Object 'System.Windows.Forms.Button'
$timer = New-Object 'System.Windows.Forms.Timer'
$BGScriptBlock = {
$synchash.form.Text = "Job is being done..."
start-sleep 3
return "OK"
}
$synchash = [Hashtable]::Synchronized(@{ })
$script:Powershell = [PowerShell]::Create().AddScript($BGScriptBlock).AddArgument($PC)
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspace = [RunspaceFactory]::CreateRunspace($sessionstate)
$runspace.ApartmentState = "STA"
$runspace.ThreadOptions = "ReuseThread"
$runspace.Open()
$runspace.SessionStateProxy.SetVariable("synchash", $synchash)
$Powershell.Runspace = $runspace
$buttonDo_Click = {
$script:AsyncResult = $Powershell.BeginInvoke()
$timer.Enabled = $true; $timer.Start(); $script:tick = 0
}
$buttonStop_Click = {
$Powershell.Stop()
$form.Text = 'Stopped'
}
$TimerTick = {
$script:tick++; write-host $script:tick;
switch ($script:Powershell.InvocationStateInfo.State)
{
'Stopped'{write-host "Stopped" }
'Completed' { $result = $Powershell.EndInvoke($script:AsyncResult); write-host "Completed, result: $result"}
{$_ -match "Stop|Completed"} {$timer.Stop(); $timer.Enabled = $false; $form.Text = 'Done'}
}
}
$form.Controls.Add($buttonDo)
$form.Controls.Add($buttonStop)
$form.Size = '400, 150'
$form.Text = 'Form'
$form.Topmost = $true
$buttonDo.Location = '73, 37'
$buttonDo.Size = '100, 30'
$buttonDo.Text = 'Do'
$buttonDo.add_Click($buttonDo_Click)
$buttonStop.Location = '209, 37'
$buttonStop.Size = '100, 30'
$buttonStop.Text = 'Stop'
$buttonStop.add_Click($buttonStop_Click)
$timer.Interval = 1000
$timer.add_Tick($TimerTick)
$synchash.form = $form
$form.ShowDialog()
Well, in real world I’m trying to initiate a PSRemoting session over HHTPS/SSL, the strange thing about is that if the session is initiated against a server that is not set up for HTTPS/SSL it waits a good minute before the time-out occures. In PS 5.0 I can force quit it using $Powershell.Close() or $Powershell.Dispose() or even $runspace.Close() but in 2.0 any of these doesn’t kill the thread, it stumbles upon a non-respoding command and freezes until it finishes. These methods are executed but only a minute later. Is there something that can be done about it?