Hi,

 

This blog is about how to handle error codes returned by PowerShell Failover Clustering CMDlets. For an introduction to this topic you can take a look at http://blogs.msdn.com/clustering/archive/2009/05/23/9636665.aspx.  Cluster CMDlets can fail for various different reasons, such as passing non-existent entities as parameters (try to delete a group using a name that is not present in the cluster); mismatching types (try to pass a string but when a cluster object is required); or when the passed parameter breaks because of some cluster business logic. This blog focuses on how to get error codes from the third type of failure.

 

 

Imagine that you are trying to add a cluster node using the Add-ClusterNode CMDlet:

 

Add-ClusterNode -Name "node1"

 

If “node1” is not part of any cluster this operation will succeed, otherwise it will fail and you will get the error message:

Add-ClusterNode : The computer 'node1.domain' is joined to a cluster.

At line:1 char:16

+ Add-ClusterNode <<<<  -Name "node1"

    + CategoryInfo          : NotSpecified: (:) [Add-ClusterNode], ClusterCMDletException

    + FullyQualifiedErrorId : Add-ClusterNode,Microsoft.FailoverClusters.PowerShell.AddClusterNodeCommand  

 

Let’s run:

 

$error[0].Exception | get-Member

 

This will give us the type of the exception contained in the latest error record.  In this case it will be Microsoft.FailoverClusters.PowerShell.ClusterCMDletException.  When this kind of exception occurs we have a non-terminating error, which means that the CMDlet itself finished its execution properly, however there was some problem with the operation completing successfully.  If the node did not get added to the cluster, since the passed name breaks some cluster business logic. 

 

 

When writing PowerhShell scripts, one often needs to know not only that the CMDlet finished, but also if its result are as expected.  In order to verify this, an extra step is needed to get the error code embedded on the returned exception.

 

You can collect the error information with:

 

$error[0].Exception.ErrorCode

 

error[0] contains an Exception object (Microsoft.FailoverClusters.PowerShell.ClusterCMDletException), which contains the error code.  For the given example this will return:

 

$error[0].Exception.ErrorCode

-2147024809

 

If you want to have the error code in a more readable format you can run:

$error[0].Exception.ErrorCode –band 0xffff

87

 

So we see this is error code 87.

 

 

 PowerShell can also be used with managed code.  The error codes can be captured similarly to the console approach described erlier.  Here is an example of code that does that:

 

System.Management.Automation.PowerShell _powershell = PowerShell.Create();

….

ErrorRecord errRec = _powershell.Streams.Error[0];

PropertyInfo errCodeInfo = null;

int retErrorCode = 0;

Try {

// if the exception is a ClusterCMDletException object we

// should have a property with error code

      errCodeInfo = errRec.Exception.GetType().GetProperty("ErrorCode");

 } catch (Exception) {

                    // Handle other type of exceptions differently

}

 if (errCodeInfo != null) {

     object propValue = errCodeInfo.GetValue(errRec.Exception, null);

     retErrorCode = Convert.ToInt32(propValue); // thats and hr Value

     retErrorCode = retErrorCode & 0xFFFF;   // this would give the int error code

}

 

 

 

I hope this information is useful for all of you writing PowerShell scripts or C# code.

 

 

Thanks,

Emanoel Xavier

Software Development Engineer in Test

Clustering & High-Availability

Microsoft