Поиск на сайте: Расширенный поиск


Новые программы oszone.net Читать ленту новостей RSS
CheckBootSpeed - это диагностический пакет на основе скриптов PowerShell, создающий отчет о скорости загрузки Windows 7 ...
Вы когда-нибудь хотели создать установочный диск Windows, который бы автоматически установил систему, не задавая вопросо...
Если после установки Windows XP у вас перестала загружаться Windows Vista или Windows 7, вам необходимо восстановить заг...
Программа подготовки документов и ведения учетных и отчетных данных по командировкам. Используются формы, утвержденные п...
Red Button – это мощная утилита для оптимизации и очистки всех актуальных клиентских версий операционной системы Windows...
OSzone.net Microsoft PowerShell Перехват ошибок с помощью –ErrorAction (–EA) в Windows PowerShell RSS

Перехват ошибок с помощью –ErrorAction (–EA) в Windows PowerShell

Текущий рейтинг: 4.18 (проголосовало 11)
 Посетителей: 6374 | Просмотров: 9187 (сегодня 0)  Шрифт: - +
В предыдущих выпусках этой рубрики я продемонстрировал, как создать довольно сложное средство интерфейса с помощью Windows PowerShell. Созданное мною средство предлагало ряд вариантов в плане вывода – благодаря встроенным возможностям оболочки и использованию объектов функцией.

Следует признаться, что у моей функции была и слабая сторона – неспособность корректно разбираться с ошибками, которые могут возникнуть, такими как проблемы подключения или разрешений. Именно к ней я и хочу обратиться в выпуске рубрики Windows PowerShell за этот месяц – я рассматриваю возможности обработки ошибок, предлагаемые Windows PowerShell.


Установка ловушки

Ключевое слово Trap («Ловушка») в Windows PowerShell определяет обработчик ошибок. Когда в сценарии происходит исключение, оболочка смотрит, была ли определена ловушка – это значит, что ловушка должна находиться в сценарии до появления исключений. Для этой демонстрации я собрал тестовый сценарий, который, как я знаю, создаст проблему с подключением. Я использую Get-WmiObject для подключения к имени компьютера, которое, как я знаю, не существует в сети. Моя задача заключается в том, чтобы ловушка для ошибок записала неверное имя компьютера в файл, дав мне файл с именами компьютеров, которые не сработали. Я также включу подключения к двум компьютерам, которые находятся в зоне доступа. Сценарий показан на рис. 1.

Рис. 1. Добавление ловушки

trap {
  write-host "Error connecting to $computer" -fore red
  "$computer" | out-file c:\demo\errors.txt -append
  continue
}

$computer = "localhost"
get-wmiobject win32_operatingsystem -comp $computer

$computer = "server2"
get-wmiobject win32_operatingsystem -comp $computer

$computer = "localhost"
get-wmiobject win32_operatingsystem -comp $computer

Данные, выдаваемые этим сценарием и показанные на рис. 2, – не совсем то, что мне нужно. Обратите внимание на то, что сообщение "Error connecting to…" («Ошибка при подключении к…») не отображается. Файл Errors.txt также не был создан. Другими словами, моя ловушка не сделала ничего. Что же случилось?

*
Увеличить

Рис. 2. Это не те выходные данные, на которые я надеялся!

Стоп!

Ключевым моментом здесь является понимание того, что обычное сообщение оболочки об ошибке – это не то же самое, что исключение. (Существуют непрерывающие и прерывающие ошибки. Прерывающие ошибки останавливают исполнение конвейера и приводят к исключению.) Улавливать можно только исключения. Когда происходит ошибка, оболочка сверяется со своей встроенной переменной $ErrorActionPreference, чтобы узнать, что следует делать. По умолчанию переменная имеет значение "Continue", что означает «отобразить сообщение об ошибке и продолжить работать». Изменение этой переменной на "Stop" заставит ее отобразить сообщение об ошибке и произвести исключение, которое можно уловить. Однако это значит, что любая ошибка в сценарии будет давать такой результат.

Лучшей методикой является использования поведения "Stop" лишь тем командлетом, от которого ожидаются проблемы. Это можно сделать, используя параметр –ErrorAction (или –EA), общий параметр, поддерживаемый всеми командлетами. Скорректированная версия сценария показана на рис. 3. Она работает в точности как и ожидается, производя результаты, которые можно найти на рис. 4.

 Рис. 3. Использование -ErrorAction

trap {
  write-host "Error connecting to $computer" -fore red
    "$computer" | out-file c:\demo\errors.txt -append
  continue
}

$computer = "localhost"
get-wmiobject win32_operatingsystem -comp $computer -ea stop

$computer = "server2"
get-wmiobject win32_operatingsystem  -comp $computer -ea stop

$computer = "localhost"
get-wmiobject win32_operatingsystem  -comp $computer -ea stop

*

Рис. 4. Я получаю более полезные результаты при использовании параметра –ErrorAction

Использование Continue в конце ловушки дает указание оболочке возобновить исполнение на строке кода, после строки, создавшей исключение. Другим вариантом является использование ключевого слова Break («Прервать») (я расскажу о нем чуть ниже). Также обратите внимание на то, что переменная $computer, определенная в сценарии, остается действительной внутри ловушки. Это обусловлено тем, что ловушка является дочерней областью самого сценария, а это значит, что ловушка может видеть все переменные внутри сценария (дополнительные сведения об этом также будут чуть ниже).

Все дело в области

Особенно коварным аспектом улавливания ошибок в Windows PowerShell является использование области. Сама оболочка представляет собой глобальную область, содержащую все, что происходит внутри оболочки. Сценарий при выполнении получает собственную область. В случае определения функции, внутренность функции является ее собственной, частной областью и так далее. Это создает своего рода родительскую/дочернюю иерархию.

Когда происходит исключение, оболочка ищет ловушку в текущей области. Это значит, что исключение внутри функции будет искать ловушку внутри этой функции. Если оболочка находит ловушку, она исполняет ловушку. Если в конце ловушки стоит Continue, оболочка возобновит исполнение строки кода, следующей за той, что вызвала исключение – оставаясь в той же области. Вот немного псевдокода, чтобы помочь проиллюстрировать это:

01  Trap {
02    # Log error to a file
03    Continue
04  }
05  Get-WmiObject Win32_Service –comp "Server2" –ea "Stop"
06  Get-Process

В случае ошибки в строке 5 исполнится ловушка в строке 1. Ловушку завершает Continue, так что исполнение продолжится на строке 6.

Теперь рассмотрим этот немного другой экземпляр области:

01  Trap {
02    # Log error to a file
03    Continue
04  }
05
06  Function MyFunction {
07    Get-WmiObject Win32_Service –comp "Server2" –ea "Stop"
08    Get-Process
09  }
10
11  MyFunction
12  Write-Host "Testing!"

Если ошибка произойдет на строке 7, оболочка будет искать ловушку внутри области функции. Таковой нет, так что оболочка выходит из области функции и ищет ловушку в родительской области. Ловушка там есть, так что она исполняется в строке 1. В данном случае Continue возобновится на строке кода в той же области, что следовала за исключением – это строка 12, а не строка 8. Другими словами, оболочка не входит обратно в функцию после выхода из нее.

Теперь сравните это поведение с данным примером:

01  Function MyFunction {
02    Trap {
03      # Log error to a file
04      Continue
05    }
06    Get-WmiObject Win32_Service –comp "Server2" –ea "Stop"
07    Get-Process
08  }
09
10  MyFunction
11  Write-Host "Testing!"

В данном случае ошибка на строке 6 исполнит ловушку на строке 2, оставаясь внутри области функции. Ключевое слово Continue останется внутри области, возобновляя исполнение на строке 7. Это достоинство включения ловушки в область, где ожидается ошибка, – невыход из области и способность возобновить выполнение внутри нее. Но что если данный метод не работает в конкретном случае?

Командлет месяца: Compare-Object

Это замечательное средство для управления нормативами настройки. Compare-Object или его псевдоним Diff, разработан для сравнения друг с другом двух наборов объектов. По умолчанию, он сравнивает каждое свойство каждого объекта и все различия выдаются командой. Представим себе, что службы сервера настроены именно так, как надо. Достаточно выполнить это, чтобы создать норматив:

Get-Service | Export-CliXML c:\baseline.xml

Почти каждый объект может быть передан Export-CliXML, который превратить объекты в файл XML. Позднее можно выполнить ту же команду (такую как Get-Service) и сравнить результаты с сохраненным XML. Вот так:

Compare-Object (Get-Service) (Import-CliXML
  c:\baseline.xml) –property name

Добавление параметра –property заставляет сравнение рассматривать лишь это свойство, а не весь объект. В этом случае будет получен список имен служб, отличающихся от норматива, дающий знать, были ли какие-то службы добавлены или удалены после его создания.

Вырываясь из ловушки

Ранее я упомянул ключевое слово Break. Рис. 5 показывает пример того, как ключевое слово Break можно применить в деле.

 Рис. 5. Использование ключевого слова Break

01  Trap {
02    # Handle the error
03    Continue
04  }
05
06  Function MyFunction {
07    Trap {
08      # Log error to a file
09      If ($condition) {
10        Continue
11      } Else {
12        Break
13      }
14    }
15    Get-WmiObject Win32_Service –comp "Server2" –ea "Stop"
16    Get-Process
17  }
18
19  MyFunction
20  Write-Host "Testing!"

Быстрый обзор пути цепи исполнения таков. Строка 19 исполняется первой, вызывая функцию на строке 6. Строка 15 исполняется и создает исключение. Это исключение оказывается уловленным на строке 7 и затем, на строке 9, ловушка должна принять решение. Предполагая, что $condition имеет значение True, ловушка возобновит исполнение на строке 16.

Но если $condition имеет значение False, ловушка использует Break. Это означает выход из текущей области и передачу первоначального исключения выше, родителю. С точки зрения оболочки это значит, что строка 19 создала исключение, которое улавливается строкой 1. Ключевое слово Continue заставит оболочку возобновить исполнение на строке 20.

В действительности обе эти ловушки имели бы немного больше кода, чтобы разбираться с записью ошибок и так далее. В данном примере я просто опустил этот функциональный код, чтобы реальный процесс было проще видеть.


Зачем беспокоиться?

В каких случаях необходимо применять улавливание ошибок? Только в тех, когда предполагается возможность ошибки и требуется какое-то иное поведение, чем простое сообщение об ошибке – например, запись ошибки в файл или отображение более полезного сообщения о ней.

Обычно я включаю сообщения об ошибках в более сложные сценарии, чтобы можно было разбираться с ошибками, которые я предвижу. Они включают такие ошибки, как проблемы подключения или разрешений, но не ограничены ими.

Чтобы разобраться в улавливании ошибок, определенно нужно немного больше времени и усилий. Но по мере перехода к более сложным задачам внутри Windows PowerShell улавливание ошибок будет вполне стоить вложенных усилий, помогая создать более отполированное и профессиональное средство.

Автор: Дон Джонс  •  Иcточник: TechNet Magazine  •  Опубликована: 13.02.2009
Нашли ошибку в тексте? Сообщите о ней автору: выделите мышкой и нажмите CTRL + ENTER


Оценить статью:
Вверх
Комментарии посетителей
Комментарии отключены. С вопросами по статьям обращайтесь в форум.