If you are having prior software development experience, for exception handling we generally use PowerShell Try-Catch-Finally block. PowerShell also support try-catch-finally block to handle or respond to terminating errors in PowerShell script.
In PowerShell 2.0, common parameters related to error handling available are: -ErrorAction and -ErrorVariable
In this blog post, I will explain you about using –ErrorAction and –ErrorVariable parameter in PowerShell with examples.
The PowerShell ErrorAction parameter allows you to specify how to respond or handle terminating errors or actions to take if command fails.
ErrorAction parameter has below options available to handle execution of command if error raised
- Continue
- Ignore
- Inquire
- SilentlyContinue
- Stop
- Suspend
Let’s understand each of ErrorAction PowerShell options with examples
-ErrorAction Continue
ErrorAction PowerShell parameter, it basically override the $ErrorActionPreference in Windows PowerShell.
$ErrorActionPreference variable responds to which action to take in case of error raised.
using PowerShell ErrorAction parameter, it default uses continue preference. It means that in the event of error raised, its output will be written to host and script will be able to continue.
Lets consider an example to stop process RabbitMQ and handle any error produced using ErrorAction PowerShell parameter
PS C:> Stop-Process -Name RabbitMQ -ErrorAction Continue; Write-Host "Execute second command";
In the above example, Stop-Process cmdlet takes RabbitMQ process name and try to stop it. As it cannot find a process with given name, it throws exception.
Error raised is output to host and using –ErrorAction continue option, it continue with execution for second command.
It converts terminating errors to non-terminating errors to continue with execution and write output to host as given below
Do you know: How to use cat command in windows!
PowerShell -ErrorAction Ignore
PowerShell ErrorAction Ignore option does not produce any error message and write any error output on host and continue with execution.
Using -ErrorAction Ignore
option no errors will be updated in PowerShell $Error variable (automatic variable).
Lets consider same example to stop RabbitMQ process. We will use -ErrorAction Ignore option to ignore any error message and continue with execution of second command.
PS C:> Stop-Process -Name RabbitMQ -ErrorAction Ignore; Write-Host "Execute second command";
Output of above command is as below
PowerShell Tip: How to add newline to string or variable?
-ErrorAction Inquire
PowerShell ErrorAction Inquire option produce an error and prompt user to confirm actions to take
a. Yes b. Yes to All c. Halt Command d. Suspend
Based on users action, it decide to continue with execution or halt or suspend it.
Let’s consider above example to stop RabbitMQ process using Stop-Process. We will use -ErrorAction Inquire option to let user to confirm action in the case of error produced
PS C:>> Stop-Process -Name RabbitMQ -ErrorAction Inquire; Write-Host "Execute second command";
Output of the above command with user selection as Yes
If the user select Halt Command, it will write error message on Host and halt further execution. If the user select Suspend option, it will suspend the current execution.
Cool Tip: Replace text in string using PowerShell!
PowerShell -ErrorAction SilentlyContinue
–ErrroAction SilentlyContinue in PowerShell silently continue with the execution of code if the part of code does not work or have non-terminating errors.
PowerShell ErrorAction SilentlyContinue
option silence non-terminating errors and continue execution. Error will updated in PowerShell Error variable (automatic variable).
Let’s consider example to stop process name as RabbitMQ using Stop-Process. We will use -ErrorAction SilentlyContinue option to silence non-terminating errors and execution of second command.
PS C:>>> Stop-Process -Name RabbitMQ -ErrorAction SilentlyContinue; Write-Host "Execute second command";
Output of the above command is as below
Cool Tip: Get-ChildItem cmdlet – Search for files in PowerShell!
-ErrorAction Stop
PowerShell ErrorAction Stop option display error message on host and stop further execution of code. It terminates the code.
Lets consider similar example given above to find process name as RabbitMQ. We will use -ErrorAction Stop option to check execution.
PS C:>>> Stop-Process -Name RabbitMQ -ErrorAction Stop; Write-Host "Execute second command";
The output of the above command is as below
-ErrorAction Suspend
PowerShell -ErrorAction Suspend option available in PowerShell workflows. If error raised in command, workflows will get suspended.
Cool Tip: Best way to use PowerShell Get-ChildItem cmdlet!
PowerShell ErrorVariable Parameter
When you run PowerShell command, in the event of error raised, error will added into PowerShell $Error automatic variable.
Using PowerShell ErrorVariable parameter, you can specify your own variable name to store error message.
PowerShell ErrorVariable will overwrite error message value to variable name. If you want to append error in variable name, use + in front of variable name. It will append error message.
Let’s consider an example to illustrate -ErrroVariable in PowerShell. We will use same example given above to stop process name as RabbitMQ. As command not able to find process, it will raise error.
Using -ErrorVariable PowerShell, we will store error message in processError variable name as given below
PS C:>>> Stop-Process -Name RabbitMQ -ErrorVariable processError;
In the above command, it will add error message on PowerShell Error variable as well as on to processvariable variable.
If we print processError variable name, it will write error output on host as given below
Cool Tip: Get-FileHash cmdlet – Get MD5 checksum in PowerShell!
You can make the use of -ErrorAction and -ErrorVariable together to silent non-terminating errors and add error message in variable to take further action
Using the same example given above with -ErrorAction SilentlyContinue option and -ErrorVariable to store error message in processError
variable.
PS C:>>> Stop-Process -Name RabbitMQ -ErrorAction SilentlyContinue -ErrorVariable processError; PS C:>>> $processError
In the above code, SilentlyContinue option in PowerShell silent non-terminating errors and -ErrorVariable parameter add error message to processError variable as given below
Cool Tip: Read more about PowerShell $PSScriptRoot Automatic Variable!
Conclusion
I hope you may have like above detailed article about PowerShell ErrorAction parameter and -ErrorVariable PowerShell parameter.
Using different options available with -ErrorAction, we can handle error message in code.
You can find more topics about PowerShell Active Directory commands and PowerShell basics on ShellGeek home page.
An Introduction to Error Handling in PowerShell
Originally by Keith Babinec, published a MSDN.
Current version is moved to by blog here
Today’s post (and this blog’s inaugural post!) is An Introduction to Error Handling in PowerShell. We will discuss error types, the $error
variable, error action preferences, try/catch blocks, and $lastexitcode.
The first requirement is to understand the types of errors that can occur during execution.
Terminating vs. Non-Terminating Errors:
- Terminating Error: A serious error during execution that halts the command (or script execution) completely. Examples can include non-existent cmdlets, syntax errors that would prevent a cmdlet from running, or other fatal errors.
- Non-Terminating Error: A non-serious error that allows execution to continue despite the failure. Examples include operational errors such file not found, permissions problems, etc.
-
Update 12/13/2013: Writing a cmdlet?
For further information regarding how a cmdlet should determine when to throw a terminating error or non-terminating error, MSDN has a nice explanation here. -
Update 12/13/2013: Want to know if an error you encountered is terminating or non-terminating?
Check to see if the error behavior is affected by changing the $ErrorActionPreference.
According to the MSDN documentation here,
«Neither $ErrorActionPreference nor the ErrorAction common parameter affect how Windows PowerShell responds to terminating errors (those that stop cmdlet processing).».
The $error
variable:
When either type of error occurs during execution, it is logged to a global variable called $error
. This variable is a collection of PowerShell Error Objects with the most recent error at index 0.
On a freshly initialized PowerShell instance (no errors have occurred yet) the $error
variable is ready and waiting as an empty collection:
PS C:> $error.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True ArrayList System.Object
PS C:> $error.Count
0
In the next snippet I have executed a cmdlet that doesn’t exist, throwing an error. If we grab the count on $error
, you will notice it has increased to one item.
Dumping that object to the pipeline by accessing $error[0]
just prints the error we already saw, right back at us.
PS C:> ThisCmdlet-DoesNotExist
The term 'ThisCmdlet-DoesNotExist' is not recognized as the name of a cmdlet, f
unction, script file, or operable program. Check the spelling of the name, or i
f a path was included, verify that the path is correct and try again.
At line:1 char:24
+ ThisCmdlet-DoesNotExist <<<<
+ CategoryInfo : ObjectNotFound: (ThisCmdlet-DoesNotExist:String)
[], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
PS C:> $error.Count
1
PS C:> $error[0]
The term 'ThisCmdlet-DoesNotExist' is not recognized as the name of a cmdlet, f
unction, script file, or operable program. Check the spelling of the name, or i
f a path was included, verify that the path is correct and try again.
At line:1 char:24
+ ThisCmdlet-DoesNotExist <<<<
+ CategoryInfo : ObjectNotFound: (ThisCmdlet-DoesNotExist:String)
[], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
There is more available to us than just what is immediately visible.
The ErrorRecord
is a rich object that contains many useful properties to explore. Try piping the error to get-member
(aliased by gm
) to see what options we have available to us:
PS C:> $error[0] | gm
TypeName: System.Management.Automation.ErrorRecord
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetObjectData Method System.Void GetObjectData(System.Runtim...
GetType Method type GetType()
ToString Method string ToString()
CategoryInfo Property System.Management.Automation.ErrorCateg...
ErrorDetails Property System.Management.Automation.ErrorDetai...
Exception Property System.Exception Exception {get;}
FullyQualifiedErrorId Property System.String FullyQualifiedErrorId {get;}
InvocationInfo Property System.Management.Automation.Invocation...
PipelineIterationInfo Property System.Collections.ObjectModel.ReadOnly...
TargetObject Property System.Object TargetObject {get;}
PSMessageDetails ScriptProperty System.Object PSMessageDetails {get=& {...
For details on what each property member provides, visit the ErrorRecord MSDN documentation. A couple important highlights:
$error[0].InvocationInfo
provides details about the context which the command was executed, if available.
$error[0].Exception
contains the original exception object as it was thrown to PowerShell.
If we explore that object (also piped to get-member) we can see important items to pull up like stack trace, source, HResult
, InnerException
, etc.
Diving into the exception object itself ($error[0].Exception
) can provide very important diagnostic details not immediately visible on the top level error record.
This is especially useful in troubleshooting third party cmdlets!
PS C:> $error[0].Exception
The term 'ThisCmdlet-DoesNotExist' is not recognized as the name of a cmdlet, f
unction, script file, or operable program. Check the spelling of the name, or i
f a path was included, verify that the path is correct and try again.
PS C:> $error[0].Exception | gm
TypeName: System.Management.Automation.CommandNotFoundException
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetBaseException Method System.Exception GetBaseException()
GetHashCode Method int GetHashCode()
GetObjectData Method System.Void GetObjectData(System.Runt...
GetType Method type GetType()
ToString Method string ToString()
CommandName Property System.String CommandName {get;set;}
Data Property System.Collections.IDictionary Data {...
ErrorRecord Property System.Management.Automation.ErrorRec...
HelpLink Property System.String HelpLink {get;set;}
InnerException Property System.Exception InnerException {get;}
Message Property System.String Message {get;}
Source Property System.String Source {get;set;}
StackTrace Property System.String StackTrace {get;}
TargetSite Property System.Reflection.MethodBase TargetSi...
WasThrownFromThrowStatement Property System.Boolean WasThrownFromThrowStat...
PS C:> $error[0].Exception.StackTrace
at System.Management.Automation.CommandDiscovery.LookupCommandInfo(String co
mmandName, CommandOrigin commandOrigin)
at System.Management.Automation.CommandDiscovery.LookupCommandProcessor(Stri
ng commandName, CommandOrigin commandOrigin, Nullable`1 useLocalScope)
at System.Management.Automation.ExecutionContext.CreateCommand(String comman
d)
at System.Management.Automation.CommandNode.CreateCommandProcessor(Int32& in
dex, ExecutionContext context)
at System.Management.Automation.CommandNode.AddToPipeline(PipelineProcessor
pipeline, ExecutionContext context)
at System.Management.Automation.PipelineNode.Execute(Array input, Pipe outpu
tPipe, ArrayList& resultList, ExecutionContext context)
at System.Management.Automation.StatementListNode.ExecuteStatement(ParseTree
Node statement, Array input, Pipe outputPipe, ArrayList& resultList, ExecutionC
ontext context)
Error Action Preference:
PowerShell halts execution on terminating errors, as mentioned before. For non-terminating errors we have the option to tell PowerShell how to handle these situations. This is where the error action preference comes in. Error Action Preference allows us to specify the desired behavior for a non-terminating error; it can be scoped at the command level or all the way up to the script level.
Available choices for error action preference:
SilentlyContinue
– error messages are suppressed and execution continues.Stop
– forces execution to stop, behaving like a terminating error.Continue
— the default option. Errors will display and execution will continue.Inquire
– prompt the user for input to see if we should proceed.Ignore
– (new in v3) – the error is ignored and not logged to the error stream. Has very restricted usage scenarios.
Example: Set the preference at the script scope to Stop
, place the following near the top of the script file:
$ErrorActionPreference = "Stop"
Example: Set the preference at the cmdlet level to Inquire
, add error action switch (or alias EA
):
get-childitem "G:FakeFolder" -ErrorAction "Inquire"
get-childitem "G:FakeFolder" -ea "Inquire"
Try
/Catch
/Finally
Blocks:
The Try
, Catch
, and Finally
statements allow us to control script flow when we encounter errors.
The statements behave similar to the statements of the same name found in C# and other languages.
The behavior of try/catch is to catch terminating errors (exceptions).
This means Non-terminating (operational) errors inside a try block will not trigger a Catch*
.
If you would like to catch all possible errors (terminating and non-terminating) – then simply set the error action preference to Stop
.
Remember that Stop
error action forces a non-terminating error to behave like a terminating error, which means it can then be trapped in a catch block.
Here is an example:
- Update 12/13/2013: In almost all cases, non-terminating errors will not trigger a catch. However I did recently observe a situation where a non-terminating error did trigger a catch block. It wasn’t from a cmdlet, but an exception generated from directly calling a method on a .net object. So keep in mind that behavior might be possible.
try
{
<#
Add dangerous code here that might produce exceptions.
Place as many code statements as needed here.
Non-terminating errors must have error action preference set to Stop to be caught.
#>
write-host "Attempting dangerous operation"
$content = get-content -Path "C:SomeFolderThis_File_Might_Not_Exist.txt" -ErrorAction Stop
}
catch
{
<#
You can have multiple catch blocks (for different exceptions), or one single catch.
The last error record is available inside the catch block under the $_ variable.
Code inside this block is used for error handling. Examples include logging an error,
sending an email, writing to the event log, performing a recovery action, etc.
In this example I'm just printing the exception type and message to the screen.
#>
write-host "Caught an exception:" -ForegroundColor Red
write-host "Exception Type: $($_.Exception.GetType().FullName)" -ForegroundColor Red
write-host "Exception Message: $($_.Exception.Message)" -ForegroundColor Red
}
finally
{
<#
Any statements in this block will always run even if errors are caught.
This statement block is optional. Normally used for cleanup and
releasing resources that must happen even under error situations.
#>
write-host "Finally block reached"
}
You can also have Catch
blocks that will only trap specific exceptions.
The reason for doing this is so you can add different handlers for each possible failure condition that you may encounter.
Some exceptions you may just want to log and exit, but others you may have a recovery action for.
Here is a Catch
statement that would trap a specific Exception
type.
The Exception
type is displayed in brackets after the catch statement:
catch [System.Management.Automation.ItemNotFoundException]
{
# catching specific exceptions allows you to have
# custom actions for different types of errors
write-host "Caught an ItemNotFoundException" -ForegroundColor Red
}
You might be wondering how I found the type name for the previous exception.
The possible exceptions for cmdlets are not usually documented, so you may need to find them on your own.
When an exception occurs you can look up the error in the $error
collection, or while inside a catch block under the $_
variable.
Call the GetType()
method on the base exception to extract the FullName
property.
Like shown here:
PS C:> $error[0].Exception.GetType().FullName
System.Management.Automation.ItemNotFoundException
Handling Errors from non-PowerShell processes:
What happens when your script needs to run an external process from PowerShell and you want to know if it succeeded?
An example would be a cmdline tool such as robocopy.exe
.
It’s an external application that returns an exit code upon completion.
But since it is an external process, its errors will not be caught in your try/catch blocks.
To trap this exit code utilize the $LastExitCode
PowerShell variable.
When the launched process exits, PowerShell will write the exit code directly to $LastExitCode
.
In most cases an exit code of 0 means success, and 1 or greater indicates a failure.
Check the external tool’s documentation to verify of course.
Here it is seen in action:
PS C:> robocopy.exe "C:DirectoryDoesNotExist" "C:NewDestination" "*.*" /R:0
-------------------------------------------------------------------------------
ROBOCOPY :: Robust File Copy for Windows
-------------------------------------------------------------------------------
Started : Sun Jun 09 18:42:09 2013
Source : C:DirectoryDoesNotExist\par Dest : C:NewDestination\par
Files : *.*
Options : *.* /COPY:DAT /R:0 /W:30
------------------------------------------------------------------------------
2013/06/09 18:42:09 ERROR 2 (0x00000002) Accessing Source Directory C:Directory
DoesNotExist\par The system cannot find the file specified.
PS C:> $lastexitcode
16
Для начала определимся, что такое обработка ошибок вообще. В общем случае ошибка — это поведение программы или скрипта, отличное от запланированного. Совсем избежать ошибок не очень возможно, поэтому надо предвидеть, где они могут возникнуть и писать код так, чтобы при возникновении ошибки можно было перехватить ее, проанализировать и определить дальнейшее поведение скрипта. Именно это обычно и подразумевается под обработкой ошибок.
В PowerShell ошибки делятся на два типа: прерывающие (Terminating) и непрерывающие (Non-Terminating). Как следует из названия, непрерывающие ошибки позволяют продолжить выполнение команды, тогда как при возникновении прерывающей ошибки дальнейшее продолжение выполнения команды невозможно. К примеру, у нас есть файл со списком служб, которые необходимо перезапустить следующей командой:
Get-Content -Path C:Filesservices.txt | Restart-Service
Предположим, что перезапуск одной из перечисленных служб по какой либо причине невозможен. Тем не менее можно продолжать выполнение задачи, поскольку остальные службы доступны и их можно перезапустить. Это пример непрерывающей ошибки.
А теперь представьте, что у нас нет прав на открытие этого файла, и соответственно прочитать список служб мы не можем. В этой ситуации продолжение работы невозможно, т.е. это прерывающая ошибка.
PowerShell позволяет обрабатывать оба эти типа ошибок. Большинство ошибок в PowerShell непрерывающие, и сегодня речь пойдет о том, как их обрабатывать.
Обработка непрерывающих ошибок
Для получения ошибки возьмем службу с ″оригинальным″ названием Service. Поскольку службы этой на сервере нет, то обращение к ней стабильно будет генерировать ошибку. Запросим данные о нескольких службах командой:
Get-Service service,spooler
Как видно из примера, PowerShell не нашел службу Service, о чем выдал ошибку и затем продолжил выполнение команды. Давайте разберемся, почему команда повела себя именно так и как это поведение изменить.
За поведение команды при возникновении ошибки отвечает параметр ErrorAction, который может принимать одно из пяти значений:
• Continue;
• SilentlyContinue;
• Stop;
• Ignore;
• Inquire.
Примечание. Еще у ErrorAction может быть значение Suspend. Но это значение может применяться только к рабочим процессам (workflows), поэтому в рамках данной статьи речь о нем не пойдет.
Значение Continue означает, что при возникновении ошибки информация об этом будет выведена на экран (отправлена в поток вывода Error) и добавлена в автоматическую переменную $Error, после чего выполнение команды будет продолжено. Надо сказать, что Continue — это действие, определенное в сеансе по умолчанию, поэтому его можно не указывать явно.
При значении SilentlyContinue информация об ошибке добавляется в переменную $Error, но не выводится на экран. При этом команда продолжает выполняться дальше, также как и в предыдущем случае.
Значение Stop останавливает дальнейшее выполнение команды при возникновении ошибки. И наоборот, значение Ignore полностью игнорирует возникновение ошибки, при этом не выводится сообщение на экран и не производится запись в $Error. Это значение появилось в PowerShell 3.0.
Inquire — наиболее интересное значение ErrorAction. Если задать это значение, то при возникновении ошибки предлагается на выбор несколько действий: продолжить (Yes), продолжить не смотря на эту и все последующие ошибки (Yes to All), остановить (Halt) или приостановить (Suspend) выполнение команды.
Самый необычный эффект дает Suspend, при выборе которого открывается параллельный сеанс (Nested Namespace). Определить его можно по значку >>. Nested Namespace представляет из себя дочерний процесс, в котором можно полноценно работать — выполнять команды, запускать скрипты и т.п. Этот режим удобно использовать для отладки скриптов, например можно по быстрому исправить причину ошибки и продолжить выполнение. Для выхода из Nested Namespace достаточно набрать exit и выбрать необходимое действие.
Примечание. У параметра ErrorAction есть алиас — EA. Кроме того, вместо названия параметра можно указывать числовые значения: 0 (SilentlyContinue), 1 (Stop), 2 (Continue), 3 (Inquire). Так например, вместо:
Get-Service service,spooler -ErrorAction SilentlyContinue
можно написать так:
Get-Service service,spooler -EA 0
Переменные для обработки ошибок
Как я уже говорил, если не указывать параметр ErrorAction, то для команды действует режим обработки ошибок, определенный в сеансе. Этот режим задается переменной $ErrorActionPreference, которая по умолчанию имеет значение Continue. При желании можно переопределить режим для всего сеанса, задав переменной $ErrorActionPreference нужное значение.
Все ошибки PowerShell сохраняет в автоматическую переменную $Error. Это глобальная переменная, которая представляет из себя массив строк, содержащий записи обо всех ошибках в текущем сеансе. Каждая новая ошибка добавляется в начало массива, соответственно для просмотра последней ошибки надо обратиться к самому первому элементу массива $Error[0].
$Error имеет свои свойства и методы, которые можно использовать. Например, посмотреть общее количество ошибок в текущем сеансе можно командой $Error.Count, а очистить список — командой $Error.Clear().
Переменная $Error не безразмерна, по умолчанию она хранит не более 256 ошибок. При превышении этого количества наиболее старые ошибки будут затираться. При необходимости количество записей в переменной $Error можно увеличить, изменив значение другой переменной $MaximumErrorCount.
Кроме $Error для хранения ошибок допускается задавать собственные переменные. Сделать это можно с помощью параметра ErrorVariable, например так:
Get-Service service,spooler -ErrorAction SilentlyContinue -ErrorVariable var
Обратите внимание, что имя переменной в команде задается без знака $, хотя в дальнейшем к ней обращаемся как к обычной переменной $var.
В отличие от глобальной переменной $Error заданные вручную переменные хранят только ошибки той команды, в которой они определены. Кроме того, по умолчанию эти переменные каждый раз перезаписываются и поэтому хранят только последнюю ошибку. Если вы хотите, чтобы новые ошибки добавлялись в переменную, не перезаписывая ее содержимое, то перед именем переменной надо поставить знак +, например +var.
Пока все, а в следующей части пойдет о способах обработки прерывающих ошибок.
- Introduction to Error Action in PowerShell
- Use the
-ErrorAction
Parameter in PowerShell - Setting Error Action Preferences in PowerShell
Whether we want to ignore error messages or terminate a script’s execution when an error occurs, Windows PowerShell has plenty of options for dealing with errors. This article will discuss multiple techniques in handling and suppressing errors.
Introduction to Error Action in PowerShell
Even though it is effortless to suppress Windows PowerShell errors, doing so isn’t always the best option (although it can be). If we carelessly tell PowerShell to hide errors, it can cause our script to behave unpredictably.
Suppressing error messages also makes troubleshooting and information gathering a lot more complicated. So tread lightly and be careful about using the following snippets that you will see in this article.
Use the -ErrorAction
Parameter in PowerShell
The most common method for dealing with errors is to append the -ErrorAction
parameter switch to a cmdlet. The -ErrorAction
parameter switch lets PowerShell tell what to do if the cmdlet produces an error.
Command:
Get-Service 'svc_not_existing' -ErrorAction SilentlyContinue
In the command above, we are querying for a service that doesn’t exist. Usually, PowerShell will throw an error if the service doesn’t exist.
Since we use the -ErrorAction
parameter, the script will continue as expected, like it doesn’t have an error.
Setting Error Action Preferences in PowerShell
If we need a script to behave in a certain way (such as suppressing errors), we might consider setting up some preference variables. Preference variables act as configuration settings for PowerShell.
We might use a preference variable to control the number of history items that PowerShell retains or force PowerShell to ask the user before performing specific actions.
For example, here is how you can use a preference variable to set the -ErrorAction
parameter to SilentlyContinue
for the entire session.
Command:
$ErrorActionPreference = 'SilentlyContinue'
There are many other error actions that we can specify for the ErrorAction
switch parameter.
Continue
: PowerShell will display the error message, but the script will continue to run.Ignore
: PowerShell does not produce any error message, writes any error output on the host, and continues execution.Stop
: PowerShell will display the error message and stop running the script.Inquire
: PowerShell displays the error message but will ask for confirmation first if the user wants to continue.SilentlyContinue
: PowerShell silently continues with code execution if the code does not work or has non-terminating errors.Suspend
: PowerShell suspends the workflow of the script.
As previously mentioned, the -ErrorAction
switch has to be used in conjunction with a PowerShell cmdlet. For instance, we used the Get-Process
cmdlet to demonstrate how the ErrorAction
switch works.
What is PowerShell Exception handling
I think the best definition of error or exception handling I can quote is the one coming from Wikipedia which reads:
Exception handling is the process of responding to the occurrence, during computation, of exceptions – anomalous or exceptional conditions requiring special processing – often changing the normal flow of program execution.
In other words exception handling is the art of pre-empting any unforeseen or unexpected situation which could arise during program or script execution. I chose word art on purpose as it takes time and practice to master it.
In the post I will got through error types, error action preference, the $Error variable, try/catch/finally blocks and will finally cover the $LastExitCode variable to trap errors generated outside PowerShell processes.
It seems a lot of material but Exception Handling is an essential part of any well written script, without it you risk to implement to quickly lose control of what your script did or did not.
I have broken down the post into sections to make navigation easier given the amount of content.
Exception Handling — An Example
Before diving error types I want to introduce a small example which hopefully will help illustrate pitfalls of a script not implementing exception handling.
Imagine we’ve been tasked with the creation of a script that will check a specific application folder and delete all temporary files an application is creating in it, script should run daily on a schedule.
# Define Application files path
$tempFilesPath = 'C:MyAppTemp1'
# Get all files
$tempFiles = Get-ChildItem -Path $tempFilesPath
# Remove files
foreach ($tempFile in $tempFiles)
{
Remove-Item -Path $tempFile
}
Write-Host 'Script execution complete!'
Once tested our script we schedule it and take on another task, unfortunately the user account under which the scheduled task runs has no permissions to access the folder so script won’t be able to complete successfully. As we implemented no proper exception handling we would find out about this only when files would start accumulating filing up the disk on the server.
This is a very simple example to show why you should always implement exception handling in your scripts.
Error Types
In PowerShell we have two error type Terminating Errors and Non-Terminating Errors which I describe in more details below.
Terminating Errors
A terminating error is a serious error that causes the command or script execution to halt completely.
Among terminating errors:
- A non existing cmdlet
- A syntax error that would prevent the cmdlet to correctly continue execution (Get-ChildItem -Path $null)
- Other fatal errors like for example a missing required parameter
Non-Terminating Errors
A non-terminating error, as the name implies, is a non serious error that will allow execution to continue.
Among non-terminating errors:
- File not found type of errors
- Permission problems
If you’re wondering error reporting is defined by the cmdlet developer and MSDN has more information about this.
Note: sure to remember difference between terminating and non-terminating errors as it is essential to proper exception handling in your code.
Error Action Preference
Now that we know more about error types in PowerShell it is time to talk about Error Action Preference.
We know that a terminating error will halt script execution but what of non-terminating errors? Short answer is we can tell PowerShell what to do when such errors are encountered through the $ErrorActionPreference variable.
The $ErrorActionPreference supports the following values:
- SilentlyContinue — Execution continues and any error message is suppressed
- Stop — Pretty self explanatory, it forces execution to top conceptually identical to a terminating error
- Continue — This is the default setting. Errors will be displayed and execution continue
- Inquire — As the name implies it will ask for user input to check if execution should proceed
- Ignore — Error is completely ignored and not logged to the error stream
To check $ErrorActionPreference value simply type the following:
# Print value
$ErrorActionPreference
# Output
Continue
You can of course change value of the $ErrorActionPreference variable both at the command level
# Set Error action to Inquire
Get-ChildItem Get-ChildItem 'C:Temp' -ErrorAction 'Inquire'
# Set Error action to Ignore
Get-ChildItem Get-ChildItem 'C:Temp' -ErrorAction 'Ignore'
Or at the script level
# Set Error action for the whole script
$ErrorActionPreference = 'Stop'
The same holds true for an interactive PowerShell session of course.
The $Error Variable
When an error occurs during execution, be it terminating or not, information is logged to a variable called $Error which is nothing else than an arraylist object
$Error.GetType()
# Output
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True ArrayList System.Object
When you start a new PowerShell session the variable will be of course empty but yet it will be initialized.
Let’s see how this works trying to run a cmdlet that does not exist:
# This does not exist
Get-MyCmdLet
# Get content of the $Error variable
$Error
Get-MyCmdLet : The term 'Get-MyCmdLet' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ Get-MyCmdLet
+ ~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-MyCmdLet:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
In the above snippet I’ve suppressed output of the inexistent cmdlet as it is the same contained in the $Error variable which logged the exception.
What if you have multiple errors in your session? The $Error variable will contain all of them with the most recent error on top, you can easily verify this via the count property
As the $Error variable is an Array you can always access last element specifying the index number like this
# Print latest error
$Error[0]
The ErrorRecord, the object type for the $Error variable, has many useful properties that we can access and use in our scripts, to list all of them you can use the following
$Error[0] | Get-Member
TypeName: System.Management.Automation.ErrorRecord
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetObjectData Method void GetObjectData(System.Runtime.Seria...
GetType Method type GetType()
ToString Method string ToString()
CategoryInfo Property System.Management.Automation.ErrorCateg...
ErrorDetails Property System.Management.Automation.ErrorDetai...
Exception Property System.Exception Exception {get;}
FullyQualifiedErrorId Property string FullyQualifiedErrorId {get;}
InvocationInfo Property System.Management.Automation.Invocation...
PipelineIterationInfo Property System.Collections.ObjectModel.ReadOnly...
ScriptStackTrace Property string ScriptStackTrace {get;}
TargetObject Property System.Object TargetObject {get;}
PSMessageDetails ScriptProperty System.Object PSMessageDetails {get=& {...
Among the various properties the two you I usually tend to use more are:
- $Error[0].Exception — Contains the original exception object as it was thrown to PowerShell
- $Error[0].InvocationInfo — Contains details about the context which the command was executed, if available
The former is handy to log exception thrown by scripts in my script log file the latter is useful when troubleshooting script execution to know what exactly went wrong and where.
But there is more, the Exception object hides some additional useful properties and methods that are not immediately visible.
The Hidden Secrets of $Error.Exception
Piping the $Error[0].Exception to the Get-Member cmdlet we can see there are many additional properties to the exception for example here’s what I can see from the exception thrown by the inexistent cmdlet
$Error[0].exception | Get-Member
TypeName: System.Management.Automation.CommandNotFoundException
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetBaseException Method System.Exception GetBaseException()
GetHashCode Method int GetHashCode()
GetObjectData Method void GetObjectData(System.Runtime.Ser...
GetType Method type GetType()
ToString Method string ToString()
CommandName Property string CommandName {get;set;}
Data Property System.Collections.IDictionary Data {...
ErrorRecord Property System.Management.Automation.ErrorRec...
HelpLink Property string HelpLink {get;set;}
HResult Property int HResult {get;set;}
InnerException Property System.Exception InnerException {get;}
Message Property string Message {get;}
Source Property string Source {get;set;}
StackTrace Property string StackTrace {get;}
TargetSite Property System.Reflection.MethodBase TargetSi...
WasThrownFromThrowStatement Property bool WasThrownFromThrowStatement {get...
As you can see in the above example we can access hidden information like StackTrace, InnerException or the Source.
It has to be noted that we don’t always need access to this level of information but it can be very useful in a troubleshooting scenario especially when dealing with 3rd party cmdlets or modules.
The try/catch/finally statements
With our newly acquired knowledge we’re now ready to dive deep into try/catch blocks that are the foundation of exception handling in PowerShell.
The try/catch/finally statements allows us to alter script execution flow and respond to any error the could be thrown by our code. Default behavior for try/catch/finally statement is to catch all terminating errors while any non-terminating error will be ignored by it.
Syntax is rather straightforward and can be summarized as:
- Try — Is the command we want PowerShell to execute
- Catch — Is the error condition we want to test for and take action on. We can specify multiple catch for different exceptions
- Finally any code in the finally block will always be executed no matter what. This block is optional and you can omit if you don’t plan to use it
Let’s see an example with our inexistent cmdlet once again
Try
{
# Will generate a temrinating error
Get-MyCmdlet -Path 'C:temp'
}
Catch
{
Write-Warning 'I could not run command!'
}
Finally
{
# Will always be executed
Write-Host 'Script Execution complete!'
}
The above is a very simple example of how you would use the try/catch statement but, as I wrote earlier, this will work only for terminating errors.
Take the following example:
try
{
$networkCard = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $Computername -Credential $Credential -Filter "IPEnabled = $True"
}
# Catch exception
catch [GetWMICOMException]
{
Write-Warning 'Error running command!'
}
Despite syntax being correct if there is an issue with the code in the try block execution will continue and code in the catch block will never be executed. Reason for this is that Get-WmiObject throws non-terminating errors.
Solution to the above issue lies in the $ErrorActionPreference variable which, as I wrote earlier, can be set to any of the supported values according to our need.
Here is the rewritten example:
try
{
# Update variable
$ErrorActionPreference = 'Stop'
$networkCard = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $Computername -Credential $Credential -Filter "IPEnabled = $True"
}
# Catch exception
catch [GetWMICOMException]
{
Write-Warning 'Error running command!'
}
Finally
{
# Set value back to default value
$ErrorActionPreference = 'Continue'
}
The above code will update the $ErrorActionPreference variable so any error will be treated as terminating allowing us to catch it, in the finally block we set value back to its default value.
The example also illustrate another important concept which is catching a specific exception which can be useful when we want to take different actions depending on the exception thrown.
To find the specific exception we use again the Get-Member cmdlet applied to the exception object
$Error[0].Exception | Get-Member
TypeName: System.Management.Automation.CommandNotFoundException
The above is from the previous example with the inexistent cmdlet but it is exactly how it works with any cmdlet, the TypeName will contain the exception type/name.
Note: If you are interested in knowing more MSDN has great documentation on the Error Record class and how to use it.
Exception Handling — A Better Example
At the beginning of the post I wrote an example to illustrate how proper exception handling is very important in any script or automation project.
Here’s the code rewritten using techniques and concept we covered in the post
# Define Application files path
$tempFilesPath = 'C:MyAppTemp1'
$isException = $false
try
{
# Get all files
$tempFiles = Get-ChildItem -Path $tempFilesPath
}
catch [ItemNotFoundException]
{
<#
Any corrective action code here
#>
$isException = $true
}
finally
{
if ($isException)
{
<#
Code to notify admins here
#>
}
else
{
# Log success
}
}
# Remove files
foreach ($tempFile in $tempFiles)
{
try
{
Remove-Item -Path $tempFile
}
catch
{
<#
Any corrective action code here
#>
$isException = $true
}
finally
{
if ($isException)
{
<#
Code to notify admins here
#>
}
else
{
# Log success
}
}
}
Write-Host 'Script execution complete!'
Closing Thoughts
In the post we’ve illustrated importance of exception handling and how to implement it in PowerShell. It does not matter how simple or short the script you are writing is you should always try to implement proper exception handling to save yourself some work when things don’t go the way you planned them.
It happens: you run a script or execute a command, and something doesn’t work quite right. You get an ugly red error. Now what?
There are many ways to handle this. When you’re sitting at the console, frequently it comes down to simply reading the error message and figuring out what you forgot or mistyped. These are often the easiest errors to deal with just for the fact that they’re interactive by nature, so you get the opportunity to try other things until you get the results you’re looking for before proceeding.
Things get a lot more complicated, however, when you’re writing a script, especially one that is meant to run without someone sitting at a console to see the errors. At least if the script is being run manually, the person sitting at the console will be able to see that something did go wrong; when it’s unattended, though, frequently you wind up losing valuable clues as to what went wrong, so you need to think about how your script could fail and account for that ahead of time with error handling.
What follows is a quick primer on the basics to get you started in error handling. I plan to write a much more detailed series on this topic in the future.
Stream 2: Error output
Without going into too much detail, it’s important to understand that errors are not passed along standard output (stream 1, basically what goes through the pipeline). This is a good thing, but can be frustrating at first when you’re trying to figure out how to capture an error (for example, sending it out to a file to log it) and find that the ugly red text doesn’t seem to go anywhere. It’s a good thing because if it sent errors out the primary stream, every following part of the pipeline would try to process the error and throw its own errors, and that would just be a huge mess.
You can get around this by using the alternate stream pipe to send errors wherever you want.
Example:
One thing to note here: all you’ll get is the text that shows on the screen. You can’t treat this like the pipeline (as in, you can’t send it to another cmdlet to do additional processing on it). There’s a lot more detail available and ways you can programmatically react to errors.
For more details on streams, see this excellent write up: Understanding Streams, Redirection, and Write-Host in PowerShell
$Error
The automatic variable $Error is one of the most basic parts of PowerShell’s error handling system. One thing to remember about it: because it’s an automatic variable, you cannon use it for something else (this caused me some headaches early on while I was getting the handle of this, as I was trying to track errors using $Error, not realizing what it was yet; I mention this so you won’t make the same mistake I did).
Every time something is sent to stream 2 (the error stream), it is also stored as an exception object in the $Error variable. Note: these are actual objects in the sense that they have .NET types, and there are a lot of .NET exception types available. Going into detail on that is beyond the scope of this post, but there is a lot of detail on each exception, including important things like TargetObject and StackTrace. You can see these by generating an error and looking at everything that is in it. Also note: the $Error variable doesn’t just contain the last error; it’s actually an array of all of the errors that have happened in your current session (up to a configurable limit set by $MaximumErrorCount, 256 by default) with the most recent always being at the first, or 0, index.
Example:
ErrorAction
Every cmdlet has a built in parameter called ErrorAction specifically to tell PowerShell what to do if that cmdlet puts anything into stream 2. If nothing is specified, it will use the default for your session, which is configured with the variable $ErrorActionPreference, or the default for that cmdlet or exception (some exceptions override the default behavior). By default, this action is Continue, which adds the error to the $Error variable and displays the text (in red (by default; this can be changed)) in the console alongside other output.
Here are the main ErrorAction values to be concerned about and what they do:
- Continue (default): Adds to $Error and displays in console, continues execution
- SilentlyContinue: Same as Continue without displaying in console
- Ignore: Does not add to $Error or display in console; acts as if the error never happened
- Stop: Same as Continue, but halts further execution; note: this is necessary for try/catch to work (more on that later)
It is strongly recommended that you do not use SilentlyContinue or Ignore to correct for actual errors, and managing this with the $ErrorActionPreference variable is bad practice. SilentlyContinue and Ignore are useful, however, when errors are both expected and don’t need to be handled or logged for whatever reason.
Write-Error and throw
When writing a script or advanced cmdlet, you might want to create your own error messages. I won’t go into details on this other than to let you know they’re here, and one major difference between using Write-Error and throw: Write-Error, by default, respects $ErrorActionPreference, while throw always generates a halting error (same as -ErrorAction Stop).
Try/Catch/Finally
In writing scripts and cmdlets, this is the most useful logical structure for handling errors that come along. If you’re doing something that has a risk of failure (for example: reading from a file that may not be there), you probably want to have your scripts handle problems on their own if possible (for example: if the file isn’t there, send an email letting someone know).
Sometimes these potential errors can be avoided altogether by checking if everything is in the correct state before proceeding (example: check to see if the file is there before trying to read from it), but this isn’t always possible or easy to do and might add a lot of additional overhead to your script. My examples here don’t need a Try/Catch/Finally block, but they’re easy enough to understand.
Basically, once you’ve identified something that can go wrong and trow an error, you add that code into a Try section (with ErrorAction set to Stop to trigger the system to execute the Catch section), and you add the handling code in the Catch section.
A really important point to understand is that you have access to the error object that caused the Catch section to execute within the Catch. It is added to the $_ auto variable. Note that it’s identical to what will be in $Error[0] immediately after getting the error on the console (and it will also still be added to $Error), so manually triggering the error and playing with $Error[0] is a great way to test what you’ll have available to work with in your Catch section.
The Finally section is not as commonly used. It executes regardless of what happens in the Try and Catch sections, so even if an error is thrown, it will execute. As an example, this can be useful when connecting to a system where you need to close the connection when you’re done, and you want to make sure it happens even if the work your script was supposed to complete caused an error to be thrown.
Note that a Try section must be followed by a Catch and/or Finally section, so you can do Try/Catch, Try/Catch/Finally, or Try/Finally.
Here’s an example (contrived, but shows how it works):
Conclusion
These are the basic building blocks of PowerShell’s excellent error handling system. If you are writing scripts or cmdlets, you should be using at least some of these. This primer should, hopefully, give you enough to get started.
Additional reading:
- Get-Help about_Automatic_Variables
- Get-Help about_Throw
- Get-Help Write-Error
- Get-Help about_Try_Catch_Finally
Have you ever run a script or a PowerShell cmdlet and get confronted with a screaming wall of text – in red – like the one shown below?
Not a reader? Watch this related video tutorial!
Not seeing the video? Make sure your ad blocker is disabled.
Errors can become overwhelming and confusing. And most of all, errors are often hard to read, which makes determining what and where the script went wrong near impossible.
Luckily, you have some options in PowerShell to make this better through error handling. Using error handling, errors can be filtered and displayed in such a way that it’s easier to make sense of. And, understanding the error makes it easy to add more logic to error handling.
In this article, you will learn about errors in PowerShell and how they can be intercepted to perform error handling using the PowerShell Try Catch
blocks (and finally
blocks).
Understanding How Errors Work in PowerShell
Before diving into error handling, let’s first cover a few concepts around errors in PowerShell. Understanding errors can lead to better error handling strategies.
The $Error
Automatic Variable
In PowerShell, there are a lot of automatic variables, and one of them is the $Error
automatic variable. PowerShell uses the $Error
variable to store all errors that are encountered in the session. The $Error
variable is an array of errors sorted by most recent.
When you first open a PowerShell session, the $Error
variable is empty. You can check it so by calling the $Error
variable.
As you can see, the $Error
variable starts off empty. But, once an error is generated, the error will be added and stored into the $Error
variable.
In the example below, the error is generated by deliberately getting a service name that does not exist.
PS> Get-Service xyz
PS> $Error
PS> $Error.Count
As you can see from the output above, the generated error was added to the $Error
variable.
The $Error variable contains a collection of errors generated in the PowerShell session. Each error can be access by calling its array position. The latest error will always be at index 0.
For example, the latest error can be retrieved using
$Error[0]
.
The $Error
Object Properties
Since everything in PowerShell is an object, the $Error
variable is an object, and objects have properties. By piping the $Error
variable to the Get-Member
cmdlet, you should see the list of the properties available.
To determine the reason for the error, you can view the content of the InvocationInfo
property using the command below.
Now, you could do the same with the other properties and discover what other information you can find!
Terminating Errors
Terminating errors stop the execution flow when it is encountered by PowerShell vs non-terminating errors. There are several ways a terminating error can occur. One example is when you call a cmdlet with a parameter that does not exist.
As you’ll from the screenshot below, when the command Get-Process notepad
runs, the command is valid, and the details of the notepad process are displayed.
But, when a parameter that does not exist is used like Get-Process notepad -handle 251
, the cmdlet displays an error that the handle
parameter is not valid. Then, the cmdlet exits without showing the details of the notepad
process.
Non-Terminating Errors
Non-terminating errors are errors that do not stop the execution of the script or command. For example, check out the code below. This code gets the list of file names from the fileslist.txt file. Then, the script goes through each file name, read the contents of each file, and outputs it on the screen.
$file_list = Get-Content .filelist.txt
foreach ($file in $file_list) {
Write-Output "Reading file $file"
Get-Content $file
}
The contents of the filelist.txt file are the file names shows in the list below.
File_1.log
File_2.log
File_3.log
File_4.log
File_5.log
File_6.log
File_7.log
File_8.log
File_9.log
File_10.log
But what if File_6.log didn’t actually exist? When you run the code, you’d expect an error will happen because the script cannot find the File_6.log. You’ll see a similar output shown below.
As you can see from the screenshot of the result above, the script was able to read the first five files in the list, but when it tried to read the file File_6.txt, an error is returned. The script then continued to read the rest of the files before exiting. It did not terminate.
The $ErrorActionPreference
Variable
So far, you’ve learned about the terminating and non-terminating errors and how they differ from each other. But, did you know that a non-terminating error can be forced to be treated as a terminating error?
PowerShell has a concept called preference variables. These variables are used to change how PowerShell behaves many different ways. One of these variables is called $ErrorActionPreference
.
The $ErrorActionPreference
variable is used to change the way PowerShell treats non-terminating errors. By default, the $ErrorActionPreference
value is set to Continue
. Changing the value of the $ErrorActionPreference
variable to STOP
forces PowerShell to treat all errors as terminating errors.
Use the code below to change the $ErrorActionPreference
value.
$ErrorActionPreference = "STOP"
To learn more about other valid $ErrorActionPreference variable values, visit PowerShell ErrorActionPreference.
Now, refer back to the example used in the Non-Terminating Errors section in this article. The script can modified to include the change in $ErrorActionPreference
like the code shown below:
# Set the $ErrorActionPreference value to STOP
$ErrorActionPreference = "STOP"
$file_list = Get-Content .filelist.txt
foreach ($file in $file_list) {
Write-Output "Reading file $file"
Get-Content $file
}
Running the modified code above will behave differently than before when the $ErrorActionPreference
value is set to the default value of Continue
.
$ErrorActionPreference
variableAs you can see from the screenshot of the result above, the script was able to read the first five files in the list, but when it tried to read the file File_6.txt, an error is returned because the file was not found. Then, the script terminated, and the rest of the files are not read.
The
$ErrorActionPreference
value is only valid in the current PowerShell session. It resets to the default value once a new PowerShell session is started.
The ErrorAction
Common Parameter
If the $ErrorActionPreference
value is applied to the PowerShell session, the ErrorAction
parameter applies to any cmdlet that supports common parameters. The ErrorAction
parameter accepts the same values that the $ErrorActionPreference
variable does.
The ErrorAction
parameter value takes precedence over the $ErrorActionPreference
value.
Let’s go back and use the same code in the previous example. But, this time, the ErrorAction
parameter is added to the Get-Content
line.
# Set the $ErrorActionPreference value to default (CONTINUE)
$ErrorActionPreference = "CONTINUE"
$file_list = Get-Content .filelist.txt
foreach ($file in $file_list) {
Write-Output "Reading file $file"
# Use the -ErrorAction common parameter
Get-Content $file -ErrorAction STOP
}
After running the modified code, you’ll see that even though the $ErrorActionPreference
is set to Continue
, the script still terminated once it encountered an error. The script terminated because the PowerShell ErrorAction
parameter value in Get-Content
is set to STOP
.
ErrorAction
parameterUsing PowerShell Try Catch Blocks
At this point, you’ve learned about PowerShell errors and how the $ErrorActionPreference
variable and PowerShell ErrorAction
parameters work. Now, it’s time you learn about the good stuff – the PowerShell Try Catch Finally
blocks.
PowerShell try catch
blocks (and optional finally block
) are a way to cast a net around a piece of code and catch any errors that return.
The code below shows the syntax of the Try
statement.
try {
<statement list>
}
catch [[<error type>][',' <error type>]*]{
<statement list>
}
finally {
<statement list>
}
The Try
block contains the code that you want PowerShell to “try” and monitor for errors. If the code in the Try
block encounters an error, the error is added to the $Error
variable and then passed to the Catch
block.
The Catch
block contains the actions to execute when it receives an error from the Try
block. There can be multiple Catch
blocks in a Try
statement.
The Finally
block contains that code that will at the end of the Try
statement. This block runs whether or not an error was uncounted.
Catching Non-Specific Errors (Catch-All) with PowerShell ErrorAction
A simple Try
statement contains a Try
and a Catch
block. The Finally
block is optional.
For example, to catch a non-specific exception, the Catch
parameter should be empty. The example code below is using the same script that was used in the The $ErrorActionPreference Variable section but modified to use the Try Catch
blocks.
As you can see from the code below, this time, the foreach
statement is enclosed inside the Try
block. Then, a Catch
block contains the code to display the string An Error Occurred
if an error happened. The code in the Finally
block just clears the $Error
variable.
$file_list = Get-Content .filelist.txt
try {
foreach ($file in $file_list) {
Write-Output "Reading file $file"
Get-Content $file -ErrorAction STOP
}
}
catch {
Write-Host "An Error Occured" -ForegroundColor RED
}
finally {
$Error.Clear()
}
The code above, after running in PowerShell, will give you this output shown below.
The output above shows that the script encountered an error, ran the code inside the Catch
block, and then terminated.
The error was handled, which was the point of error handling. However, the error displayed was too generic. To show a more descriptive error, you could access the Exception
property of the error that was passed by the Try
block.
The code below is modified, specifically the code inside the Catch
block, to display the exception message from the current error that was passed down the pipeline – $PSItem.Exception.Message
$file_list = Get-Content .filelist.txt
try {
foreach ($file in $file_list) {
Write-Output "Reading file $file"
Get-Content $file -ErrorAction STOP
}
}
catch {
Write-Host $PSItem.Exception.Message -ForegroundColor RED
}
finally {
$Error.Clear()
}
This time, when the modified code above is run, the message displayed is a lot more descriptive.
Catching Specific Errors
There are times when a catch-all error handling is not the most appropriate approach. Perhaps, you want your script to perform an action that is dependent on the type of error that is encountered.
How do you determine the error type? By checking the TypeName
value of the Exception
property of the last error. For example, to find the error type from the previous example, use this command:
$Error[0].Exception | Get-Member
The result of the code above would look like the screenshot below. As you can see, the TypeName
value is displayed – System.Management.Automation.ItemNotFoundException
.
Now that you know the error type that you need to intercept, modify the code to catch it specifically. As you see from the modified code below, there are now two Catch
blocks. The first Catch
block intercepts a specific type of error (System.Management.Automation.ItemNotFoundException
). In contrast, the second Catch
block contains the generic, catch-all error message.
$file_list = Get-Content .filelist.txt
try {
foreach ($file in $file_list) {
Write-Output "Reading file $file"
Get-Content $file -ErrorAction STOP
}
}
catch [System.Management.Automation.ItemNotFoundException]{
Write-Host "The file $file is not found." -ForegroundColor RED
}
catch {
Write-Host $PSItem.Exception.Message -ForegroundColor RED
}
finally {
$Error.Clear()
}
The screenshot below shows the output of the modified code above.
Conclusion
In this article, you’ve learned about errors in PowerShell, its properties, and how you can determine an error’s specific type. You’ve also learned the difference between how the $ErrorActionPreference
variable and the PowerShell ErrorAction
parameter affects how PowerShell treats non-terminating errors.
You have also learned how to use the PowerShell Try Catch Finally
blocks to perform error handling, whether for specific errors or a catch-all approach.
The examples that are shown in this article only demonstrates the basics of how the Try Catch Finally
blocks work. The knowledge that I hope you have gained in this article should give you the starting blocks to start applying error handling in your scripts.
Further Reading
- About_Try_Catch_Finally
- About_Automatic_Variables
- Back to Basics: The PowerShell foreach Loop
- Back to Basics: Understanding PowerShell Objects