2

I have a console application and a method that executes a PowerShell script within the console application. So I'm trying to grab an error text that it outputs in the application and do something with it.

Example/What I'm trying to do:

    If Error.contains("Object") 
{
    // do something here
}

Here is my current method

  public void ExecutePowershellScript()
{
  var file = @"C:\Path\filename.ps1";
           
            var start = new ProcessStartInfo()
            {
                FileName = "powershell.exe",
                Arguments = $"-NoProfile -ExecutionPolicy unrestricted -file \"{file}\"",
                UseShellExecute = false
            };
            Process.Start(start);
}

3 Answers 3

3

Process.start: how to get the output?

When you create your Process object set StartInfo appropriately:

var proc = new Process 
{
    StartInfo = new ProcessStartInfo
    {
        FileName = "program.exe",
        Arguments = "command line arguments to your executable",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};

then start the process and read from it:

proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
    string line = proc.StandardOutput.ReadLine();
    // do something with line
}

You can use int.Parse() or int.TryParse() to convert the strings to numeric values. You may have to do some string manipulation first if there are invalid numeric characters in the strings you read.

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, and you can set async error handlers process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler); process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler); //* Start process and handlers
2

You can set RedirectStandardError = true and access any errors from process.StandardError

    public static void ExecutePowershellScript()
    {
        var file = @"C:\Path\filename.ps1";

        var start = new ProcessStartInfo()
        {
            FileName = "powershell.exe",
            Arguments = $"-NoProfile -ExecutionPolicy unrestricted -file \"{file}\"",
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true
        };
        using Process process = Process.Start(start);
        string output = process.StandardOutput.ReadToEnd();
        string errors = process.StandardError.ReadToEnd();
    }



Okay, scratch the above suggestion. After being corrected by mklement0,

This is a perfectly reasonable attempt, but, unfortunately, it can lead to hangs (while waiting for one's stream end, the other, when exceeding the buffer size, may cause process execution to block). If you need to capture both streams, you must collect the output from one of them via events. – mklement0

I changed the solution to use the ErrorDataReceived event

        public static async Task ExecutePowershellScript()
        {
            var file = @"C:\Path\filename.ps1";

            var start = new ProcessStartInfo
            {
                FileName = "powershell.exe",
                Arguments = $"-NoProfile -ExecutionPolicy unrestricted -file \"{file}\"",
                UseShellExecute = false,
                // redirect standard error stream to process.StandardError
                RedirectStandardError = true
            };

            using var process = new Process
            {
                StartInfo = start
            };

            // Subscribe to ErrorDataReceived event
            process.ErrorDataReceived += (sender, e) =>
            {
                //  code to process the error lines in e.Data
            };

            process.Start();

            // Necessary to start redirecting errors to StandardError
            process.BeginErrorReadLine();

            // Wait for process to exit
            await process.WaitForExitAsync();

        }

6 Comments

This is a perfectly reasonable attempt, but, unfortunately, it can lead to hangs (while waiting for one's stream end, the other, when exceeding the buffer size, may cause process execution to block). If you need to capture both streams, you must collect the output from one of them via events.
Fair enough. Thanks for the info! @mklement0
@mklement0, ever think of making a book (or article/blog) bridging the gap between C# and PowerShell? 🤔 I'm real persistent on these book ideas lol
Thanks for updating, @Daniel. Just to reiterate: The original approach works robustly when only one stream is captured. When both need to be captured, the event-based approach is the only fully robust one, though, pragmatically speaking, reading from both streams in a loop, line by line, will work too - you would only get in trouble with excessively long individual lines (close to 64KiB and above).
@AbrahamZinala :) I'm starting to get concerned about the amount of homework...
|
0
start.Start();
while (!start.StandardOutput.EndOfStream)
{
    string line = start.StandardOutput.ReadLine();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.