Powershell error action

-ErrorAction parameter in PowerShell allows you to specify how to handle terminating errors,-ErrorVariable parameter,store error message

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

PowerShell -ErrorAction Parameter - Continue
PowerShell -ErrorAction Parameter – Continue

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 -ErrorAction Parameter - Ignore
PowerShell -ErrorAction Parameter – Ignore

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

PowerShell -ErrorAction Parameter - Inquire
PowerShell -ErrorAction Parameter – Inquire

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

PowerShell -ErrorAction Parameter - SilentlyContinue
PowerShell -ErrorAction Parameter – SilentlyContinue

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

PowerShell -ErrorAction Parameter - Stop
PowerShell -ErrorAction Parameter – Stop

-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

PowerShell -ErrorVariable - variable
PowerShell -ErrorVariable – variable

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

powershell erroraction silentlycontinue
PowerShell -ErrorAction and -ErrorVariable

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.
  1. 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.

  2. 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 — это действие, определенное в сеансе по умолчанию, поэтому его можно не указывать явно.

обработка ошибки, режим Continue

При значении SilentlyContinue информация об ошибке добавляется в переменную $Error, но не выводится на экран. При этом команда продолжает выполняться дальше, также как и в предыдущем случае.

обработка ошибки, режим SilentlyContinue

Значение Stop останавливает дальнейшее выполнение команды при возникновении ошибки. И наоборот, значение Ignore полностью игнорирует возникновение ошибки, при этом не выводится сообщение на экран и не производится запись в $Error. Это значение появилось в PowerShell 3.0.

Обработка ошибок в режимах Stop и Ignore

Inquire — наиболее интересное значение ErrorAction. Если задать это значение, то при возникновении ошибки предлагается на выбор несколько действий: продолжить (Yes), продолжить не смотря на эту и все последующие ошибки (Yes to All), остановить (Halt) или приостановить (Suspend) выполнение команды.

Самый необычный эффект дает Suspend, при выборе которого открывается параллельный сеанс (Nested Namespace). Определить его можно по значку >>. Nested Namespace представляет из себя дочерний процесс, в котором можно полноценно работать — выполнять команды, запускать скрипты и т.п. Этот режим удобно использовать для отладки скриптов, например можно по быстрому исправить причину ошибки и продолжить выполнение. Для выхода из Nested Namespace достаточно набрать exit и выбрать необходимое действие.

Обработка ошибки в режиме Inquire

Примечание. У параметра 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

Переменная $Error не безразмерна, по умолчанию она хранит не более 256 ошибок. При превышении этого количества наиболее старые ошибки будут затираться. При необходимости количество записей в переменной $Error можно увеличить, изменив значение другой переменной $MaximumErrorCount.

Кроме $Error для хранения ошибок допускается задавать собственные переменные. Сделать это можно с помощью параметра ErrorVariable, например так:

Get-Service service,spooler -ErrorAction SilentlyContinue -ErrorVariable var

Обратите внимание, что имя переменной в команде задается без знака $, хотя в дальнейшем к ней обращаемся как к обычной переменной $var.

назначение собственной переменной для хранения ошибок

В отличие от глобальной переменной $Error заданные вручную переменные хранят только ошибки той команды, в которой они определены. Кроме того, по умолчанию эти переменные каждый раз перезаписываются и поэтому хранят только последнюю ошибку. Если вы хотите, чтобы новые ошибки добавлялись в переменную, не перезаписывая ее содержимое, то перед именем переменной надо поставить знак +, например +var.

Пока все, а в следующей части пойдет о способах обработки прерывающих ошибок.

  1. Introduction to Error Action in PowerShell
  2. Use the -ErrorAction Parameter in PowerShell
  3. Setting Error Action Preferences in PowerShell

Suppressing PowerShell Errors

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.

Example of errors in PowerShell
Example of errors in PowerShell

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.

The $Error variable is empty
The $Error variable is empty

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
The error is added to the $Error variable
The error is added to the $Error variable

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.

The $Error object properties
The $Error object properties

To determine the reason for the error, you can view the content of the InvocationInfo property using the command below.

The InvocationInfo property
The InvocationInfo property

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.

The notepad process details
The notepad process details

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.

Error is thrown because the parameter is invalid
Error is thrown because the parameter is invalid

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.

Example of non-terminating error
Example of non-terminating error

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 STOPforces 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.

Forcing a terminating error using the $ErrorActionPreference variable
Forcing a terminating error using the $ErrorActionPreference variable

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 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.

Forcing a terminating error using the ErrorAction parameter
Forcing a terminating error using the PowerShell ErrorAction parameter

Using 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.

Script terminated when an error occurred
Script terminated when an error occurred

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.

Script terminated with a descriptive error message
Script terminated with a descriptive error message

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.

Getting the error TypeName value
Getting the error TypeName value

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.

Script terminated with a specific error message
Script terminated with a specific error message

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

Понравилась статья? Поделить с друзьями:
  • Powerpoint разрывает слова как исправить
  • Powerpoint произошла серьезная ошибка во время последнего запуска
  • Powerpoint ошибка при открытии файла
  • Powerpoint ошибка при запуске приложения 0xc0000142
  • Powerpoint как изменить язык интерфейса