4

I have some PowerShell hosts in C# from where I execute PowerShell script code. The code below is from a host in an Add0In for Visual Studio. Problem is that if an error occurs in the PowerShell script code that I don't know the file and line number of the PowerShell script file where the error occured.

My hosting code looks like:

        public Exception Execute(string scriptcode, Hashtable variables)
    {
        Runspace runspace = null;
        Pipeline pipeline = null;
        PipelineStateInfo info = null;

        try
        {
            // Make our output window active
            Logger.ShowOutputWindow();

            // Create the runspace and stuff.
            runspace = RunspaceFactory.CreateRunspace(host);
            pipeline = runspace.CreatePipeline();

            runspace.Open();

            // Add our scriptcode to the pipeline
            pipeline.Commands.Add(new Command(scriptcode, true));

            // We don't want to get PSObjects out of the pipeline, output result as string in default way
            pipeline.Commands.Add(new Command("Out-Default", true));

            // Set up global variables
            FillVariables(runspace, variables);

            SetUpOutputStreams(pipeline);


            // Run the scriptcode
            Collection<PSObject> psOutput = pipeline.Invoke();

            // Did it complete ok?
            info = pipeline.PipelineStateInfo;
            if (info.State != PipelineState.Completed)
            {
                return info.Reason;
            }
            else
            {
                return null; // succesful!
            }
        }
        catch (Exception ex)
        {
            return ex;
        }
    }

First I had my script in the scriptcode variable, I now write the code to a temporary .ps1 file first so I could report on linenumbers in that file. But I can't find how to execute code in a file so it is possible to retrieve filename and line numbers in case of errors.

Any ideas?

1
  • any solution about it and full source code? Commented May 25, 2012 at 8:19

1 Answer 1

7

This should get you in the right place:

//invoke pipeline
collection = pipeline.Invoke();

// check for errors (non-terminating)
if (pipeline.Error.Count > 0)
{
  //iterate over Error PipeLine until end
  while (!pipeline.Error.EndOfPipeline)
  {
    //read one PSObject off the pipeline
    var value = pipeline.Error.Read() as PSObject;
    if (value != null)
    {
      //get the ErrorRecord
      var r = value.BaseObject as ErrorRecord;
      if (r != null)
      {
        //build whatever kind of message your want
        builder.AppendLine(r.InvocationInfo.MyCommand.Name + " : " + r.Exception.Message);
        builder.AppendLine(r.InvocationInfo.PositionMessage);
        builder.AppendLine(string.Format("+ CategoryInfo: {0}", r.CategoryInfo));
        builder.AppendLine(
        string.Format("+ FullyQualifiedErrorId: {0}", r.FullyQualifiedErrorId));
      }
    }
  }
  return builder.ToString();
}

UPDATE:

As well as the information I wrote in the comment, please also look at this book: Professional PowerShell Programming

I found this book invaluable when I first started programming a host for the PowerShell runtime. It was written by some of the PowerShell devs.

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

2 Comments

Strange thing is that if an error occurs, for example using throw or 1/0, the pipeline.Invoke() throws an exception, and the error collection is empty. So I don't get the invocation information. It also does not make tracing work (set-psdebug -trace 1).
Yes. This code will catch any errors PowerShell surfaces, not exceptions PowerShell throws. Those have to be caught in a normal try catch block around your invoke call. I usually have NullReferenceException and some specific PowerShell exceptions caught for specific cases. Tracing is another pipeline. I don't have the SDK in front of me at the moment, but I believe it's accessed the same way.

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.