Продолжаем тему обработки ошибок в PowerShell, начатую в предыдущей статье. Сегодня речь пойдет об обработке прерывающих ошибок (исключений). Надо понимать, что сообщение об ошибке — это не то же самое, что исключение. Как вы помните, в PowerShell есть два типа ошибок — непрерывающие и прерывающие.
Непрерывающие ошибки позволяют продолжить работу, тогда как прерывающие останавливают выполнение команды. Остановка приводит к исключению (exception), которое и можно отлавливать и обрабатывать.
Примечание. Таким же образом можно обрабатывать и непрерывающие ошибки. Изменение параметра ErrorAction на Stop прервет выполнение команды и произведет исключение, которое можно уловить.
Для наглядности сгенерируем ошибку, попытавшись прочитать файл, на который у нас нет прав. А теперь обратимся к переменной $Error и выведем данные об исключении. Как видите, данное исключение имеет тип UnauthorizedAccessException и относится к базовому типу System.SystemException.
Для обработки исключений в PowerShell есть несколько способов, которые мы сегодня и рассмотрим.
Try/Catch/Finally
Конструкция Try/Catch/Finally предназначена для обработки исключений, возникающих в процессе выполнения скрипта. В блоке Try располагается исполняемый код, в котором должны отслеживаться ошибки. При возникновении в блоке Try прерывающей ошибки оболочка PowerShell ищет соответствующий блок Catch для обработки этой ошибки, и если он найден, то выполняет находящиеся в нем инструкции. Блок Catch может включать в себя любые команды, необходимые для обработки возникнувшей ошибки иили восстановления дальнейшей работы скрипта.
Блок Finally располагается обычно в конце скрипта. Команды, находящиеся в нем, выполняются в любом случае, независимо от возникновения ошибок. Была ли ошибка перехвачена и обработана блоком Catch или при выполнении скрипта ошибок не возникало вообще, блок Finally будет выполнен. Присутствие этого блока в скрипте необязательно, основная его задача — высвобождение ресурсов (закрытие процессов, очистка памяти и т.п.).
В качестве примера в блок Try поместим код, который читает файлы из указанной директории. При возникновении проблем блок Catch выводит сообщение об ошибке, после чего отрабатывает блок Finally и работа скрипта завершается:
try {
Get-Content -Path ″C:Files*″ -ErrorAction Stop
}
catch {
Write-Host ″Some error was found.″
}
finally {
Write-Host ″Finish.″
}
Для блока Catch можно указать конкретный тип ошибки, добавив после ключевого слова Catch в квадратных скобках название исключения. Так в следующем примере укажем в качестве типа исключение System.UnauthorizedAccessException, которое возникает при отсутствии необходимых прав доступа к объекту:
try {
Get-Content -Path ″C:Files*″ -ErrorAction Stop
}
catch [System.UnauthorizedAccessException]
{
Write-Host ″File is not accessible.″
}
finally {
Write-Host ″Finish.″
}
Если для блока Catch указан тип ошибки, то этот блок будет обрабатывать только этот тип ошибок, или тип ошибок, наследуемый от указанного типа. При возникновении другого типа ошибка не будет обработана. Если же тип не указан, то блок будет обрабатывать любые типы ошибок, возникающие в блоке Try.
Блок Try может включать несколько блоков Catch, для разных типов ошибок, соответственно можно для каждого типа ошибки задать свой обработчик. Например, возьмем два блока Catch, один для ошибки при отсутствии прав доступа, а второй — для любых других ошибок, которые могут возникнуть в процессе выполнения скрипта:
try {
Get-Content -Path ″C:Files*″ -ErrorAction Stop
}
catch [System.UnauthorizedAccessException]
{
Write-Host ″File is not accessible.″
}
catch {
Write-Host ″Other type of error was found:″
Write-Host ″Exception type is $($_.Exception.GetType().Name)″
}
finally {
Write-Host ″Finish.″
}
Trap
Еще один способ обработки ошибок — это установка ловушки (trap). В этом варианте обработчик ошибок задается с помощью ключевого слова Trap, определяющего список команд, которые должны выполниться при возникновении прерывающей ошибки и исключения. Когда происходит исключение, то оболочка PowerShell ищет в коде инструкции Trap для данной ошибки, и если находит, то выполняет их.
Возьмем наиболее простой пример ловушки, которая обрабатывает все произошедшие исключения и выводит сообщение об ошибке:
trap {
Write-Host ″Error was found.″
}
Get-Content -Path C:File* -ErrorAction Stop
Так же, как и для trycatch, ключевое слово Trap позволяет задавать тип исключения, указав его в квадратных скобках. К примеру, можно задать в скрипте несколько ловушек, одну нацелив на конкретную ошибку, а вторую на обработку оставшихся:
trap [System.Management.Automation.ItemNotFoundException]
{
Write-Host ″File is not accessible.″
break
}
trap {
Write-Host ″Other error was found.″
continue
}
Get-Content -Path C:File* -ErrorAction Stop
Вместе с Trap можно использовать ключевые слова Break и Continue, которые позволяют определить, должен ли скрипт продолжать выполняться после возникновения прерывающей ошибки. По умолчанию при возникновении исключения выполняются команды, входящие в блок Trap, выводится информация об ошибке, после чего выполнение скрипта продолжается со строки, вызвавшей ошибку:
trap {
Write-Host ″Error was found.″
}
Write-Host ″Before error.″
Get-Content -Path C:File* -ErrorAction Stop
Write-Host ″After error.″
Если использовать ключевое слово Break, то при возникновении ошибки будет выполнены команды в блоке Trap, после чего выполнение скрипта будет прервано:
trap {
Write-Host ″Error was found.″
break
}
Write-Host ″Before error.″
Get-Content -Path C:File* -ErrorAction Stop
Write-Host ″After error.″
Как видно из примера, команда, следующая за исключением, не отработала и сообщение ″After error.″ выведено не было.
Если же в Trap включено ключевое слово Continue, то выполнение скрипта будет продолжено, так же как и в случае по умолчанию. Единственное отличие в том, что с Continue ошибка не записывается в поток Error и не выводится на экран.
trap {
Write-Host ″Error was found.″
continue
}
Write-Host ″Before error.″
Get-Content -Path C:File* -ErrorAction Stop
Write-Host ″After error.″
Область действия
При отлове ошибок с помощью Trap надо помнить о такой вещи, как область действия (scope). Оболочка PowerShell является глобальной областью, в которую входят все процессы, запущенный скрипт получает собственную область, а если внутри скрипта определены функции, то внутри каждой определена своя, частная область действия. Это создает своего рода родительско-дочернюю иерархию.
При появлении исключения оболочка ищет ловушку в текущей области. Если в ней есть ловушка, она выполняется, если нет — то производится выход в вышестоящую область и поиск ловушки там. Когда ловушка находится, то происходит ее выполнение. Затем, если ловушка предусматривает продолжение работы, то оболочка возобновляет выполнение кода, начиная с той строки, которая вызвала исключение, но при этом оставаясь в той же области, не возвращаясь обратно.
Для примера возьмем функцию Content, внутри которой будет выполняться наш код. Область действия внутри функции назовем scope 1, а снаружи scope 2:
trap {
Write-Host ″Error was found.″
continue
}
function Content {
Write-Host ″Before error, scope1.″
Get-Content -Path C:File* -ErrorAction Stop
Write-Host ″After error, scope 1.″
}
Content
Write-Host ″After error, scope 2.″
При возникновении ошибки в функции Content оболочка будет искать ловушку внутри нее. Затем, не найдя ловушку внутри функции, оболочка выйдет из текущей области и будет искать в родительской области. Ловушка там есть, поэтому будет выполнена обработка ошибки, после чего Continue возобновит выполнение скрипта, но уже в родительской области (scope 2), не возвращаясь обратно в функцию (scope 1).
А теперь немного изменим скрипт, поместив ловушку внутрь функции:
function Content {
trap {
Write-Host ″Error was found.″
continue
}
Write-Host ″Before error, scope 1.″
Get-Content -Path C:File* -ErrorAction Stop
Write-Host ″After error, scope 1.″
}
Content
Write-Host ″After error, scope 2.″
Как видите, теперь при возникновении ошибки внутри функции будет произведена обработка ошибки, после чего выполнение будет продолжено с той строки, в которой произошла ошибка — не выходя из функции.
Заключение
Если сравнить Try/Catch и Trap, то у каждого метода есть свои достоинства и недостатки. Конструкцию Try/Catch можно более точно нацелить на возможную ошибку, так как Catch обрабатывает только содержимое блока Try. Эту особенность удобно использовать при отладке скриптов, для поиска ошибок.
И наоборот, Trap является глобальным обработчиком, отлавливая ошибки во всем скрипте независимо от расположения. На мой взгляд это более жизненный вариант, который больше подходит для постоянной работы.
В Powershell существует несколько уровней ошибок и несколько способов их обработать. Проблемы одного уровня (Non-Terminating Errors) можно решить с помощью привычных для Powershell команд. Другой уровень ошибок (Terminating Errors) решается с помощью исключений (Exceptions) стандартного, для большинства языков, блока в виде Try, Catch и Finally.
Как Powershell обрабатывает ошибки
До рассмотрения основных методов посмотрим на теоретическую часть.
Автоматические переменные $Error
В Powershell существует множество переменных, которые создаются автоматически. Одна из таких переменных — $Error хранит в себе все ошибки за текущий сеанс PS. Например так я выведу количество ошибок и их сообщение за весь сеанс:
Get-TestTest
$Error
$Error.Count
При отсутствии каких либо ошибок мы бы получили пустой ответ, а счетчик будет равняться 0:
Переменная $Error являет массивом и мы можем по нему пройтись или обратиться по индексу что бы найти нужную ошибку:
$Error[0]
foreach ($item in $Error){$item}
Свойства объекта $Error
Так же как и все что создается в Powershell переменная $Error так же имеет свойства (дополнительную информацию) и методы. Названия свойств и методов можно увидеть через команду Get-Member:
$Error | Get-Member
Например, с помощью свойства InvocationInfo, мы можем вывести более структурный отчет об ошибки:
$Error[0].InvocationInfo
Методы объекта $Error
Например мы можем очистить логи ошибок используя clear:
$Error.clear()
Критические ошибки (Terminating Errors)
Критические (завершающие) ошибки останавливают работу скрипта. Например это может быть ошибка в названии командлета или параметра. В следующем примере команда должна была бы вернуть процессы «svchost» дважды, но из-за использования несуществующего параметра ‘—Error’ не выполнится вообще:
'svchost','svchost' | % {Get-Process -Name $PSItem} --Error
Не критические ошибки (Non-Terminating Errors)
Не критические (не завершающие) ошибки не остановят работу скрипта полностью, но могут вывести сообщение об этом. Это могут быть ошибки не в самих командлетах Powershell, а в значениях, которые вы используете. На предыдущем примере мы можем допустить опечатку в названии процессов, но команда все равно продолжит работу:
'svchost111','svchost' | % {Get-Process -Name $PSItem}
Как видно у нас появилась информация о проблеме с первым процессом ‘svchost111’, так как его не существует. Обычный процесс ‘svchost’ он у нас вывелся корректно.
Параметр ErrorVariable
Если вы не хотите использовать автоматическую переменную $Error, то сможете определять свою переменную индивидуально для каждой команды. Эта переменная определяется в параметре ErrorVariable:
'svchost111','svchost' | % {Get-Process -Name $PSItem } -ErrorVariable my_err_var
$my_err_var
Переменная будет иметь те же свойства, что и автоматическая:
$my_err_var.InvocationInfo
Обработка некритических ошибок
У нас есть два способа определения последующих действий при ‘Non-Terminating Errors’. Это правило можно задать локально и глобально (в рамках сессии). Мы сможем полностью остановить работу скрипта или вообще отменить вывод ошибок.
Приоритет ошибок с $ErrorActionPreference
Еще одна встроенная переменная в Powershell $ErrorActionPreference глобально определяет что должно случится, если у нас появится обычная ошибка. По умолчанию это значение равно ‘Continue’, что значит «вывести информацию об ошибке и продолжить работу»:
$ErrorActionPreference
Если мы поменяем значение этой переменной на ‘Stop’, то поведение скриптов и команд будет аналогично критичным ошибкам. Вы можете убедиться в этом на прошлом скрипте с неверным именем процесса:
$ErrorActionPreference = 'Stop'
'svchost111','svchost' | % {Get-Process -Name $PSItem}
Т.е. скрипт был остановлен в самом начале. Значение переменной будет храниться до момента завершения сессии Powershell. При перезагрузке компьютера, например, вернется значение по умолчанию.
Ниже значение, которые мы можем установить в переменной $ErrorActionPreference:
- Continue — вывод ошибки и продолжение работы;
- Inquire — приостановит работу скрипта и спросит о дальнейших действиях;
- SilentlyContinue — скрипт продолжит свою работу без вывода ошибок;
- Stop — остановка скрипта при первой ошибке.
Самый частый параметр, который мне приходится использовать — SilentlyContinue:
$ErrorActionPreference = 'SilentlyContinue'
'svchost111','svchost' | % {Get-Process -Name $PSItem}
Использование параметра ErrorAction
Переменная $ErrorActionPreference указывает глобальный приоритет, но мы можем определить такую логику в рамках команды с параметром ErrorAction. Этот параметр имеет больший приоритет чем $ErrorActionPreference. В следующем примере, глобальная переменная определяет полную остановку скрипта, а в параметр ErrorAction говорит «не выводить ошибок и продолжить работу»:
$ErrorActionPreference = 'Stop'
'svchost111','svchost' | % {Get-Process -Name $PSItem -ErrorAction 'SilentlyContinue'}
Кроме ‘SilentlyContinue’ мы можем указывать те же параметры, что и в переменной $ErrorActionPreference.
Значение Stop, в обоих случаях, делает ошибку критической.
Обработка критических ошибок и исключений с Try, Catch и Finally
Когда мы ожидаем получить какую-то ошибку и добавить логику нужно использовать Try и Catch. Например, если в вариантах выше мы определяли нужно ли нам отображать ошибку или останавливать скрипт, то теперь сможем изменить выполнение скрипта или команды вообще. Блок Try и Catch работает только с критическими ошибками и в случаях если $ErrorActionPreference или ErrorAction имеют значение Stop.
Например, если с помощью Powershell мы пытаемся подключиться к множеству компьютеров один из них может быть выключен — это приведет к ошибке. Так как эту ситуацию мы можем предвидеть, то мы можем обработать ее. Процесс обработки ошибок называется исключением (Exception).
Синтаксис и логика работы команды следующая:
try {
# Пытаемся подключиться к компьютеру
}
catch [Имя исключения 1],[Имя исключения 2]{
# Раз компьютер не доступен, сделать то-то
}
finally {
# Блок, который выполняется в любом случае последним
}
Блок try мониторит ошибки и если она произойдет, то она добавится в переменную $Error и скрипт перейдет к блоку Catch. Так как ошибки могут быть разные (нет доступа, нет сети, блокирует правило фаервола и т.д.) то мы можем прописывать один блок Try и несколько Catch:
try {
# Пытаемся подключится
}
catch ['Нет сети']['Блокирует фаервол']{
# Записываем в файл
}
catch ['Нет прав на подключение']{
# Подключаемся под другим пользователем
}
Сам блок finally — не обязательный и используется редко. Он выполняется самым последним, после try и catch и не имеет каких-то условий.
Catch для всех типов исключений
Как и было показано выше мы можем использовать блок Catch для конкретного типа ошибок, например при проблемах с доступом. Если в этом месте ничего не указывать — в этом блоке будут обрабатываться все варианты ошибок:
try {
'svchost111','svchost' | % {Get-Process -Name $PSItem -ErrorAction 'Stop'}
}
catch {
Write-Host "Какая-то неисправность" -ForegroundColor RED
}
Такой подход не рекомендуется использовать часто, так как вы можете пропустить что-то важное.
Мы можем вывести в блоке catch текст ошибки используя $PSItem.Exception:
try {
'svchost111','svchost' | % {Get-Process -Name $PSItem -ErrorAction 'Stop'}
}
catch {
Write-Host "Какая-то неисправность" -ForegroundColor RED
$PSItem.Exception
}
Переменная $PSItem хранит информацию о текущей ошибке, а глобальная переменная $Error будет хранит информацию обо всех ошибках. Так, например, я выведу одну и ту же информацию:
$Error[0].Exception
Создание отдельных исключений
Что бы обработать отдельную ошибку сначала нужно найти ее имя. Это имя можно увидеть при получении свойств и методов у значения переменной $Error:
$Error[0].Exception | Get-Member
Так же сработает и в блоке Catch с $PSItem:
Для вывода только имени можно использовать свойство FullName:
$Error[0].Exception.GetType().FullName
Далее, это имя, мы вставляем в блок Catch:
try {
'svchost111','svchost' | % {Get-Process -Name $PSItem -ErrorAction 'Stop'}
}
catch [Microsoft.PowerShell.Commands.ProcessCommandException]{
Write-Host "Произошла ошибка" -ForegroundColor RED
$PSItem.Exception
}
Так же, как и было описано выше мы можем усложнять эти блоки как угодно указывая множество исключений в одном catch.
Выброс своих исключений
Иногда нужно создать свои собственные исключения. Например мы можем запретить добавлять через какой-то скрипт названия содержащие маленькие буквы или сотрудников без указания возраста и т.д. Способов создать такие ошибки — два и они тоже делятся на критические и обычные.
Выброс с throw
Throw — выбрасывает ошибку, которая останавливает работу скрипта. Этот тип ошибок относится к критическим. Например мы можем указать только текст для дополнительной информации:
$name = 'AD.1'
if ($name -match '.'){
throw 'Запрещено использовать точки в названиях'
}
Если нужно, то мы можем использовать исключения, которые уже были созданы в Powershell:
$name = 'AD.1'
if ($name -like '*.*'){
throw [System.IO.FileNotFoundException]'Запрещено использовать точки в названиях'
}
Использование Write-Error
Команда Write-Error работает так же, как и ключ ErrorAction. Мы можем просто отобразить какую-то ошибку и продолжить выполнение скрипта:
$names = @('CL1', 'AD.1', 'CL3')
foreach ($name in $names){
if ($name -like '*.*'){
Write-Error -Message 'Обычная ошибка'
}
else{
$name
}
}
При необходимости мы можем использовать параметр ErrorAction. Значения этого параметра были описаны выше. Мы можем указать значение ‘Stop’, что полностью остановит выполнение скрипта:
$names = @('CL1', 'AD.1', 'CL3')
foreach ($name in $names){
if ($name -like '*.*'){
Write-Error -Message 'Обычная ошибка' -ErrorAction 'Stop'
}
else{
$name
}
}
Отличие команды Write-Error с ключом ErrorAction от обычных команд в том, что мы можем указывать исключения в параметре Exception:
Write-Error -Message 'Обычная ошибка' -ErrorAction 'Stop'
Write-Error -Message 'Исключение' -Exception [System.IO.FileNotFoundException] -ErrorAction 'Stop'
В Exception мы так же можем указывать сообщение. При этом оно будет отображаться в переменной $Error:
Write-Error -Exception [System.IO.FileNotFoundException]'Моё сообщение'
…
Теги:
#powershell
#ошибки
description | Locale | ms.date | online version | schema | title |
---|---|---|---|---|---|
Describes how to use the `try`, `catch`, and `finally` blocks to handle terminating errors. |
en-US |
11/12/2021 |
https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.2&WT.mc_id=ps-gethelp |
2.0.0 |
about Try Catch Finally |
Short description
Describes how to use the try
, catch
, and finally
blocks to handle
terminating errors.
Long description
Use try
, catch
, and finally
blocks to respond to or handle terminating
errors in scripts. The Trap
statement can also be used to handle terminating
errors in scripts. For more information, see about_Trap.
A terminating error stops a statement from running. If PowerShell does not
handle a terminating error in some way, PowerShell also stops running the
function or script using the current pipeline. In other languages, such as C#,
terminating errors are referred to as exceptions.
Use the try
block to define a section of a script in which you want
PowerShell to monitor for errors. When an error occurs within the try
block,
the error is first saved to the $Error
automatic variable. PowerShell then
searches for a catch
block to handle the error. If the try
statement does
not have a matching catch
block, PowerShell continues to search for an
appropriate catch
block or Trap
statement in the parent scopes. After a
catch
block is completed or if no appropriate catch
block or Trap
statement is found, the finally
block is run. If the error cannot be handled,
the error is written to the error stream.
A catch
block can include commands for tracking the error or for recovering
the expected flow of the script. A catch
block can specify which error types
it catches. A try
statement can include multiple catch
blocks for different
kinds of errors.
A finally
block can be used to free any resources that are no longer needed
by your script.
try
, catch
, and finally
resemble the try
, catch
, and finally
keywords used in the C# programming language.
Syntax
A try
statement contains a try
block, zero or more catch
blocks, and zero
or one finally
block. A try
statement must have at least one catch
block
or one finally
block.
The following shows the try
block syntax:
The try
keyword is followed by a statement list in braces. If a terminating
error occurs while the statements in the statement list are being run, the
script passes the error object from the try
block to an appropriate catch
block.
The following shows the catch
block syntax:
catch [[<error type>][',' <error type>]*] {<statement list>}
Error types appear in brackets. The outermost brackets indicate the element is
optional.
The catch
keyword is followed by an optional list of error type
specifications and a statement list. If a terminating error occurs in the
try
block, PowerShell searches for an appropriate catch
block. If
one is found, the statements in the catch
block are executed.
The catch
block can specify one or more error types. An error type is a
Microsoft .NET Framework exception or an exception that is derived from a .NET
Framework exception. A catch
block handles errors of the specified .NET
Framework exception class or of any class that derives from the specified
class.
If a catch
block specifies an error type, that catch
block handles that
type of error. If a catch
block does not specify an error type, that catch
block handles any error encountered in the try
block. A try
statement can
include multiple catch
blocks for the different specified error types.
The following shows the finally
block syntax:
finally {<statement list>}
The finally
keyword is followed by a statement list that runs every time the
script is run, even if the try
statement ran without error or an error was
caught in a catch
statement.
Note that pressing CTRL+C stops the pipeline. Objects
that are sent to the pipeline will not be displayed as output. Therefore, if
you include a statement to be displayed, such as «Finally block has run», it
will not be displayed after you press CTRL+C, even if the
finally
block ran.
Catching errors
The following sample script shows a try
block with a catch
block:
try { NonsenseString } catch { "An error occurred." }
The catch
keyword must immediately follow the try
block or another catch
block.
PowerShell does not recognize «NonsenseString» as a cmdlet or other item.
Running this script returns the following result:
When the script encounters «NonsenseString», it causes a terminating error. The
catch
block handles the error by running the statement list inside the block.
Using multiple catch statements
A try
statement can have any number of catch
blocks. For example, the
following script has a try
block that downloads MyDoc.doc
, and it contains
two catch
blocks:
try { $wc = new-object System.Net.WebClient $wc.DownloadFile("http://www.contoso.com/MyDoc.doc","c:tempMyDoc.doc") } catch [System.Net.WebException],[System.IO.IOException] { "Unable to download MyDoc.doc from http://www.contoso.com." } catch { "An error occurred that could not be resolved." }
The first catch
block handles errors of the System.Net.WebException and
System.IO.IOException types. The second catch
block does not specify an
error type. The second catch
block handles any other terminating errors that
occur.
PowerShell matches error types by inheritance. A catch
block handles errors
of the specified .NET Framework exception class or of any class that derives
from the specified class. The following example contains a catch
block that
catches a «Command Not Found» error:
catch [System.Management.Automation.CommandNotFoundException] {"Inherited Exception" }
The specified error type, CommandNotFoundException, inherits from the
System.SystemException type. The following example also catches a Command
Not Found error:
catch [System.SystemException] {"Base Exception" }
This catch
block handles the «Command Not Found» error and other errors that
inherit from the SystemException type.
If you specify an error class and one of its derived classes, place the catch
block for the derived class before the catch
block for the general class.
[!NOTE]
PowerShell wraps all exceptions in a RuntimeException type. Therefore,
specifying the error type System.Management.Automation.RuntimeException
behaves the same as an unqualified catch block.
Using Traps in a Try Catch
When a terminating error occurs in a try
block with a Trap
defined within
the try
block, even if there is a matching catch
block, the Trap
statement
takes control.
If a Trap
exists at a higher block than the try
, and there is no matching
catch
block within the current scope, the Trap
will take control, even if
any parent scope has a matching catch
block.
Accessing exception information
Within a catch
block, the current error can be accessed using $_
, which
is also known as $PSItem
. The object is of type ErrorRecord.
try { NonsenseString } catch { Write-Host "An error occurred:" Write-Host $_ }
Running this script returns the following result:
An Error occurred:
The term 'NonsenseString' 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.
There are additional properties that can be accessed, such as ScriptStackTrace,
Exception, and ErrorDetails. For example, if we change the script to the
following:
try { NonsenseString } catch { Write-Host "An error occurred:" Write-Host $_.ScriptStackTrace }
The result will be similar to:
An Error occurred:
at <ScriptBlock>, <No file>: line 2
Freeing resources using finally
To free resources used by a script, add a finally
block after the try
and
catch
blocks. The finally
block statements run regardless of whether the
try
block encounters a terminating error. PowerShell runs the finally
block
before the script terminates or before the current block goes out of scope.
A finally
block runs even if you use CTRL+C to stop the
script. A finally
block also runs if an Exit keyword stops the script from
within a catch
block.
See also
- about_Break
- about_Continue
- about_Scopes
- about_Throw
- about_Trap
I am trying to see if a process is running on multiple servers and then format it into a table.
get-process -ComputerName server1,server2,server3 -name explorer | Select-Object processname,machinename
Thats the easy part — When the process does not exist or if the server is unavailable, powershell outputs a big ugly error, messes up the the table and doesn’t continue. Example
Get-Process : Couldn't connect to remote machine.At line:1 char:12 + get-process <<<< -ComputerName server1,server2,server3 -name explorer | format-table processname,machinename
+ CategoryInfo : NotSpecified: (:) [Get-Process], InvalidOperatio nException + FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.Power Shell.Commands.GetProcessCommand
How do I get around this? If the I would still like to get notified if the process isn’t available or Running.
description | Locale | ms.date | online version | schema | title |
---|---|---|---|---|---|
Describes how to use the `try`, `catch`, and `finally` blocks to handle terminating errors. |
en-US |
11/12/2021 |
https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.3&WT.mc_id=ps-gethelp |
2.0.0 |
about Try Catch Finally |
Short description
Describes how to use the try
, catch
, and finally
blocks to handle
terminating errors.
Long description
Use try
, catch
, and finally
blocks to respond to or handle terminating
errors in scripts. The Trap
statement can also be used to handle terminating
errors in scripts. For more information, see about_Trap.
A terminating error stops a statement from running. If PowerShell does not
handle a terminating error in some way, PowerShell also stops running the
function or script using the current pipeline. In other languages, such as C#,
terminating errors are referred to as exceptions.
Use the try
block to define a section of a script in which you want
PowerShell to monitor for errors. When an error occurs within the try
block,
the error is first saved to the $Error
automatic variable. PowerShell then
searches for a catch
block to handle the error. If the try
statement does
not have a matching catch
block, PowerShell continues to search for an
appropriate catch
block or Trap
statement in the parent scopes. After a
catch
block is completed or if no appropriate catch
block or Trap
statement is found, the finally
block is run. If the error cannot be handled,
the error is written to the error stream.
A catch
block can include commands for tracking the error or for recovering
the expected flow of the script. A catch
block can specify which error types
it catches. A try
statement can include multiple catch
blocks for different
kinds of errors.
A finally
block can be used to free any resources that are no longer needed
by your script.
try
, catch
, and finally
resemble the try
, catch
, and finally
keywords used in the C# programming language.
Syntax
A try
statement contains a try
block, zero or more catch
blocks, and zero
or one finally
block. A try
statement must have at least one catch
block
or one finally
block.
The following shows the try
block syntax:
The try
keyword is followed by a statement list in braces. If a terminating
error occurs while the statements in the statement list are being run, the
script passes the error object from the try
block to an appropriate catch
block.
The following shows the catch
block syntax:
catch [[<error type>][',' <error type>]*] {<statement list>}
Error types appear in brackets. The outermost brackets indicate the element is
optional.
The catch
keyword is followed by an optional list of error type
specifications and a statement list. If a terminating error occurs in the
try
block, PowerShell searches for an appropriate catch
block. If
one is found, the statements in the catch
block are executed.
The catch
block can specify one or more error types. An error type is a
Microsoft .NET Framework exception or an exception that is derived from a .NET
Framework exception. A catch
block handles errors of the specified .NET
Framework exception class or of any class that derives from the specified
class.
If a catch
block specifies an error type, that catch
block handles that
type of error. If a catch
block does not specify an error type, that catch
block handles any error encountered in the try
block. A try
statement can
include multiple catch
blocks for the different specified error types.
The following shows the finally
block syntax:
finally {<statement list>}
The finally
keyword is followed by a statement list that runs every time the
script is run, even if the try
statement ran without error or an error was
caught in a catch
statement.
Note that pressing CTRL+C stops the pipeline. Objects
that are sent to the pipeline will not be displayed as output. Therefore, if
you include a statement to be displayed, such as «Finally block has run», it
will not be displayed after you press CTRL+C, even if the
finally
block ran.
Catching errors
The following sample script shows a try
block with a catch
block:
try { NonsenseString } catch { "An error occurred." }
The catch
keyword must immediately follow the try
block or another catch
block.
PowerShell does not recognize «NonsenseString» as a cmdlet or other item.
Running this script returns the following result:
When the script encounters «NonsenseString», it causes a terminating error. The
catch
block handles the error by running the statement list inside the block.
Using multiple catch statements
A try
statement can have any number of catch
blocks. For example, the
following script has a try
block that downloads MyDoc.doc
, and it contains
two catch
blocks:
try { $wc = new-object System.Net.WebClient $wc.DownloadFile("http://www.contoso.com/MyDoc.doc","c:tempMyDoc.doc") } catch [System.Net.WebException],[System.IO.IOException] { "Unable to download MyDoc.doc from http://www.contoso.com." } catch { "An error occurred that could not be resolved." }
The first catch
block handles errors of the System.Net.WebException and
System.IO.IOException types. The second catch
block does not specify an
error type. The second catch
block handles any other terminating errors that
occur.
PowerShell matches error types by inheritance. A catch
block handles errors
of the specified .NET Framework exception class or of any class that derives
from the specified class. The following example contains a catch
block that
catches a «Command Not Found» error:
catch [System.Management.Automation.CommandNotFoundException] {"Inherited Exception" }
The specified error type, CommandNotFoundException, inherits from the
System.SystemException type. The following example also catches a Command
Not Found error:
catch [System.SystemException] {"Base Exception" }
This catch
block handles the «Command Not Found» error and other errors that
inherit from the SystemException type.
If you specify an error class and one of its derived classes, place the catch
block for the derived class before the catch
block for the general class.
[!NOTE]
PowerShell wraps all exceptions in a RuntimeException type. Therefore,
specifying the error type System.Management.Automation.RuntimeException
behaves the same as an unqualified catch block.
Using Traps in a Try Catch
When a terminating error occurs in a try
block with a Trap
defined within
the try
block, even if there is a matching catch
block, the Trap
statement
takes control.
If a Trap
exists at a higher block than the try
, and there is no matching
catch
block within the current scope, the Trap
will take control, even if
any parent scope has a matching catch
block.
Accessing exception information
Within a catch
block, the current error can be accessed using $_
, which
is also known as $PSItem
. The object is of type ErrorRecord.
try { NonsenseString } catch { Write-Host "An error occurred:" Write-Host $_ }
Running this script returns the following result:
An Error occurred:
The term 'NonsenseString' 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.
There are additional properties that can be accessed, such as ScriptStackTrace,
Exception, and ErrorDetails. For example, if we change the script to the
following:
try { NonsenseString } catch { Write-Host "An error occurred:" Write-Host $_.ScriptStackTrace }
The result will be similar to:
An Error occurred:
at <ScriptBlock>, <No file>: line 2
Freeing resources using finally
To free resources used by a script, add a finally
block after the try
and
catch
blocks. The finally
block statements run regardless of whether the
try
block encounters a terminating error. PowerShell runs the finally
block
before the script terminates or before the current block goes out of scope.
A finally
block runs even if you use CTRL+C to stop the
script. A finally
block also runs if an Exit keyword stops the script from
within a catch
block.
See also
- about_Break
- about_Continue
- about_Scopes
- about_Throw
- about_Trap