- Create a certificate-signed RDP shortcut via Group Policy - Fri, Aug 9 2019
- Monitor web server uptime with a PowerShell script - Tue, Aug 6 2019
- How to build a PowerShell inventory script for Windows Servers - Fri, Aug 2 2019
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.
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.
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.
IMHO, it is good to turn all non-terminating errors into terminating ones and process with try{} catch {}.
The first example, under “Non-terminating errors” doesn’t work. The script does NOT continue running.
@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?
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.
@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.
$error is an array with all former exceptions.
$Error[0] is the latest one.
Each error has several 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.
This works perfectly for me
The only thing I get is:
Yes $_ is another way to only get the exception.
And LOL for “blabla” 😉
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:
And it threw my error, along with PS jargon, but at least it terminated the script. So I tried as you suggested:
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:
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.
@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:
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).
You should always set the $ErrorActionPreference to “Stop”.
The distinction between non-terminating and terminating errors is the source of very many errors on itself. Because in almost all cases, the script is in an unexpected state after an error: the developer just does not remember to check for all possible errors. And letting software run in a state that the developer did not expect is always a bad idea.
I have seen this happen very often: some batch encounters an error and just keeps doing “something”. The work to clean up this mess is almost always much worse than having a clear error in the first place.
I would respectively disagree – it’s always a matter of perspective and usage. Depending on the script, setting ErrorActionPreference to Stop can absolutely cause all kinds of noise, bloated problems.
However, for troubleshooting purposes, sometimes it does help to set EA to Stop.. it’s very circumstantial.
David F.
There is a reason that proper programming languages do not have the concept of non-terminating errors: it leads to unforeseeable results too often. Because errors tend to occur where nobody is expecting them.
During 20 years of development and administration, I have met only about a handful of edge-cases where I actually used an empty catch-block (and commented the reason).
But I have seen a gazillion scripts ignoring errors and causing real damage afterwards. E.g. one of those scripts had the task of cleaning up a directory. The dev ignored errors, since the script could encounter files in use and should just leave them. But one time it failed in determining the path itself and continued with $null as a value. The developer did not expect issues there. But now, his script deleted everything in the default-path, which was the user’s home-folder.
A very good practice in software development (aside from gaming) is to fail as early as possible. This applies to script development as well.
And if a developer does really have one of the edge-cases at his hands, where he wants to continue, he can always decide to do so by using an empty catch-block. But this should only be done after careful consideration and not as default-behaviour.
Ignoring errors by default was just a stupid decision by MS.
But there’s a huge difference between professional programmers and scripting admins. Script writers aren’t always looking at idempotency. And as one of the scripting admins.. if I’m doing something that starts deleting things, I do put in lots of checks, and force error checking.
But, bad script design is bad script design 🙂
David F.