Adding Non-Terminating Error Reporting to Your Cmdlet
Cmdlets can report nonterminating errors by calling the WriteError method and still continue to operate on the current input object or on further incoming pipeline objects. This section explains how to create a cmdlet that reports nonterminating errors from its input processing methods.
Note: |
|---|
| You can download the C# source file (getproc04.cs) for this Get-Proc cmdlet using the Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components. For download instructions, see How to Install Windows PowerShell. The downloaded source files are available in the <PowerShell Samples> directory. |
For nonterminating errors (as well as terminating errors), the cmdlet must pass an ErrorRecord object identifying the error. Each error record is identified by a unique string called the "error identifier." In addition to the identifier, the category of each error is specified by constants defined by a ErrorCategory enumeration. The user can view errors based on their category by setting the $ErrorView variable to "CategoryView".
Note: |
|---|
| Your cmdlet can report terminating errors (errors that prevent the cmdlet from continuing to process any more records) by calling the ThrowTerminatingError method to report the error. For an example of a cmdlet that reports terminating errors, see Adding Aliases, Wildcard Expansion, and Help to Cmdlet Parameters. |
For more information about error records, see Windows PowerShell Error Records.
Topics in this section include the following:
- Defining the Cmdlet
- Defining Parameters
- Overriding Input Processing Methods
- Reporting Nonterminating Errors
- Code Sample
- Defining Object Types and Formatting
- Building the Cmdlet
- Testing the Cmdlet
Defining the Cmdlet
The first step in cmdlet creation is always naming the cmdlet and declaring the .NET class that implements the cmdlet. This cmdlet retrieves process information, so the verb name chosen here is "Get". (Almost any sort of cmdlet that is capable of retrieving information can process command-line input.) For more information about approved cmdlet verbs, see Cmdlet Verbs.
The following is the definition for this Get-Proc cmdlet. Details of this definition are given in Creating a Cmdlet without Parameters.
Defining Parameters
If necessary, your cmdlet must define parameters for processing input. This Get-Proc cmdlet defines a Name parameter as described in Adding Parameters that Process Command-Line Input.
Here is the parameter declaration for the Name parameter of this Get-Proc cmdlet.
Overriding Input Processing Methods
All cmdlets must override at least one of the input processing methods provided by the Cmdlet class. These methods are discussed in Creating a Cmdlet without Parameters.
Note: |
|---|
| Your cmdlet should handle each record as independently as possible. |
This Get-Proc cmdlet overrides the ProcessRecord method to handle the Name parameter for input provided by the user or a script. This method will get the processes for each requested process name or all processes if no name is provided. Details of this override are given in Creating a Cmdlet without Parameters.
Things to Remember When Reporting Errors
The ErrorRecord object that the cmdlet passes when writing an error requires an exception at its core. Follow the .NET guidelines when determining the exception to use. Basically, if the error is semantically the same as an existing exception, the cmdlet should use or derive from that exception. Otherwise, it should derive a new exception or exception hierarchy directly from the Exception class.
When creating error identifiers (accessed through the FullyQualifiedErrorId property of the ErrorRecord class) keep the following in mind.
-
Use strings that are targeted for diagnostic purposes so that when inspecting the fully qualified identifier you can determine what the error is and where the error came from.
-
A well formed fully qualified error identifier might be as follows.
CommandNotFoundException,Micrososft.PowerShell.Commands.GetCommanddCommand.
Notice that in the previous example, the error identifier (the first token) designates what the error is and the remaining part indicates where the error came from.
-
For more complex scenarios, the error identifier can be a dot separated token that can be parsed on inspection. This allows you too branch on the parts of the error identifier as well as the error identifier and error category.
The cmdlet should assign specific error identifiers to different code paths. Keep the following information in mind for assignment of error identifiers:
-
An error identifier should remain constant throughout the cmdlet life cycle. Do not change the semantics of an error identifier between cmdlet versions.
-
Use text for an error identifier that tersely corresponds to the error being reported. Do not use white space or punctuation.
-
Have your cmdlet generate only error identifiers that are reproducible. For example, it should not generate an identifier that includes a process identifier. Error identifiers are useful to a user only when they correspond to identifiers that are seen by other users experiencing the same problem.
Unhandled exceptions are not caught by Windows PowerShell in the following conditions:
-
If a cmdlet creates a new thread and code running in that thread throws an unhandled exception, Windows PowerShell will not catch the error and will terminate the process.
-
If an object has code in its destructor or Dispose methods that causes an unhandled exception, Windows PowerShell will not catch the error and will terminate the process.
Reporting Nonterminating Errors
Any one of the input processing methods can report a nonterminating error to the output stream using the WriteError method. Here is a code example from this Get-Proc cmdlet that illustrates the call to WriteError from within the override of the ProcessRecord method. In this case, the call is made if the cmdlet cannot find a process for a specified process identifier.
protected override void ProcessRecord() { // If no name parameter passed to cmdlet, get all processes. if (processNames == null) { WriteObject(Process.GetProcesses(), true); } else { // If a name parameter is passed to cmdlet, get and write // the associated processes. // Write a nonterminating error for failure to retrieve // a process. foreach (string name in processNames) { Process[] processes; try { processes = Process.GetProcessesByName(name); } catch (InvalidOperationException ex) { WriteError(new ErrorRecord( ex, "NameNotFound", ErrorCategory.InvalidOperation, name)); continue; } WriteObject(processes, true); } // foreach (... } // else }
Things to Remember About Writing Nonterminating Errors
For a nonterminating error, the cmdlet must generate a specific error identifier for each specific input object.
A cmdlet frequently needs to modify the Windows PowerShell action produced by a nonterminating error. It can do this by defining the ErrorAction and ErrorVariable parameters. If defining the ErrorAction parameter, the cmdlet presents the user options SilentlyContinue, Continue, Stop, and Inquire. The user can also directly influence the action by setting the $ErrorActionPreference variable.
The cmdlet can save nonterminating errors to a variable using the ErrorVariable parameter, which is not affected by the setting of ErrorAction. Failures can be appended to an existing error variable by adding a plus sign (+) to the front of the variable name.
Code Sample
For complete sample code, see the following topics.
| Language | Topic |
|---|---|
| C# | |
| VB.NET |
Define Object Types and Formatting
Windows PowerShell passes information between cmdlets using .NET objects. Consequently, a cmdlet might need to define its own type, or the cmdlet might need to extend an existing type provided by another cmdlet. For more information about defining new types or extending existing types, see Extending Object Types and Formatting.
Building the Cmdlet
After implementing a cmdlet, you must register it with Windows PowerShell through a Windows PowerShell snap-in. For more information about registering cmdlets, see Registering a Program Module with Windows PowerShell.
Testing the Cmdlet
When your cmdlet has been registered with Windows PowerShell, you can test it by running it on the command line. Let's test the sample Get-Proc cmdlet to see whether it reports an error:
-
Start Windows PowerShell, and use the Get-Proc cmdlet to retrieve the processes named "TEST".
The following output appears.PS> get-proc -name test
get-proc : Operation is not valid due to the current state of the object. At line:1 char:9 + get-proc <<<< -name test
See Also
Concepts
Adding Parameters that Process Pipeline InputAdding Parameters that Process Command-Line Input
Creating a Cmdlet without Parameters
Windows PowerShell SDK
Other Resources
Creating CmdletsExtending Object Types and Formatting
Registering a Program Module with Windows PowerShell
Windows PowerShell Programmer's Guide
Note: