none
Powershell retrieving pipeline errors in C# RRS feed

  • Question

  • Hello,

    I'm trying to retrieve errors from executing remote Powershell commands via C#. I'm trying to use this snippet of code as shown here but I do not get the pipeline.Streams property available. Can anyone tell me what is wrong here?

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    
    using System.Management.Automation;
    using System.Management.Automation.Remoting;
    using System.Management.Automation.Runspaces;
    using System.Security;
    
    namespace O365PS
    {
        class Program
        {
            static void Main(string[] args)
            {
                string userName = "admin@somecompany.com";
                string password = "Password";
    
                // Encrypt password using SecureString class
                SecureString securePassword = new SecureString();
    
                foreach (char c in password)
                {
                    securePassword.AppendChar(c);
                }
    
                PSCredential credential = new PSCredential(userName, securePassword);
    
                // Connection information object required to connect to the service
                WSManConnectionInfo connectionInfo = new WSManConnectionInfo(
                    new Uri("https://ps.outlook.com/powershell"), 
                    "http://schemas.microsoft.com/powershell/Microsoft.Exchange", 
                    credential);
    
                connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
                connectionInfo.MaximumConnectionRedirectionCount = 2;
                
                // Create runspace on remote Exchange server
                using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
                {
                    runspace.Open();
    
                    using(PowerShell ps = PowerShell.Create())
                    {
                        ps.Runspace = runspace;
    
                        string[] members = new string[] { "user1@somecompany.com", "user2@somecompany.com",
                                                          "user3@somecompany.com"                        
                        };
    
                        foreach (string member in members)
                        {
                            Command command = new Command("Add-DistributionGroupMember");
                            command.Parameters.Add("Identity", "test");
                            command.Parameters.Add("Member", member);
                            Pipeline pipeline = runspace.CreatePipeline();
                            pipeline.Commands.Add(command);
    
                            try 
                            {
                                Collection<PSObject> results = pipeline.Invoke();
    
                                Collection<ErrorRecord> errors = pipeline.Streams.Error.ReadAll(); // Streams property is not available
    
                                 if (errors != null && errors.Count > 0)
                                 {
                                     foreach (ErrorRecord er in errors)
                                     {
                                         Console.WriteLine(er.Exception.ToString());
                                     }
                                 }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex.Message); 
                            }
                        }    
                        
                    }
                }
                Console.WriteLine("Operation completed");
                Console.ReadKey();
            }
        }
    }
    

    Thanks.

    Wednesday, November 30, 2011 10:49 AM

Answers

  • I was able to get the pipeline error as below. For some reason, the ReadToEnd() method always returned a null for me, so I just used the Read() method to get the error.

    results = pipeline.Invoke();
    
    if (pipeline.Error.Count > 0)
    {
           var error = pipeline.Error.Read() as Collection<ErrorRecord>;
           if (error != null)
           {
               foreach (ErrorRecord er in error)
               {
                    Console.WriteLine("[PowerShell]: Error in cmdlet: " + er.Exception.Message);
               }
           }
    }
    


    • Marked as answer by preambleMe Sunday, December 4, 2011 2:04 AM
    Sunday, December 4, 2011 2:04 AM

All replies

  • Hello,

    Can anyone help me out on this? This MSDN article says:

    Streams: Gets the data streams that contain any messages and error reports that were generated when the pipeline of the PowerShell object is invoked.

    But I don't get the Streams property available in Intellisense.

    Any help on this is greatly appreciated.

    Thanks.

    Wednesday, November 30, 2011 3:30 PM
  • I was able to get the pipeline error as below. For some reason, the ReadToEnd() method always returned a null for me, so I just used the Read() method to get the error.

    results = pipeline.Invoke();
    
    if (pipeline.Error.Count > 0)
    {
           var error = pipeline.Error.Read() as Collection<ErrorRecord>;
           if (error != null)
           {
               foreach (ErrorRecord er in error)
               {
                    Console.WriteLine("[PowerShell]: Error in cmdlet: " + er.Exception.Message);
               }
           }
    }
    


    • Marked as answer by preambleMe Sunday, December 4, 2011 2:04 AM
    Sunday, December 4, 2011 2:04 AM
  • Thanks a lot.This was of great help.

    But for me error object was still null.Following snippet worked fine

    if (pipeline.Error.Count > 0)
                {
                    StringBuilder err = new StringBuilder();
                    while (!pipeline.Error.EndOfPipeline)
                    {
                        err.AppendLine(pipeline.Error.Read().ToString());
                    }
                }

    Hope this helps someone

    • Proposed as answer by Shanmuga Thursday, March 10, 2016 11:50 AM
    Thursday, March 10, 2016 11:50 AM
  • Thanks, this was really helpful for me! I refined & combined both of your snippets, as I looked into it and if it is not an ErrorRecord-Collection, it seems it is an ErrorRecord (I'm throwing the exceptions, feel free to change) :

    if (pl.Error.Count > 0) {
                        StringBuilder err = new StringBuilder();
                        while (!pl.Error.EndOfPipeline)
                        {
                            var x = pl.Error.Read();
                            if (x is Collection<ErrorRecord>)
                            {
                                throw (x as Collection<ErrorRecord>).First().Exception;
                            }
                            if (x is ErrorRecord)
                            {
                                throw (x as ErrorRecord).Exception;
                            }
                            err.AppendLine(pl.Error.Read().ToString());
                        }
                        throw new Exception("Error executing PowershellCommand : " +  err);
    }

    Casting could be optimized (is and as result in double type inspection), but I left it this way as it's not performance critical in my case, and in my opinion is easier to read.




    Wednesday, March 8, 2017 12:42 PM