Глядя на скрипт Get-WebFile на PoshCode, http://poshcode.org/3226 , я заметил странное для меня устройство:
$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return
В чем причина этого, а не в следующем?
$URL_Format_Error = [string]"..."
Throw $URL_Format_Error
Или даже лучше:
$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error
Как я понимаю, вы должны использовать Write-Error для нескончаемых ошибок и Throw для завершающих ошибок, поэтому мне кажется, что вы не должны использовать Write-Error с последующим возвратом. Есть ли разница?
powershell
error-handling
powershell-2.0
Билл Барри
источник
источник
return
это не возвращение к вызывающему вprocess
блоке (расширенный) функции; вместо этого он переходит к следующему входному объекту в конвейере. Действительно, это типичный сценарий для генерации нескончаемых ошибок: если обработка дополнительных входных объектов все еще возможна.Throw
генерируется ошибка, определяющая сценарий , которая не совпадает с ошибкой, определяющей оператор, которая вызывается, например, с помощьюGet-Item -NoSuchParameter
или1 / 0
.Ответы:
Write-Error
следует использовать, если вы хотите сообщить пользователю о некритической ошибке. По умолчанию все, что он делает, это печатает сообщение об ошибке красным текстом на консоли. Это не останавливает конвейер или цикл от продолжения.Throw
с другой стороны, выдает то, что называется завершающей ошибкой. Если вы используете команду throw, конвейер и / или токовая петля будут прерваны. Фактически, все выполнение будет прекращено, если вы не используете структуруtrap
илиtry/catch
структуру для обработки ошибки завершения.Существует одна вещь , чтобы отметить, если вы установите
$ErrorActionPreference
на"Stop"
и использоватьWrite-Error
его будет производить ошибку завершающего .В скрипте, на который вы ссылаетесь, мы находим это:
Похоже, что автор этой функции хотел остановить выполнение этой функции и отобразить сообщение об ошибке на экране, но не хотел, чтобы весь сценарий прекратил выполнение. Автор сценария мог бы использовать,
throw
однако это означало бы, что вам придется использоватьtry/catch
при вызове функции.return
выйдет из текущей области видимости, которая может быть функцией, сценарием или блоком сценария. Это лучше всего иллюстрируется кодом:Выход для обоих:
Один гоча здесь использует
return
сForEach-Object
. Это не нарушит обработку, как можно было бы ожидать.Больше информации:
$ErrorActionPreference
: about_Preference_Variablestry/catch
: about_Try_Catch_Finallytrap
: about_Trapthrow
: about_Throwreturn
: about_Returnисточник
return
.Основное различие между командлетом Write-Error и ключевым словом throw в PowerShell заключается в том, что первый просто печатает некоторый текст в стандартный поток ошибок (stderr) , тогда как последний фактически прекращает обработку выполняемой команды или функции, которая затем обрабатывается. PowerShell, отправив информацию об ошибке на консоль.
Вы можете наблюдать за их поведением в приведенных вами примерах:
В этом примере
return
было добавлено ключевое слово, чтобы явно остановить выполнение скрипта после отправки сообщения об ошибке на консоль. Во втором примере, с другой стороны,return
ключевое слово не является необходимым, поскольку завершение неявным образом выполняетсяthrow
:источник
[System.Management.Automation.ErrorRecord]
экземпляры, которые по умолчанию , собранное в автоматическом$Error
сборе ($Error[0]
содержит самую последнюю ошибку). Даже если вы просто использоватьWrite-Error
с строкой , эта строка получает завернутые в[System.Management.Automation.ErrorRecord]
экземпляре.Важно : Есть 2 типа оканчивающихся ошибок , которые текущие разделы справки , к сожалению , приравнивать :
Заявление -terminating ошибка, как сообщают командлеты в некоторых невосстанавливаемых ситуациях и выражениямив которых / происходит ошибка PS выполнения исключения .NET; только оператор завершается, и выполнение сценария продолжается по умолчанию .
ошибки, определяющие сценарий (точнее: завершающие пространство выполнения ), как инициируемые, так
Throw
и эскалацией одного из других типов ошибок через значение переменной параметра предпочтения действия ошибкиStop
.Если не пойман, они заканчивают текущее пространство выполнения (поток); то есть они завершают не только текущий скрипт, но и всех его вызывающих, если это применимо).
Для всестороннего обзора обработки ошибок PowerShell см. Эту проблему документации GitHub .
Оставшаяся часть этого поста посвящена ошибкам, не приводящим к завершению оператора и завершающим оператор .
В дополнение к существующим полезным ответам с акцентом на суть вопроса: как вы решаете , сообщать об ошибке, заканчивающейся или не заканчивающейся утверждением ?
Отчет об ошибках командлета содержит полезные рекомендации; позвольте мне попробовать прагматическое резюме :
Общая идея неразрывных ошибок состоит в том, чтобы разрешить «отказоустойчивую» обработку больших входных наборов : отказ обрабатывать подмножество входных объектов не должен (по умолчанию) прерывать - потенциально длительный - процесс в целом , что позволяет вам проверять ошибки и позже обрабатывать только неисправные объекты - как сообщается в записях ошибок, собранных в автоматической переменной
$Error
.Сообщить о недопустимой ошибке, если ваш командлет / расширенная функция:
$PSCmdlet.WriteError()
для сообщения о нескончаемой ошибке (Write-Error
к сожалению, она не$?
должна быть установлена$False
в области вызова - см. Эту проблему GitHub ).$?
сообщает, сообщила ли самая последняя команда хотя бы об одной нескончаемой ошибке.$?
бытие$False
может означать, что любое (непустое) подмножество входных объектов не было должным образом обработано, возможно, весь набор.$ErrorActionPreference
и / или параметр общего командлета-ErrorAction
могут изменять поведение не прекращающихся ошибок (только) с точки зрения поведения вывода ошибок и того, следует ли преобразовывать не прекращающиеся ошибки в определяющие сценарий ошибки .Сообщите об ошибке ЗАКЛЮЧИТЕЛЬНОЕ ЗАЯВЛЕНИЕ во всех других случаях .
$PSCmdlet.ThrowTerminatingError()
для того, чтобы генерировать ошибку завершения оператора.Throw
ключевого слова генерирует сценарий ошибки -terminating , что прерывает весь скрипт (технически: текущая нить ).try/catch
обработчик илиtrap
оператор (который нельзя использовать с ошибками без завершения ), но обратите внимание, что даже ошибки, определяющие операторы по умолчанию, не препятствуют выполнению остальной части сценария. Как и в случае ошибок без завершения ,$?
отражает,$False
вызвало ли предыдущее утверждение ошибку завершения в операторе.К сожалению, не все собственные командлеты ядра PowerShell играют по этим правилам :
Хотя маловероятно, что
New-TemporaryFile
произойдет сбой, (PSv5 +) сообщит о непрекращающейся ошибке, если произойдет сбой, несмотря на то, что он не принимает входные данные конвейера и создает только один выходной объект - это было исправлено по крайней мере в PowerShell [Core] 7.0, однако: см. Этот GitHub вопрос .Resume-Job
В справке утверждается, что передача неподдерживаемого типа задания (например, задания, созданного с помощьюStart-Job
, который не поддерживается, потому чтоResume-Job
применяется только к заданиям рабочего процесса ) вызывает ошибку завершения, но это не так для PSv5.1.источник
Write-Error
позволяет потребителю функции подавить сообщение об ошибке с помощью-ErrorAction SilentlyContinue
(альтернативно-ea 0
). Хотяthrow
требуетtry{...} catch {..}
Чтобы попробовать ... поймать с
Write-Error
:источник
Дополнение к ответу Энди Арисменди :
Завершает ли процесс запись-ошибка или нет, зависит от
$ErrorActionPreference
настройки.Для нетривиальных скриптов,
$ErrorActionPreference = "Stop"
это рекомендуемое значение потерпеть неудачу быстро.(с http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/ )
Тем не менее, он делает
Write-Error
звонки, заканчивающиеся.Чтобы использовать Write-Error как не завершающую команду независимо от других настроек среды, вы можете использовать общий параметр
-ErrorAction
со значениемContinue
:источник
Если вы правильно прочитали код, значит вы правы. Следует использовать для исправления ошибок
throw
, и если вы имеете дело с типами .NET, полезно также следовать соглашениям об исключениях .NET.источник