As DBAs, we're always working on protecting ourselves from problems by disaster recovery procedures like backups, but in our haste to get a script done, we also are prone to forget the same concept within our code to protect the process from errors. PowerShell provides ways to manage those times when there are errors in the execution of our script so we can recover, and still get the job done.

Trap Statement for Handling Errors

PowerShell 1.0 supported the Trap statement for handling errors, and I still frequently use that in my scripts. PowerShell works within the .NET Framework, so errors have multiple levels. It's rare that the top level error message PowerShell returns will help you solve the problem. Let's take, for example. the case where we want to use the SMO CheckTables('FAST') method, which effectively runs DBCC CHECKDB(N'AdventureWorks', REPAIR_FAST). If we run call this method without error handling, we'll get this message.

  1. Exception calling "CheckTables with "1" argument(s): "Check tables failed for Database 'AdventureWorks'."

Now, that isn't very helpful at all. Here's the Trap function I frequently use.

  1. # Handle any errors that occur
  2. Trap {
  3.   # Handle the error
  4.   $err = $_.Exception
  5.   write-output $err.Message
  6.   while( $err.InnerException ) {
  7.           $err = $err.InnerException
  8.           write-output $err.Message
  9.           };
  10.   # End the script.
  11.   break
  12.   }

When the CheckTables('FAST') method is called, now I get the following error messages back.

  1. An exception occurred while executing a Transact-SQL statement or batch.
  2. Repair statement not processed. Database needs to be in single user mode.

The error message in Figure 1 is much more useful and helps me understand exactly what the problem is and how to address it. Note, the use of the keyword "break" after the semi-colon in the trap statement, which causes the script to terminate after the error is encountered and handled. The keyword "continue" will allow non-terminating errors to continue script execution after being handled.

Try-Catch-Finally Method of Handling Errors

PowerShell 2.0 introduced the Try-Catch-Finally method of handling errors that most .NET developers are more accustomed to and which provides much more flexibility in handling problems that may come up. The additional feature you get in this method of handling errors is that you can specify different types of error-handling for different types of errors.  In this example, we'll run the same CheckTables method, but handle an ItemNotFoundException separately, then handle all remaining errors in a manner similar to what I showed in the Trap statement above.

  1. try {
  2. # Connect to the specified instance
  3. $s = new-object ('Microsoft.SqlServer.Management.Smo.Server') $inst
  5. $db = $s.Databases[$dbname]
  6. $db.CheckTables('Fast')
  7. }
  8. catch [System.Management.Automation.ItemNotFoundException] {
  9. write-output "$dbname database not found"
  10. }
  11. catch {
  12.    # Handle the error
  13.    $err = $_.Exception
  14.    write-output $err.Message
  15.    while( $err.InnerException ) {
  16.            $err = $err.InnerException
  17.            write-output $err.Message
  18.           }
  19. }
  20. finally {
  21. write-output "script completed"
  22. }

As you can see, this can provide additional flexibility to handle a variety of errors, and the fact that the Try-Catch-Finally blocks are nestable gives you a lot of control over your scripts.

Related: Run Your SQL Server DBCCs and Check Your Errorlog with PowerShell