obsługa błędu może przyprawić nieco problemu, dla tego kilka zebranych tips’n’tricks, które mogą się przydać.
try/catch nie działa!
czasem nie działa. a to dla tego, że klauza catch zostanie wykonana dla błędów ‚terminujących’. większość błędów natomiast jest ‚zwykłymi’ błędami, nieterminującymi. zachowanie można zmienić albo zmieniając standardowe zachowanie poprzez globalnie ustawienie zmiennej
1 |
$ErrorActionPreference="stop" |
co spowoduje nadpisanie wartości ustawionych dla commandletu.
można też po prostu dodać parametr ‚-ea’ dla konkretnego wywołania. przykład. to nie zadziała zgodnie z oczekiwaniami:
1 |
try { gwmi -class win32_bios -ComputerName tralla} catch { echo 'TU NIE DZIAŁA'} |
napis ‚tu nie działa’ nigdy się nie pojawi. poprawiona wersja:
1 |
try { gwmi -class win32_bios -ComputerName tralla -ea stop} catch { echo "TU NIE DZIAŁA" } |
zapytanie reqrsywne
problem z takim wymuszeniem jest w przypadq zapytań reqrsywnych. scenariusz: chciałbym wyszukać wszystkie katalogi, do których nie mam dostępu. robię reqrsywne przejście po katalogach i ustawiam błąd jako terminujący:
1 |
try { ls -Recurse -Directory C:\Windows\ -ea stop|out-null} catch { write-host "TU NIE DZIAŁA!" } |
niby działa… ale, błąd jest terminujący. co oznacza, że po pierwszym wystąpieniu zakończy działanie wykonania. zobaczymy tylko pierwszy katalog, do którego nie mamy dostępu.
należy skorzystać z innej metody – przekazania błędów do zmiennej. uzysqje się to poprzez parametr ‚ErrorValue’ [alias ‚ev’]. wada jest taka, że zmienna zwracana jest po zakończeniu działania. tutaj już nie ma try/catch!
1 2 3 4 5 |
ls -Recurse -Directory C:\Windows\ -ev LISTINGERRORS|out-null foreach($lerr in $LISTINGERRORS) { write-host "TU NIE DZIAŁA!" $lerr } |
oczywiście jeśli nie chce się oglądać błędów z przebiegu, to można sobie dodać ‚-ea SilentlyContinue’ .
szczegóły błędu
na ekranie nadal będzie śmietnik. fajnie byłoby złapać tylko nazwy – i np. dla nich coś wykonać. dla tego warto zapoznać się z obiektem błędu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
TypeName: System.Management.Automation.ErrorRecord Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetObjectData Method void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.... GetType Method type GetType() ToString Method string ToString() CategoryInfo Property System.Management.Automation.ErrorCategoryInfo CategoryInfo {get;} ErrorDetails Property System.Management.Automation.ErrorDetails ErrorDetails {get;set;} Exception Property System.Exception Exception {get;} FullyQualifiedErrorId Property string FullyQualifiedErrorId {get;} InvocationInfo Property System.Management.Automation.InvocationInfo InvocationInfo {get;} PipelineIterationInfo Property System.Collections.ObjectModel.ReadOnlyCollection[int] PipelineIterationInfo {g... ScriptStackTrace Property string ScriptStackTrace {get;} TargetObject Property System.Object TargetObject {get;} PSMessageDetails ScriptProperty System.Object PSMessageDetails {get=& { Set-StrictMode -Version 1; $this.Except... |
teraz widać co mamy do dyspozycji. wyjątkowo ciekawe do obsługi będą ‚FullyQualifiedErrorId’ pozwalający na zdefiniowanie logiki zależnie od rodzaju błędu, oraz ‚TargetObject’ gdzie powinna znaleźć się informacja o obiekcie, który wygenerował błąd. proponuję przetestować, bo tak najlepiej się uczyć:
1 2 3 4 |
ls -Recurse -Directory C:\Windows\ -ev LISTINGERRORS -ea SilentlyContinue|out-null foreach($lerr in $LISTINGERRORS) { write-host $lerr.TargetObject } |
nie wszystko jest błędem
i na koniec – nie wszystko co my uważamy za błąd, jest błędem. nie mam teraz przygotowanego przykładu, niemniej zdarzało mi się, że commandlet zwracał null lub informował o niepowodzeniu – co było jak najbardziej prawidłowym zachowaniem a nie błędem per se. w takim przypadq trzeba sobie obsłużyć błąd zwykłym if’em bo try/catch tego nie znajdzie.
eN.
Najnowsze komentarze