Force stopping powershell runspace

This topic contains 1 reply, has 2 voices, and was last updated by Profile photo of Don Jones Don Jones 1 week, 2 days ago.

  • Author
    Posts
  • #63486
    Profile photo of Mark
    Mark
    Participant

    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?

  • #70666
    Profile photo of Don Jones
    Don Jones
    Keymaster

    I think you want to not Stop so much as "Pause," from what you're saying. Which means you'd need to have a spot in your script which checks to see if it's been asked to pause, and enters a Start-Sleep loop until it is resumed.

    PowerShell's not really designed for this type of thing, so whatever you do will end up being a little hack-y.

You must be logged in to reply to this topic.