Google
 

Friday, December 5, 2008

Handling errors when calling PowerShell using C#

In a previous post, I explained how to call PowerShell Commands from C# code in an easy way. But what about error handling?
First, we should know about the types of errors that need to be handled:
  • Exceptions due to error in syntax of the command or script.
  • Errors generated from commands themselves due to logical errors or invalid parameters.
Handling Exceptions:
Several exceptions can be thrown. The base for PowerShell exceptions is the System.Management.Automation.RuntimeException class. Exceptions can originate from bad syntax or calling invalid commands.
Handling this kind of errors follows the common exception handling in .net as this example shows:


try
{
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "c:\\" + " -recurse -Filter *.exe");
}
}
catch (System.Management.Automation.RuntimeException ex)
{
Console.WriteLine(ex.Message);
//Specific handling for PowerShell errors
}
catch (Exception ex)
{
//general handling and logging
}

Command Errors:
These errors that commands return. For example, when you run this command in PowerShell while you don't have a Q drive:
dir Q:
You'll get this error:
Get-ChildItem : Cannot find drive. A drive with name 'q' does not exist.
At line:1 char:4
Which makes sense. But how to check for this kind of errors?
The Invoke method of the RunspaceInvoke class has an overload that accepts an IList as the 3rd parameter. This out parameter will contain a list of errors that has occurred.


IList errors;
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "Q:\\" + " -recurse -Filter *.exe", null, out errors);
}

if (errors.Count > 0)
{
PSObject error = errors[0] as PSObject;
if (error != null)
{
ErrorRecord record = error.BaseObject as ErrorRecord;
Console.WriteLine(record.Exception.Message);
Console.WriteLine(record.FullyQualifiedErrorId);
}

return;
}

In the above code, I cast the error to PSObject and get its BaseObject and cast it to ErrorRecord which contains the error information.

An interesting part here, is that you can check the FullyQualifiedErrorId property which is a string to distinguish errors and create logic to handle specific errors. ErrorDetails property can also be checked. But be careful because it can be null.

I hope this post can make your programming with PowerShell easier.