Powershell Beginstop Seems to Raise 2 Events

This topic contains 1 reply, has 1 voice, and was last updated by  Colin Bruce 3 months, 3 weeks ago.

  • Author
    Posts
  • #97547

    Colin Bruce
    Participant

    I have been writing a script in PowerShell V4 on Windows 8.1 which makes use of background processes and
    events. I have found something which is a little strange. Rather than post the 2,500 lines or so of my
    script I have included a much shorter program which exhibits the odd behaviour. I expect it is something
    I am doing wrong but I cannot see what the problem is. The code is as follows:

    # Scriptblocks to simulate the background task and the action to
    # take when an event is raised
    
    [scriptblock] $MyScript = {
        for ($i = 0;$i -lt 30;$i++)
        {
            [console]::writeline("This is a test - $i")
            start-sleep -m 500
        }
    }
    
    [scriptblock] $StateChanged = {
        [console]::writeline("The state changed")
    }
    
    #  Create a runspace pool
    
    $RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, [int] $env:NUMBER_OF_PROCESSORS + 1)
    $RunspacePool.ApartmentState = "MTA"
    $RunspacePool.Open()
    
    #  Create and start the background task to run
    
    $PS = [powershell]::Create()
    [void] $PS.AddScript($MyScript)
    $PS.RunspacePool = $RunspacePool
    $Asyncresult = $PS.BeginInvoke()
    
    #  Register an interest in the InvocationStateChanged event for
    #  the background task. Should the event happen (which it will)
    #  run the $StateChanged scriptblock
    
    Register-ObjectEvent -InputObject $PS -EventName InvocationStateChanged -Action $StateChanged
    
    #  The loop that simulates the main purpose of the script
    
    [int] $j = 0
    while ($PS.InvocationStateInfo.State -eq [System.Management.Automation.PSInvocationState]::Running)
    {
        if ($j -eq 2)
        {
            [void] $PS.BeginStop($NULL, $NULL)
        }
        "Running: $j" | out-host
        sleep -m 400
        $j = $j + 1
    }
    
    sleep 10
    

    Essentially all it does is create a runspace to run a powershell scriptblock and while that is running something
    else happens in the foreground. I simulate someone pressing a button or, for whatever reason, a beginstop method
    being executed to stop the background process. That all works and the background process duly stops. However,
    I have registered an event for the background powershell script which runs a scriptblock when the background
    job changes state. The strange thing is that the scriptblock gets invoked twice and I cannot work out why.

    Here is some output from running the script:

    E:\Test Programs>powershell -file .\strange.ps1
    This is a test - 0
    Running: 0
    This is a test - 1
    Running: 1
    The state changed
    Running: 2
    The state changed
    E:\Test Programs>
    

    As you can see it displays "The state changed" twice. They are a fraction of a second apart. I put a
    sleep 10 at the end to eliminate the possibility that it is the script stopping that is causing the
    second "The state changed" message.

    If anyone can explain what is wrong I would be very grateful.

  • #97617

    Colin Bruce
    Participant

    More information and a work around

    I have a little more information and a work around. I tried running it in the ISE and setting a breakpoint at the only line in the StateChanged script block. When I run it, it stops at that line as expected. single stepping it, it goes to the closing curly bracket next and then on the next single step, goes back to the first line in the scriptblock. A further single step goes to the curly bracket and one more exits the scriptblock. I added a couple of extra lines to the StateChanged script block and when it is executed, it steps through the scriptblock exactly twice and only leaves it after it has been run twice. I don't know why it is doing this but I found that if I add a break or exit statement at the end of the scriptblock it behaves properly. I am not aware of a need to add such statements at the end of scriptblocks adn I have tried running the scriptblock directly using

    &$StateChanged

    and when I do that it just runs once as you would expect so I guess this is something to with using a scriptblock with

    register-ObjectEvent

    I did use get-event to see if there were other events but there were none and I also tried this on Windows 10 with POwerShell V5 and the behaviour is exactly the same as on Windows 8.1 with PowerShell V4

You must be logged in to reply to this topic.