Unlike other programming languages, the PowerShell scripting language has two types of error scenarios: terminating and non-terminating. Both of these types of errors are "bad," but by classifying them differently, the scripter can handle them differently. This distinction is important if you want to stop or exit a PowerShell script when it errors.

Non-terminating errors ^

For example, let's say I've got a script that checks to see whether a file exists or not. I'll call it ErrorExample.ps1. This script uses Test-Path to confirm whether a file exists. If it doesn't, it will return an error via the Write-Error cmdlet. This error will be non-terminating because Write-Error always returns non-terminating errors.

if (-not (Test-Path -Path C:\DoesNotExist.txt)) {
    Write-Error 'The file does not exist'
} else {
    Write-Host 'The file does exist'
}
Write-Host 'Continuing script regardless if file exists or not...'

The script will continue executing code whether or not that file exists as shown below.

Non terminating error

Non terminating error

This is a non-terminating error example because Write-Error did not terminate the script at line two. Instead, it returned the error to the console and kept going. This scenario sometimes isn't desirable. Perhaps that file you're checking for is critical to the success of the lines below it. In that case, you'd want the script to stop execution completely. You'd know that if that file doesn't exist, the rest of the script isn't going to work.

Terminating errors ^

Terminating errors are the second type of error in PowerShell. We can think of terminating errors as exceptions. Exceptions are either errors that terminate a script completely or ones PowerShell "throws" into a catch block to handle the error and perform whatever necessary actions after throwing the exception.

One way a scripter can invoke a terminating error is by using the throw keyword. This PowerShell construct creates a terminating error while also throwing an exception. Using the example above, let's say that file is critical and we'd like to stop script execution if it doesn't exist. We could replace Write-Error with throw instead.

if (-not (Test-Path -Path C:\DoesNotExist.txt)) {
    throw 'The file does not exist'
} else {
    Write-Host 'The file does exist'
}

Write-Host 'Continuing script regardless if file exists or not...'

Notice now that line seven doesn't run; throw has stopped the script at line two.

Terminating error

Terminating error

Turning non-terminating into terminating errors ^

It's sometimes hard to replace all Write-Error references and other actions that produce non-terminating errors with throw statements. Instead, you can keep all of those non-terminating error-producing commands in your scripts and "convert" them to terminating errors.

If you'd like to turn all non-terminating errors into terminating ones, you can perform a global action change by setting the $ErrorActionPreference variable to Stop. This automatic variable controls non-terminating error behavior. By setting $ErrorActionPreference to Stop, you're telling PowerShell to treat all instances where a non-terminating error occurs as terminating. This action applies across the board.

However, maybe you'd rather not change all non-terminating errors to terminating ones and pick certain ones instead. Using the common parameter ErrorAction applied to all cmdlets and advanced functions, you can make this happen.

In our example again, I can actually "override" the Write-Error cmdlet's behavior by forcing it to throw a terminating error. I'll use the ErrorAction parameter and set it to Stop.

Subscribe to 4sysops newsletter!

Write-Error 'The file does not exist' -ErrorAction Stop

When the script runs now, you'll see that it stops execution without using the throw keyword. You can use the ErrorAction parameter on every cmdlet and advanced function in PowerShell. It is a great way to choose which commands should stop script execution and which ones should not. Depending on the severity and dependencies further down in the script, this may or not may be necessary.

+6
avataravatar
10 Comments
  1. IMHO, it is good to turn all non-terminating errors into terminating ones and process with try{} catch {}.

    +5

  2. Justin 3 years ago

    The first example, under "Non-terminating errors" doesn't work. The script does NOT continue running.

    0

    • @Justin

      The article of Adam is correct.

      Can you share the lines of code (not the whole script) that are not working as expected on your computer?

      0

  3. David 3 years ago

    I always see these examples, but none go on to tell us how to suppress the error message that Throw produces. I would like my error message to be the ONLY error message that gets outputted and to terminate the script there and then.

    0

    • @David

      You can achieve that with the try/catch statements.
      The try statement suppresses all output.
      Then inside the catch statement, you can choose which part of the error you want to display.

      try{
          throw 'My Custom Error Message'
      }
      catch{
          $error[0].Exception
      }
      

      $error is an array with all former exceptions.
      $Error[0] is the latest one.
      Each error has several properties.

      $error[0]|Get-Member -MemberType Properties

      I choose in my example to display the Exception property because this is probably what you want, but you can display any of them.

      0

    • This works perfectly for me

      try
      {
      blabla
      
      }
      catch
      {
      "$_"
      }

      The only thing I get is:

      The term 'blabla' is not recognized as the name of a cmdlet, function, script fi
      le, or operable program. Check the spelling of the name, or if a path was includ
      ed, verify that the path is correct and try again.
      0

  4. David 3 years ago

    Hello again,

    Thanks for responding, I have been "Trying" to use the Try/Catch brackets, however I have not seen the Throw command been used within the Try brackets before.

    I originally had this:

    Try { $users = Get-ADUser -Filter * -Properties proxyAddresses -ErrorAction Stop }
    Catch { Throw "This script requires AD module be loaded, try again after it is."}

    And it threw my error, along with PS jargon, but at least it terminated the script. So I tried as you suggested:

    Try {  
      $users = Get-ADUser -Filter * -Properties proxyAddresses -ErrorAction Stop 
      Throw "This script requires AD module be loaded, try again after it is."
    }
    Catch { }

    And I got no output at all, except that I know it did not terminate the script, it continued.

    I ended up finding a different, however longer, way of doing it:

    Try { $users = Get-ADUser -Filter * -Properties proxyAddresses -ErrorAction Stop }
    Catch { write-host "This script requires AD module be loaded, try again after it is."; Exit }

    I'm open to seeing a more concise way of it, but could not as yet.

    PS. I'm not really sure how to use your code brackets, but gave it a shot using the provided toolbar, haha.

    0

    • @David

      The Try/Catch statement is working like this:

      Let's TRY something, and if it's throwing an error,
      let's CATCH the error to see how we will handle it.

      But your third example shows that you already understood this principle.

      Just an additional information:

      Don't assume that there is only one possible error.
      There are many ways something can go wrong.
      Usually, I catch known errors and return the original exception when unknown errors are raised.

      In your example this would give something like:

      Try {
          $users = Get-ADUser -Filter * -Properties proxyAddresses -ErrorAction Stop
      }
      
      Catch [System.Management.Automation.CommandNotFoundException]{
          write-host 'This script requires AD module be loaded, try again after it is.'
          Exit
      }
      
      catch {
          $Error[0].Exception
          Exit
      }
      0

  5. Travis Drake 3 years ago

    David,

    There really isn't a good way to write error output without powershell dumping the context with the error. I am assuming that is what you mean when asking how to suppress the error message from powershell that throw produces.

    Unfortunately powershell wraps all exceptions (throw 'x' produces an exception) in ErrorRecords, which come along with the PS Jargon you mentioned. Powershell itself isn't outputting that jargon, it is actually your shell choosing what to do with an ErrorRecord that bubbles up that causes the rest of the jargon to show up in addition to your throw message. Even Write-Error will still bubble up an error record, which your shell will dump that jargon for.

    This is normal and expected in powershell, and the right way to do what you are doing is the first way in your post (although you should probably filter on the error, as there may have been many reasons Get-ADUser could fail, not just because the commandlets were not loaded).

    +2
    avataravatar

Leave a reply

Please enclose code in pre tags

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2021

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account