1

I am using Microsoft.PowerShell.5.1.ReferenceAssemblies to run some powershell scripts.

    private void RunScript(string command)
    {

        var runspace = RunspaceFactory.CreateRunspace();
        runspace.Open();
        var builder = new StringBuilder();

        var task = new Task(() => {

            var pipeline = runspace.CreatePipeline();
            pipeline.Commands.AddScript(command);
            try
            {
                var result = pipeline.Invoke();
                foreach (var r in result)
                {
                    builder.Append(r.ToString());
                }
            }
            catch (Exception e)
            {
                builder.Append(e);
            }

            runspace.Close();

            var consoleOutput = builder.ToString();

            runspace.Dispose();
        });

        psScriptsRunning.Add(runspace);

        task.Start();
    }

I keep track of the runspaces in psScriptsRunning. So when my app is closed, I go through and close the runspaces.

    public void deinit()
    {
        foreach(var runspace in psScriptsRunning)
        {
            runspace.Dispose();   
        }
    }

This has the effect of closing the powershell scripts and any processes it has spawned. However seems like it takes a while to actually close the processes, if you have a better way to improve this, please let me know.

However, if someone kills my app from Task Manager, this code will not run. How can I kill any processes launched by the powershell scripts?

Previously before supporting powershell scripts directly via runspaces, I used to create a process and launch via powershell.exe.

I was able to make sure any processes spawned were killed by using job objects see Kill child process when parent process is killed.

Now that I am using runspaces, how can I achieve the same ?

The reason I went with runspaces instead of using powershell.exe was due to better launching times of the powershell scripts.

rukiman
  • 597
  • 10
  • 32
  • You might want to take a look at [Job objects](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_jobs?view=powershell-7). I have only used the c# variant, not the powershell one, but I would assume they use they work in a similar way. – JonasH Sep 14 '20 at 09:48
  • Not sure how this helps me. I already use powershell job objects to start the new processes. However the job objects I was referring to in my post is not the same as this. – rukiman Sep 14 '20 at 11:04
  • Appreciate your question as it clearly spells out my current problem. Couldn't get real-time output from PS without using the pipeline approach. When trying to kill the process, the pipeline hangs on dispose. – Michael Feb 14 '22 at 15:16

1 Answers1

0

Ok after some investigation. It turns out I had the solution in front of my eyes. The job objects c# code in Kill child process when parent process is killed

is all I needed. I was calling it for all child processes I created, it seems I didn't need to do this. All I had to do was call it for my application's process. Then all processes my application creates i.e via runspaces etc all automatically get tagged as from the same job. So when anyone kills my application process, all those other processes also get killed.

I just made the mistake of assuming that I had to get the children processes and assign to the job myself.

rukiman
  • 597
  • 10
  • 32