Search code examples
c#powershellprocessstart-jobstart-process

Detaching process from powershell hosted in C# application


We have a C# application that executes PowerShell scripts as an extension point, we don't have access to change this code but it is pretty much the following:

string command = @"C:\temp.ps1";
var fileName = "powershell";
var args = $"-ExecutionPolicy unrestricted . '{command}'";

var process = CreateProcess(fileName, args);
ExecuteProcess(ref process);

private Process CreateProcess(string fileName, string args)
{
    return new Process
    {
        StartInfo =
        {
            FileName = fileName,
            Arguments = args,
            RedirectStandardError = true,
            RedirectStandardOutput = true,
            UseShellExecute = false
        }
    };
}

private int ExecuteProcess(ref Process proc)
{
    proc.Start();

    string text = string.Empty;
    string text2 = string.Empty;
    while (!proc.HasExited)
    {
        Thread.Sleep(1000);
        text += proc.StandardOutput.ReadToEnd();
        text2 += proc.StandardError.ReadToEnd();
    }
    proc.WaitForExit();
    text2 += proc.StandardError.ReadToEnd();
    text += proc.StandardOutput.ReadToEnd();

    Console.WriteLine(text);
    Console.WriteLine(text2);

    return proc.ExitCode;
}

We have a PowerShell script that gets executed from this code that has a long-running process, to keep this simple we'll just use ping.exe with a -t argument.

ping -t google.com

We want to be able to fork the ping.exe process so that the c# application can resume execution as soon as possible and that the ping.exe in this example continues on it's merry way.

I've tried to run Start-Process inside the powershell script but this still just blocks the execution of the C# application until all the processes have fully executed (so it eventually runs to completion):

Start-Process ping -ArgumentList "-t","google.com" -RedirectStandardOutput ".\out.log" -RedirectStandardError ".\err.log"

I've also tried to run Start-Job and wrap the start process in a separate job, however, this seems to start the job but never completes

Start-Job -ScriptBlock { Start-Process ping -ArgumentList "-t","google.com" -RedirectStandardOutput ".\out.log" -RedirectStandardError ".\err.log" }

Is there any way to start a new process from within PowerShell and allow the C# application to continue executing?


Solution

  • I've kinda found a workaround - if I pass in -Verb Open to Start-Process it seems to resume execution to the C# application straight away. The only problem is that you can't redirect the standard out or error to files.

    Start-Process ping -ArgumentList "-t","google.com" -Verb Open