Reputation: 4392
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?
Upvotes: 4
Views: 8617
Reputation: 4379
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.
Upvotes: 7