Search code examples
c#powershell

How to read PowerShell exit code via C#


I am using System.Management.Automation.Runspaces to execute PowerShell scripts. Is there an option I can read the exit code of a given script?

using System.IO;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;
using System.Management.Automation;

namespace PowerShell
{
    public class PowerShellExecuter
    {
        public Collection<PSObject> RunPsScript(string psScriptFile)
        {
            string psScript;
            if (File.Exists(psScriptFile))
            {
                psScript = File.ReadAllText(psScriptFile);
            }
            else
            {
                throw new FileNotFoundException("Wrong path for the script file");
            }
            Runspace runSpace = RunspaceFactory.CreateRunspace();
            runSpace.Open();

            RunspaceInvoke runSpaceInvoker = new RunspaceInvoke(runSpace);
            runSpaceInvoker.Invoke("Set-ExecutionPolicy Unrestricted");

            Pipeline pipeLine = runSpace.CreatePipeline();
            pipeLine.Commands.AddScript(psScript);
            pipeLine.Commands.Add("Out-String");

            Collection<PSObject> returnObjects = pipeLine.Invoke();
            runSpace.Close();

            return returnObjects;
        }
    }
}

Solution

  • PowerShell commands have a richer error mechanism than integer exit codes. There is an error stream that non-terminating errors appear on. Terminating errors result in thrown exceptions so you need to handle those. The following code shows how to use the two mechanisms:

    using System;
    using System.Collections.ObjectModel;
    using System.Management.Automation;
    
    namespace PowerShellRunspaceErrors
    {
        class Program
        {
            private static PowerShell s_ps;
    
            static void Main(string[] args)
            {
                s_ps = PowerShell.Create();
                ExecuteScript(@"Get-ChildItem c:\xyzzy");
                ExecuteScript("throw 'Oops, I did it again.'");
            }
    
            static void ExecuteScript(string script)
            {
                try
                {
                    s_ps.AddScript(script);
                    Collection<PSObject> results = s_ps.Invoke();
                    Console.WriteLine("Output:");
                    foreach (var psObject in results)
                    {
                        Console.WriteLine(psObject);
                    }
                    Console.WriteLine("Non-terminating errors:");
                    foreach (ErrorRecord err in s_ps.Streams.Error)
                    {
                        Console.WriteLine(err.ToString());
                    }
                }
                catch (RuntimeException ex)
                {
                    Console.WriteLine("Terminating error:");
                    Console.WriteLine(ex.Message);
                }
            }
        }
    }
    

    If you run this program it outputs:

    Output:
    Non-terminating errors:
    Cannot find path 'C:\xyzzy' because it does not exist.
    Terminating error:
    Oops, I did it again.
    Press any key to continue . . .