- Обработка ошибок с исключениями в Powershell с Try и Catch
- Как Powershell обрабатывает ошибки
- Автоматические переменные $Error
- Свойства объекта $Error
- Методы объекта $Error
- Критические ошибки (Terminating Errors)
- Не критические ошибки (Non-Terminating Errors)
- Параметр ErrorVariable
- Обработка некритических ошибок
- Приоритет ошибок с $ErrorActionPreference
- Использование параметра ErrorAction
- Обработка критических ошибок и исключений с Try, Catch и Finally
- Catch для всех типов исключений
- Создание отдельных исключений
- Выброс своих исключений
- Выброс с throw
- Использование Write-Error
- Записи об ошибках Windows PowerShell
- Идентификатор ошибки
- Категория ошибки
- Сообщение об ошибке замены
- Рекомендуемые сведения о действии
- Сведения о вызове
Обработка ошибок с исключениями в Powershell с Try и Catch
02 октября 2020
В Powershell существует несколько уровней ошибок и несколько способов их обработать. Проблемы одного уровня (Non-Terminating Errors) можно решить с помощью привычных для Powershell команд. Другой уровень ошибок (Terminating Errors) решается с помощью исключений (Exceptions) стандартного, для большинства языков, блока в виде Try, Catch и Finally.
Навигация по посту
Как Powershell обрабатывает ошибки
До рассмотрения основных методов посмотрим на теоретическую часть.
Автоматические переменные $Error
В Powershell существует множество переменных, которые создаются автоматически. Одна из таких переменных — $Error хранит в себе все ошибки за текущий сеанс PS. Например так я выведу количество ошибок и их сообщение за весь сеанс:
При отсутствии каких либо ошибок мы бы получили пустой ответ, а счетчик будет равняться 0:
Переменная $Error являет массивом и мы можем по нему пройтись или обратиться по индексу что бы найти нужную ошибку:
Свойства объекта $Error
Так же как и все что создается в Powershell переменная $Error так же имеет свойства (дополнительную информацию) и методы. Названия свойств и методов можно увидеть через команду Get-Member:
Например, с помощью свойства InvocationInfo, мы можем вывести более структурный отчет об ошибки:
Методы объекта $Error
Например мы можем очистить логи ошибок используя clear:
Критические ошибки (Terminating Errors)
Критические (завершающие) ошибки останавливают работу скрипта. Например это может быть ошибка в названии командлета или параметра. В следующем примере команда должна была бы вернуть процессы «svchost» дважды, но из-за использования несуществующего параметра ‘—Error’ не выполнится вообще:
Не критические ошибки (Non-Terminating Errors)
Не критические (не завершающие) ошибки не остановят работу скрипта полностью, но могут вывести сообщение об этом. Это могут быть ошибки не в самих командлетах Powershell, а в значениях, которые вы используете. На предыдущем примере мы можем допустить опечатку в названии процессов, но команда все равно продолжит работу:
Как видно у нас появилась информация о проблеме с первым процессом ‘svchost111’, так как его не существует. Обычный процесс ‘svchost’ он у нас вывелся корректно.
Параметр ErrorVariable
Если вы не хотите использовать автоматическую переменную $Error, то сможете определять свою переменную индивидуально для каждой команды. Эта переменная определяется в параметре ErrorVariable:
Переменная будет иметь те же свойства, что и автоматическая:
Повторное использование логина и пароля в Powershell с Get-Credential и их шифрование
Обработка некритических ошибок
У нас есть два способа определения последующих действий при ‘Non-Terminating Errors’. Это правило можно задать локально и глобально (в рамках сессии). Мы сможем полностью остановить работу скрипта или вообще отменить вывод ошибок.
Приоритет ошибок с $ErrorActionPreference
Еще одна встроенная переменная в Powershell $ErrorActionPreference глобально определяет что должно случится, если у нас появится обычная ошибка. По умолчанию это значение равно ‘Continue’, что значит «вывести информацию об ошибке и продолжить работу»:
Если мы поменяем значение этой переменной на ‘Stop’, то поведение скриптов и команд будет аналогично критичным ошибкам. Вы можете убедиться в этом на прошлом скрипте с неверным именем процесса:
Т.е. скрипт был остановлен в самом начале. Значение переменной будет храниться до момента завершения сессии Powershell. При перезагрузке компьютера, например, вернется значение по умолчанию.
Ниже значение, которые мы можем установить в переменной $ErrorActionPreference:
- Continue — вывод ошибки и продолжение работы;
- Inquire — приостановит работу скрипта и спросит о дальнейших действиях;
- SilentlyContinue — скрипт продолжит свою работу без вывода ошибок;
- Stop — остановка скрипта при первой ошибке.
Самый частый параметр, который мне приходится использовать — SilentlyContinue:
Использование параметра ErrorAction
Переменная $ErrorActionPreference указывает глобальный приоритет, но мы можем определить такую логику в рамках команды с параметром ErrorAction. Этот параметр имеет больший приоритет чем $ErrorActionPreference. В следующем примере, глобальная переменная определяет полную остановку скрипта, а в параметр ErrorAction говорит «не выводить ошибок и продолжить работу»:
Кроме ‘SilentlyContinue’ мы можем указывать те же параметры, что и в переменной $ErrorActionPreference.
Значение Stop, в обоих случаях, делает ошибку критической.
Обработка критических ошибок и исключений с Try, Catch и Finally
Когда мы ожидаем получить какую-то ошибку и добавить логику нужно использовать Try и Catch. Например, если в вариантах выше мы определяли нужно ли нам отображать ошибку или останавливать скрипт, то теперь сможем изменить выполнение скрипта или команды вообще. Блок Try и Catch работает только с критическими ошибками и в случаях если $ErrorActionPreference или ErrorAction имеют значение Stop.
Например, если с помощью Powershell мы пытаемся подключиться к множеству компьютеров один из них может быть выключен — это приведет к ошибке. Так как эту ситуацию мы можем предвидеть, то мы можем обработать ее. Процесс обработки ошибок называется исключением (Exception).
Синтаксис и логика работы команды следующая:
Блок try мониторит ошибки и если она произойдет, то она добавится в переменную $Error и скрипт перейдет к блоку Catch. Так как ошибки могут быть разные (нет доступа, нет сети, блокирует правило фаервола и т.д.) то мы можем прописывать один блок Try и несколько Catch:
Сам блок finally — не обязательный и используется редко. Он выполняется самым последним, после try и catch и не имеет каких-то условий.
Catch для всех типов исключений
Как и было показано выше мы можем использовать блок Catch для конкретного типа ошибок, например при проблемах с доступом. Если в этом месте ничего не указывать — в этом блоке будут обрабатываться все варианты ошибок:
Такой подход не рекомендуется использовать часто, так как вы можете пропустить что-то важное.
Мы можем вывести в блоке catch текст ошибки используя $PSItem.Exception:
Переменная $PSItem хранит информацию о текущей ошибке, а глобальная переменная $Error будет хранит информацию обо всех ошибках. Так, например, я выведу одну и ту же информацию:
Создание отдельных исключений
Что бы обработать отдельную ошибку сначала нужно найти ее имя. Это имя можно увидеть при получении свойств и методов у значения переменной $Error:
Так же сработает и в блоке Catch с $PSItem:
Для вывода только имени можно использовать свойство FullName:
Далее, это имя, мы вставляем в блок Catch:
Так же, как и было описано выше мы можем усложнять эти блоки как угодно указывая множество исключений в одном catch.
Создание и изменение в Powershell NTFS разрешений ACL
Выброс своих исключений
Иногда нужно создать свои собственные исключения. Например мы можем запретить добавлять через какой-то скрипт названия содержащие маленькие буквы или сотрудников без указания возраста и т.д. Способов создать такие ошибки — два и они тоже делятся на критические и обычные.
Выброс с throw
Throw — выбрасывает ошибку, которая останавливает работу скрипта. Этот тип ошибок относится к критическим. Например мы можем указать только текст для дополнительной информации:
Если нужно, то мы можем использовать исключения, которые уже были созданы в Powershell:
Использование Write-Error
Команда Write-Error работает так же, как и ключ ErrorAction. Мы можем просто отобразить какую-то ошибку и продолжить выполнение скрипта:
При необходимости мы можем использовать параметр ErrorAction. Значения этого параметра были описаны выше. Мы можем указать значение ‘Stop’, что полностью остановит выполнение скрипта:
Отличие команды Write-Error с ключом ErrorAction от обычных команд в том, что мы можем указывать исключения в параметре Exception:
В Exception мы так же можем указывать сообщение. При этом оно будет отображаться в переменной $Error:
Источник
Записи об ошибках Windows PowerShell
Командлеты должны передавать объект System. Management. Automation. ерроррекорд , который определяет условие ошибки для завершающих и устранимых ошибок.
- Исключение, описывающее ошибку. Часто это исключение, которое командлет перехватывает и преобразует в запись об ошибке. Каждая запись об ошибке должна содержать исключение.
Если командлет не перехватывает исключение, он должен создать новое исключение и выбрать класс исключения, который наилучшим образом описывает условие ошибки. Однако исключение не требуется, так как доступ к нему можно получить с помощью свойства System. Management. Automation. ерроррекорд. Exception объекта System. Management. Automation. ерроррекорд .
идентификатор ошибки, предоставляющий целевой указатель, который может использоваться в целях диагностики, а также скрипты Windows PowerShell для обработки определенных условий ошибок с определенными обработчиками ошибок. Каждая запись об ошибке должна содержать идентификатор ошибки (см. Идентификатор ошибки).
Категория ошибок, которая предоставляет общее обозначение, которое можно использовать в целях диагностики. Каждая запись об ошибке должна указывать категорию ошибок (см. раздел Категория ошибок).
Необязательное сообщение об ошибке замены и рекомендуемое действие (см. сообщение об ошибке замены).
Дополнительные сведения о вызове командлета, вызвавшего ошибку. эти сведения задаются Windows PowerShell (см. сообщение о вызове).
Целевой объект, который был обработан при возникновении ошибки. Это может быть входной объект или другой объект, обрабатываемый командлетом. Например, для команды remove-item -recurse c:\somedirectory ошибка может быть экземпляром объекта FileInfo для «к:\сомедиректори\локкедфиле». Сведения о целевом объекте являются необязательными.
Идентификатор ошибки
При создании записи об ошибке укажите идентификатор, обозначающий условие ошибки в командлете. Windows PowerShell объединяет целевой идентификатор с именем командлета, чтобы создать полный идентификатор ошибки. Полный идентификатор ошибки можно получить с помощью свойства System. Management. Automation. ерроррекорд. фулликуалифиедеррорид объекта System. Management. Automation. ерроррекорд . Идентификатор ошибки недоступен для самого себя. Он доступен только в составе полного идентификатора ошибки.
При создании записей об ошибках следуйте приведенным ниже рекомендациям по созданию идентификаторов ошибок.
Создание идентификаторов ошибок, относящихся к условию ошибки. Нацеливание идентификаторов ошибок для целей диагностики и скриптов, которые обрабатывали определенные условия ошибок с помощью конкретных обработчиков ошибок. Пользователь должен иметь возможность использовать идентификатор ошибки для идентификации ошибки и ее источника. Идентификаторы ошибок также позволяют создавать отчеты о конкретных условиях ошибок из существующих исключений, чтобы новые подклассы исключений не требовались.
В общем случае назначьте разные идентификаторы ошибок разным путям кода. Преимущества конечных пользователей от конкретных идентификаторов. Часто каждый путь кода, вызывающий System. Management. Automation. командлет. WriteError или System. Management. Automation. командлет. ThrowTerminatingError * , имеет свой собственный идентификатор. В качестве правила определите новый идентификатор при определении новой строки шаблона для сообщения об ошибке и наоборот. Не используйте сообщение об ошибке в качестве идентификатора.
При публикации кода с использованием определенного идентификатора ошибки вы устанавливаете семантику ошибок с этим идентификатором для полного жизненного цикла поддержки продукта. Не используйте его в контексте, который семантически отличается от исходного контекста. При изменении семантики этой ошибки создайте и затем используйте новый идентификатор.
Обычно конкретный идентификатор ошибки следует использовать только для исключений определенного типа CLR. Если тип исключения или тип целевого объекта изменяется, создайте и используйте новый идентификатор.
Выберите текст для идентификатора ошибки, который кратко соответствует ошибке, о которой вы сообщаете. используйте стандартные платформа .NET Framework соглашения об именовании и капитализации. Не используйте пробелы или знаки препинания. Не следует локализовать идентификаторы ошибок.
Не следует динамически создавать идентификаторы ошибок невоспроизводимым способом. Например, не следует включать сведения об ошибке, такие как идентификатор процесса. Идентификаторы ошибок полезны только в том случае, если они соответствуют идентификаторам ошибок, видимым другим пользователям, которые столкнулись с тем же условием ошибки.
Категория ошибки
При создании записи об ошибке укажите категорию ошибки с помощью одной из констант, определенных перечислением System. Management. Automation. ErrorCategory . Windows PowerShell использует категорию ошибок для вывода сведений об ошибках, когда пользователь присваивает $ErrorView переменной значение «CategoryView» .
Старайтесь не использовать константу System. Management. Automation. ErrorCategory NotSpecified . Если у вас есть какие-либо сведения об ошибке или об операции, вызвавшей ошибку, выберите категорию, которая лучше описывает ошибку или операцию, даже если категория не является идеальным соответствием.
сведения, отображаемые Windows PowerShell, называются строкой представления «категория» и формируются из свойств класса System. Management. Automation. ерроркатегоринфо . (Доступ к этому классу осуществляется через свойство Error System. Management. Automation. ерроррекорд. CategoryInfo .)
В следующем списке описаны отображаемые сведения.
Category: определенная Windows PowerShell константа System. Management. Automation. ErrorCategory .
TargetName: по умолчанию имя объекта, обрабатываемого командлетом при возникновении ошибки. Или другая строка, определяемая командлетом.
TargetType: по умолчанию это тип целевого объекта. Или другая строка, определяемая командлетом.
Действие: по умолчанию имя командлета, создавшего запись об ошибке. Или другая строка, определяемая командлетом.
Причина: по умолчанию это тип исключения. Или другая строка, определяемая командлетом.
Сообщение об ошибке замены
При разработке записи об ошибке для командлета сообщение об ошибке по умолчанию поступает из текста сообщения по умолчанию в свойстве System. Exception. Message . это свойство только для чтения, текст сообщения которого предназначен только для целей отладки (в соответствии с рекомендациями платформа .NET Framework). Рекомендуется создать сообщение об ошибке, которое заменит или дополнит текст сообщения по умолчанию. Сделайте сообщение более понятным для пользователя и более конкретным для командлета.
Заменяющее сообщение предоставляется объектом System. Management. Automation. ErrorDetails . Используйте один из следующих конструкторов этого объекта, так как они предоставляют дополнительные сведения о локализации, которые могут использоваться Windows PowerShell.
ErrorDetails (командлет, строка, строка, объект []). Используйте этот конструктор, если строка шаблона является строкой ресурса в той же сборке, в которой реализуется командлет, или если требуется загрузить строку шаблона с помощью переопределения метода System. Management. Automation. командлета. жетресаурцестринг .
ErrorDetails (сборка, строка, строка, объект []): Используйте этот конструктор, если строка шаблона находится в другой сборке и вы не загрузили ее с помощью переопределения System. Management. Automation. командлета. жетресаурцестринг.
сообщение о замене должно соответствовать платформа .NET Framework правилам проектирования для написания сообщений об исключениях с небольшими различиями. Рекомендации о том, что сообщения об исключениях должны быть написаны для разработчиков. Эти замещающие сообщения должны быть написаны для пользователя командлета.
Сообщение об ошибке замены должно быть добавлено перед вызовом методов System. Management. Automation. командлет. WriteError или System. Management. Automation. командлета. ThrowTerminatingError * . Чтобы добавить заменяющее сообщение, задайте свойство System. Management. Automation. ерроррекорд. ErrorDetails записи об ошибке. если это свойство задано, Windows PowerShell отображает свойство System. Management. Automation. ErrorDetails. Message * вместо текста сообщения по умолчанию.
Рекомендуемые сведения о действии
Объект System. Management. Automation. ErrorDetails также может предоставлять сведения о том, какие действия рекомендуются при возникновении ошибки.
Сведения о вызове
если командлет использует system. management. automation. командлет. WriteError или system. management. automation. командлет. Throwterminatingerror * для сообщения о записи об ошибке, Windows PowerShell автоматически добавляет сведения, описывающие команду, которая была вызвана при возникновении ошибки. Эта информация предоставляется объектом System. Management. Automation. инвокатионинфо , который содержит имя командлета, который был вызван командой, самой командой, а также сведения о конвейере или скрипте. Это свойство доступно только для чтения.
Источник