Не все $Errors одинаково критичны

В PowerShell ошибки делятся на 2 категории:

Terminating Errors — критичные для выполнения команды, ошибки синтаксиса, и т.п. При возникновении такой ошибки дальнейшее выполнение команды прерывается (по умолчанию), и если установлен trap, то выполняется определённый в нём скриптблок.

Non terminating Errors — ошибки которые можно и стерпеть😉 Это ошибки несмотря на которые выполнение команды можно продолжить (и даже получить еще ошибок😉 ). О них и поговорим сегодня.

Для примера разберём два типа ошибок у командлета Copy-Item. Первая ошибка — это несуществующий путь в параметре -Destination:

[PS <6> C:\Root] trap {"Ошибка!"}; Copy-Item -Path test.txt -Destination \\сервер\шара
Ошибка!
Copy-Item : Не найдено сетевое имя.
At line:1 char:28
+ trap {"Ошибка!"}; Copy-Item <<<<  -Path test.txt -Destination \\сервер\шара

Путь указанный в -Destination критичен для командлета Copy-Item, без него невозможна дальнейшая работа, ведь именно в это место должны копироваться все указанные файлы. Поэтому в этом случае ошибка является Terminating, и прерывая действие командлета, вызывает блок кода из конструкции trap.

Теперь вызовем другую ошибку:

[PS <9> C:\Root] trap {"Ошибка!"}; Copy-Item -Path файл.txt -Destination \\сервер\шара
Copy-Item : Cannot find path 'C:\Root\файл.txt' because it does not exist.
At line:1 char:28
+ trap {"Ошибка!"}; Copy-Item <<<<  -Path файл.txt -Destination \\сервер\шара

На этот раз командлет не смог найти файл для копирования, но тем не менее не вызвал блок trap! Дело в том что отсутствие файла источника не является критической (Terminating) ошибкой. Ведь этих файлов может быть указано много, что с того что один из них не существует? Поэтому прерывания команды и не произошло. Вот пример того, какую пользу это может принести:

[PS <10> C:\Root] trap {"Ошибка!"}; Copy-Item -Path файл.txt,file.txt -Destination \\localhost\c$\temp
Copy-Item : Cannot find path 'C:\Root\файл.txt' because it does not exist.
At line:1 char:28
+ trap {"Ошибка!"}; Copy-Item <<<<  -Path файл.txt,file.txt -Destination \\localhost\c$\temp
[PS <11> C:\Root] Test-Path \\localhost\c$\temp\file.txt
True

Тут в качестве источника было указано несколько файлов, и командлет вызвав ошибку, всё же продолжил дальнейшую работу, и скопировал существующий файл file.txt.

Действительно, в большинстве случаев, указывая командлету задачу скопировать несколько файлов, мы хотим чтобы он скопировал все которые сможет, а не прерывался после первой же ошибки. Но может возникнуть и обратная ситуация, когда критичен каждый файл. В таком случае можно сказать командлету о том что все ошибки надо считать Terminating. Делается это указанием параметра -ErrorAction «Stop» (или -EA 1):

[PS <14> C:\Root] del \\localhost\c$\temp\file.txt
[PS <15> C:\Root] trap {"Ошибка!"}; Copy-Item -Path файл.txt,file.txt -Destination \\localhost\c$\temp -ea 1
Ошибка!
Copy-Item : Command execution stopped because the shell variable "ErrorActionPreference" is set to Stop: Cannot find pa
th 'C:\Root\файл.txt' because it does not exist.
At line:1 char:28
+ trap {"Ошибка!"}; Copy-Item <<<<  -Path файл.txt,file.txt -Destination \\localhost\c$\temp -ea 1
[PS <16> C:\Root] Test-Path \\localhost\c$\temp\file.txt
False

И вот что произошло. Так как я сказал командлету останавливаться на любых ошибках — он и остановился после того как не смог скопировать первый же файл, и второй файл скопирован не был. Кроме того был вызван скриптблок указанный в trap.

Можно и повторить тот же эффект, но в пределах всего скрипта, установив в его начале значение специальной переменной $ErrorActionPreference:

$ErrorActionPreference = "Stop"

Ну и третий вариант — когда не надо прерывать выполнение команды, но о наличии Non terminating ошибок узнать всё таки хочется. Просто проверяем количество элементов в переменной указанной в параметре -ErrorVariable:

[PS <23> C:\Root] trap {"Ошибка!"}; Copy-Item -Path файл.txt,file.txt -Destination \\localhost\c$\temp -ErrorVariable e
Copy-Item : Cannot find path 'C:\Root\файл.txt' because it does not exist.
At line:1 char:28
+ trap {"Ошибка!"}; Copy-Item <<<<  -Path файл.txt,file.txt -Destination \\localhost\c$\temp -ErrorVariable e
[PS <24> C:\Root] if ($e.Count -ge 1) {"При выполнении команды произошли ошибки."}
При выполнении команды произошли ошибки.

PS: Напоминалка🙂 Заходим сегодня, в 12:00 по Москве, на вебкаст Андрея, слушать про использование NPS (тот что раньше звался IAS, а по сути RADIUS), в NAP.

комментариев 5 to “Не все $Errors одинаково критичны”

  1. s7s Says:

    А есть возможность отловить и обработаь ошибки в сторонних программах? То есть я из powershell’а вызываю другую программу (например, schtasks.exe) и мне необходимо отловить и по разному обработать различные ошибки. Где копать?

  2. Xaegr Says:

    2 s7s: Да, можно. $LASTEXITCODE https://xaegr.wordpress.com/2008/04/04/errors1/

  3. s7s Says:

    Спасибо, почти то что нужно. Однако, $LASTEXITCODE возвращает одно и тоже значение «1» и при ошибке «Отказано в доступе» и при «Не найден сетевой путь». Хотелось по разному обрабатывать эти ошибки. Есть такая возможность?

  4. Xaegr Says:

    2 s7s: Возможность есть, для этого программа должна возвращать для разных ошибок разные коды🙂
    Ну либо можно просто получать возвращаемый текст, и обрабатывать с помощью например оператора -match.

  5. s7s Says:

    Ну я так и подумал, что возможно дело в программе. А так работать с текстом в powershell еще не очень умею, извернулся так: сначала пингую, если ответа нет, тогда «Ненайден сетевой путь», если же пинг есть, а $LASTEXITCODE = 1, значит «Ошибка доступа»🙂


Обсуждение закрыто.

%d такие блоггеры, как: