Обробка помилок в PowerShell (частина 2).
Продовжуємо тему обробки помилок в PowerShell, розпочату в попередній статті. Сьогодні мова піде про обробку переривають помилок (винятків). Треба розуміти, що повідомлення про помилку - це не те ж саме, що виключення. Як ви пам'ятаєте, в PowerShell є два типи помилок - неперервні і переривають.
неперервні помилки дозволяють продовжити роботу, тоді як переривають зупиняють виконання команди. Зупинка призводить до виключення (exception), яке і можна відловлювати і обробляти.
Примітка. Таким же чином можна обробляти і неперервні помилки.Зміна параметра ErrorAction на Stop перерве виконання команди і зробить виняток, яке можна вловити.
Для наочності сгенерируем помилку, спробувавши прочитати файл, на який у нас немає прав. А тепер звернемося до змінної $ Error і виведемо дані про виключення. Як бачите, цей виняток має тип UnauthorizedAccessException і відноситься до базового типу System.SystemException.
Для обробки виключень в PowerShell є кілька способів, які ми сьогодні і розглянемо.
Try/Catch/Finally
Конструкція Try/Catch/Finally призначена для обробки винятків, що виникають в процесі виконання скрипта. У блоці Try розташовується виконуваний код, в якому повинні відслідковуватися помилки.При виникненні в блоці Try перериває помилки оболонка PowerShell шукає відповідний блок Catch для обробки цієї помилки, і якщо він знайдений, то виконує знаходяться в ньому інструкції. Блок Catch може включати в себе будь-які команди, необхідні для обробки виниклої помилки і \ або відновлення подальшої роботи скрипта.
Блок Finally розташовується зазвичай в кінці скрипта. Команди, що знаходяться в ньому, виконуються в будь-якому випадку, незалежно від виникнення помилок. Чи була помилка перехоплена і оброблена блоком Catch або при виконанні скрипта помилок не виникало взагалі, блок Finally буде виконаний.Присутність цього блоку в скрипті необов'язково, основне його завдання - вивільнення ресурсів (закриття процесів, очищення пам'яті і т.п.).
Як приклад в блок Try помістимо код, який читає файли з зазначеної директорії. При виникненні проблем блок Catch виводить повідомлення про помилку, після чого відпрацьовує блок Finally і робота скрипта завершується:
try {
Get-Content -Path "C: \ Files \ *" -ErrorAction Stop
}
catch {
Write-Host "Some error was found."
}
finally {
Write-Host" Finish. "
}
Для блоку Catch можна вказати конкретний тип помилки, додавши після ключового слова Catch в квадратних дужках назву виключення. Так в наступному прикладі вкажемо в якості типу виняток System.UnauthorizedAccessException, яке виникає при відсутності необхідних прав доступу до об'єкта:
try {
Get-Content -Path "C: \ Files \ *" - ErrorAction Stop
}
catch [System.UnauthorizedAccessException]
{
Write-Host "File is not accessible."
}
finally {
Write-Host "Finish."
}
Якщо для блоку Catch зазначений тип помилки, то цей блок буде обробляти тільки цей тип помилок, або тип помилок, успадковані від зазначеного типу. При виникненні іншого типу похибка не буде оброблена.Якщо ж тип не вказано, то блок буде обробляти будь-які типи помилок, що виникають в блоці Try.
Блок Try може включати кілька блоків Catch, для різних типів помилок, відповідно можна для кожного типу помилки задати своє обробник. Наприклад, візьмемо два блоки Catch, один для помилки при відсутності прав доступу, а другий - для будь-яких інших помилок, які можуть виникнути в процесі виконання скрипта:
try {
Get-Content -Path " C: \ Files \ * "-ErrorAction Stop
}
catch [System.UnauthorizedAccessException]
{
Write-Host "File is not accessible."
}
catch {
Write-Host "Other type of error was found:"
Write-Host "Exception type is $ ($ _. Exception.GetType (). Name)"
}
finally {
Write-Host "Finish."
}
Trap
Ще один спосіб обробки помилок - це установка пастки (trap). У цьому варіанті обробник помилок задається за допомогою ключового слова Trap, що визначає список команд, які повинні виконатися при виникненні перериває помилки і виключення.Коли відбувається виключення, то оболонка PowerShell шукає в коді інструкції Trap для даної помилки, і якщо знаходить, то виконує їх.
Візьмемо найпростіший приклад пастки, яка обробляє всі відбулися виключення і виводить повідомлення про помилку:
trap {
Write-Host "Error was found."
}
Get-Content -Path C: \ File \ * -ErrorAction Stop
Так само, як і для try \ catch, ключове слово Trap дозволяє задавати тип виключення, вказавши його в квадратних дужках. Наприклад, можна задати в скрипті кілька пасток, одну націливши на конкретну помилку, а другу на обробку залишилися:
trap [System.Management.Automation.ItemNotFoundException]
{
Write-Host "File is not accessible."
break
}
trap {
Write-Host "Other error was found. "
continue
}
Get-Content -Path C: \ File \ * -ErrorAction Stop
Разом з Trap можна використовувати ключові слова Break і Continue , які дозволяють визначити, чи повинен скрипт продовжувати виконуватися після виникнення перериває помилки.За замовчуванням при виникненні виключення виконуються команди, що входять в блок Trap, виводиться інформація про помилку, після чого виконання скрипта триває з рядка, що викликала помилку:
trap {
Write-Host "Error was found. "
}
Write-Host" Before error. "
Get-Content -Path C: \ File \ * -ErrorAction Stop
Write-Host" After error."
Якщо використовувати ключове слово Break, то при виникненні помилки буде виконано команди в блоці Trap, після чого виконання скрипта буде перервано:
trap {
Write-Host "Error was found."
break
}
Write-Host "Before error. "
Get-Content -Path C: \ File \ * -ErrorAction Stop
Write-Host" After error. "
Як видно з прикладу, команда, наступна за винятком, не відпрацювала і повідомлення "After error."Виведено не було.
Якщо ж в Trap включено ключове слово Continue, то виконання скрипта буде продовжено, так само як і в випадку за замовчуванням. Єдина відмінність в тому, що з Continue похибка не записується в потік Error і не виводиться на екран.
trap {
Write-Host "Error was found."
continue
}
Write-Host" Before error. "
Get-Content -Path C: \ File \ * -ErrorAction Stop
Write-Host" After error. "
Область дії
При вилові помилок за допомогою Trap треба пам'ятати про таку річ, як область дії (scope). Оболонка PowerShell є глобальною областю, в яку входять всі процеси, запущений скрипт отримує власну область, а якщо всередині скрипта визначені функції, то всередині кожної визначена своя, приватна область дії.Це створює свого роду батьківсько-дочірню ієрархію.
З появою виключення оболонка шукає пастку в поточній області. Якщо в ній є пастка, вона виконується, якщо немає - то проводиться вихід у вищу область і пошук пастки там. Коли пастка знаходиться, то відбувається її виконання.Потім, якщо пастка передбачає продовження роботи, то оболонка відновлює виконання коду, починаючи з того рядка, яка викликала виняток, але при цьому залишаючись в тій же області, що не повертаючись назад.
Для прикладу візьмемо функцію Content, всередині якої буде виконуватися наш код.Область дії всередині функції назвемо scope 1, а зовні scope 2:
trap {
Write-Host "Error was found."
continue
}
function Content {
Write-Host "Before error, scope1."
Get-Content -Path C: \ File \ * -ErrorAction Stop
Write-Host "After error, scope 1."
}
Content
Write-Host "After error, scope 2."
При виникненні помилки в функції Content оболонка буде шукати пастку всередині неї.Потім, не знайшовши пастку всередині функції, оболонка вийде з поточної області і буде шукати в батьківській області. Пастка там є, тому буде виконана обробка помилки, після чого Continue відновить виконання скрипта, але вже в батьківській області (scope 2), що не повертаючись назад в функцію (scope 1).
А тепер трохи змінимо скрипт, помістивши пастку всередину функції:
function Content {
trap {
Write-Host "Error was found."
continue
}
Write-Host "Before error, scope 1."
Get-Content -Path C: \ File \ * -ErrorAction Stop
Write-Host "After error, scope 1."
}
Content
Write-Host "After error , scope 2. "
Як бачите, тепер при виникненні помилки усередині функції буде проведена обробка помилки, після чого виконання буде продовжено з тієї рядки, в якій сталася помилка - не виходячи з функції.
Висновок
Якщо порівняти Try/Catch і Trap, то у кожного методу є свої переваги і недоліки . Конструкцію Try/Catch можна більш точно націлити на можливу помилку, так як Catch обробляє тільки вміст блоку Try. Цю особливість зручно використовувати при налагодженні скриптів, для пошуку помилок.
І навпаки, Trap є глобальним оброблювачем, отлавливая помилки у всьому скрипті незалежно від розташування. На мій погляд це більш життєвий варіант, який більше підходить для постійної роботи.
.