Лучший отвечающий
Не отрабатывает Catch в скрипте powershell

Вопрос
-
Добрый день! Если скрипт powershell вида:
try
{ command -ErrorAction Stop | command | command -ErrorAction Stop
command -ErrorAction Stop
command -ErrorAction Stop
}
catch { Write-Output "Error: $PSItem" | Out-File -FilePath .\errlog.txt }
-
В начале скрипта я размещаю файл блокировки в целевой директории. По завершении - удаляю.
Я вижу в логах ошибку:
Сообщение об ошибке = Выполнение команды остановлено, так как привилегированной переменной
"ErrorActionPreference" или общему параметру присвоено значение Stop. Не удается найти путь...
Но при этом не вижу файл блокировки и не вижу содержимого $PSItem. Складывается впечатление, что -ErrorAction Stop в связке с Catch не прерывает работу скрипта при ошибке, а лишь перехватывает. И скрипт продолжает выполняться дальше. Если это так, то почему нет содержимого $PSItem?
- Изменено Whols 24 февраля 2021 г. 10:00
24 февраля 2021 г. 8:17
Ответы
-
Благодарю, разобрался! Я видел сообщение об исключении в команде GetChildItem, ошибочно считая, что ранние команды (в том числе запись файла блокировки) выполнены. При отсутствии $ErrorActionPreference = "Stop" скрипт выполнялся дальше (ну, недоступен сетевой путь да и черт с ним! - (с) posh) . Останавливался как раз на нужном мне участке и вызывал исключение, которое следом пишет в лог находящийся (внимание!) на том же сетевом ресурсе (додумался тоже - а что, удобно, все в одном месте и данные и результат работы).
В итоге, две ошибки в журнале событий и ни одного факта выполнения в директории.-
Что касается прерывание работы скрипта - это не совсем то, что мне было нужно, т.к. вызывая исключение я могу перехватить (любое) одной строкой в скрипте и понять, что именно вызвало остановку.
Get-ChildItem "$SrcPath\Свет" -Fi *_base.jpg -R |
Where-Object {$_.LastWriteTime -GT ((Get-Date).AddDays(-1))} |
ForEach-Object {Copy-Item -Path ($_.FullName) -D "$Outpath\Свет\" -Force -ErrorAction Stop
}Catch { Write-Output "Operation closed with an error: $PSItem" | Out-File -FilePath .\errlog.txt }
Вот пример рекурсивного копирования с прерыванием работы в случае любой ошибки на этапе копирования.
-
Под левым карманом я имел ввиду следующее - если для функции уже предопределена переменная, в которую разработчик заботливо перенес данные, то лучше использовать в этой функции именно ее, а не делать отдельный вызов. К тому же, обработчик Catch сам по себе содержит (может содержать) ряд команд, ошибки в которых приведут к изменению стека $Error.
- Помечено в качестве ответа Whols 4 марта 2021 г. 5:52
25 февраля 2021 г. 12:48
Все ответы
-
то что вы написали тут не имеет ничего общего с тем что вы выполняете.
у вас скорее всего ошибка синтаксиса, поэтому страдает логика, а это невозможно проверить и поправить на том что вы привели.Подход с -ErrorAction "Stop" для каждой команды это не самое правильное решение. Используйте $ErrorActionPreference = "Stop" вначале скрипта или в начале блока Try{}
The opinion expressed by me is not an official position of Microsoft
- Изменено Vector BCOModerator 24 февраля 2021 г. 11:19
24 февраля 2021 г. 11:17Модератор -
Спасибо за ответ. При написании скрипта я руководствовался этим:
https://docs.microsoft.com/ru-ru/powershell/scripting/learn/deep-dives/everything-about-exceptions?view=powershell-7.1
Попробую указать $ErrorActionPreference. Не совсем понимаю, правда, как это скажется на связке Try-Catch - сейчас я задаю список операций через -ErrorAction, любая ошибка в которых, вызывает исключение и запускает обработчик Catch. Если я правильно понял, $ErrorActionPreference = "Stop" указывает, что ВСЕ ошибки должны вызывать остановку скрипта. В этом случае блок Catch, который перехватывает только исключения мне уже не нужен? Что мне даст остановка скрипта в произвольном месте?
Хочу уточнить, мне нужно понимать, что за ошибка возникла, для этого я пытаюсь читать содержимое $PSItem (как указано в руководстве). Можно, конечно, читать и $Error[0], но это примерно как правой рукой проверять левый карман.
Через перехват исключения я проверяю три операции (не каждую) - доступность файлов на сетевом ресурсе, доступность FTP, возможность записи в FTP-директорию.
24 февраля 2021 г. 15:31 -
В общем, в результате эксперементов выяснил, что Catch прекрасно работает в исходном скрипте при возникновении исключения в вызове GetChildItem. Отдает ошибку и вызывает остановку скрипта. Проблемы начинаются при рекурсивном запросе - такой запрос в несуществующую директорию просто...не вызывает никакой ошибки! По крайней мере при ручном выполнении сценария.
Отделил мух от котлет - проверка доступности идет отдельным запросом с вызовом исключения, дальше уже рекурсивный поиск.
- Изменено Whols 24 февраля 2021 г. 16:08
24 февраля 2021 г. 15:43 -
Мы разговариваем о скрипте которого нигде не видать.
Я могу что-то предугадывать, но не понимаю почему бы просто не опубликовать то что есть?
Есть общие рекоммендации по написанию скриптов и $ErrorActionPreference = 'stop' является одной из таких.
Ошибки бывают терминирующие и не терминирующие, вторые не отлавливаются в Catch блоке.
Оба варианта и -erroraction которые используете вы и то что предлагаю я меняют поведение ошибок и они начинают прерывать выполнение команды в месте ошибки.
$error[0], Catch{$_}, Catch{$PSItem} содержат одну и туже ошибку в общем случае, поэтому ваша аналогия с левым карманом мне не яснаThe opinion expressed by me is not an official position of Microsoft
24 февраля 2021 г. 16:00Модератор -
Благодарю, разобрался! Я видел сообщение об исключении в команде GetChildItem, ошибочно считая, что ранние команды (в том числе запись файла блокировки) выполнены. При отсутствии $ErrorActionPreference = "Stop" скрипт выполнялся дальше (ну, недоступен сетевой путь да и черт с ним! - (с) posh) . Останавливался как раз на нужном мне участке и вызывал исключение, которое следом пишет в лог находящийся (внимание!) на том же сетевом ресурсе (додумался тоже - а что, удобно, все в одном месте и данные и результат работы).
В итоге, две ошибки в журнале событий и ни одного факта выполнения в директории.-
Что касается прерывание работы скрипта - это не совсем то, что мне было нужно, т.к. вызывая исключение я могу перехватить (любое) одной строкой в скрипте и понять, что именно вызвало остановку.
Get-ChildItem "$SrcPath\Свет" -Fi *_base.jpg -R |
Where-Object {$_.LastWriteTime -GT ((Get-Date).AddDays(-1))} |
ForEach-Object {Copy-Item -Path ($_.FullName) -D "$Outpath\Свет\" -Force -ErrorAction Stop
}Catch { Write-Output "Operation closed with an error: $PSItem" | Out-File -FilePath .\errlog.txt }
Вот пример рекурсивного копирования с прерыванием работы в случае любой ошибки на этапе копирования.
-
Под левым карманом я имел ввиду следующее - если для функции уже предопределена переменная, в которую разработчик заботливо перенес данные, то лучше использовать в этой функции именно ее, а не делать отдельный вызов. К тому же, обработчик Catch сам по себе содержит (может содержать) ряд команд, ошибки в которых приведут к изменению стека $Error.
- Помечено в качестве ответа Whols 4 марта 2021 г. 5:52
25 февраля 2021 г. 12:48 -
Под левым карманом я имел ввиду следующее - если для функции уже предопределена переменная, в которую разработчик заботливо перенес данные, то лучше использовать в этой функции именно ее, а не делать отдельный вызов. К тому же, обработчик Catch сам по себе содержит (может содержать) ряд команд, ошибки в которых приведут к изменению стека $Error.
понятно что написав скрипт криво, при условии что в catch у вас может полететь ексепшн, ваша оригинальная ошибка сместиться с позиции 0 на позицию 1, но и автоматические переменные при неумелом использовании могут менять значения
так же трай кетчи можно делать вложенными, делать несколько кетчей розделяя их по типам ошибок итд
пример
$errorActionPreference = "stop" $looperrors = @() try { # main try var1 = 1 # exeption will be here gci $env:userProfile -recurse -file | foreach { try{ #secondary try # some logic here var2 = 2 } catch { $looperrors += $_ } if ($LoopErrors.count -ge 1){ throw "something was not ok in a loop: $loopErrors" } } catch { #main catch write $_ }
The opinion expressed by me is not an official position of Microsoft
25 февраля 2021 г. 13:32Модератор