Centrum Skryptów - Systemy Operacyjne

W jaki sposób użyć zmiennej $ErrorActionPreference do kontrolowania obsługi błędów przez aplet polecenia?

Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

Witamy w rubryce TechNet, w której Skrypciarze z firmy Microsoft odpowiadają na częste pytania dotyczące używania skryptów w administracji systemu. Jeśli macie jakieś pytania z tej dziedziny, zachęcamy do wysłania e-maila na adres: scripter@microsoft.com. Nie możemy zagwarantować odpowiedzi na każde otrzymane pytanie, ale staramy się jak możemy.

W jaki sposób użyć zmiennej $ErrorActionPreference do kontrolowania obsługi błędów przez aplet polecenia?

Cześć, Skrypciarze! W języku VBScript podobało mi się to, że można było dodać polecenie On Error Resume Next na początku skryptu. Rozwiązywało to wiele problemów. Działało jak czary i naprawiłem w ten sposób wiele skryptów. Brakuje mi takiej funkcjonalności w programie Windows PowerShell.

-- MW

Cześć, MW! Czołem, tutaj skrypciarz Ed Wilson. Czołem, tutaj skrypciarz Ed Wilson. Jest poniedziałek rano. Z zasady lubię poniedziałki. Chociaż szczerze mówiąc nie różnią się bardzo od sobót czy czwartków. Dzień ze skryptami to dzień ze skryptami — każdy jest dobry! Ci z Was, którzy śledzą nas w serwisie Twitter lub Facebook, wiedzą, że łatwo tam natknąć się na mnie lub na Craiga w weekend. Dzisiaj wyjątkowo zamiast herbaty piję kawę Peaberry Kona, pochodzącą z Hawajów. Zwykle wkładam do kawy laskę cynamonu (podłapałem ten zwyczaj na warsztatach z języka VBScript w Lizbonie), ale ta kawa jest tak dobra, że byłoby to niedopuszczalne. To samo tyczy się dodawania do niej mleka i cukru. Tak więc piję ją czarną. A skoro już mowa o Hawajach — świetnie nurkuje się u wybrzeży wyspy Kauai. Kiedyś zrobiłem tam to zdjęcie:

MW, funkcjonalność podobną do użycia polecenia On Error Resume Next można uzyskać, przypisując ciąg znaków SilentlyContinue do zmiennej automatycznej $ErrorActionPreference. Funkcjonalność ta jest tylko podobna, ponieważ nie ukrywa ona wszystkich błędów. Jeśli np. spróbujemy utworzyć nieistniejący obiekt (np. o nazwie foo), program Windows PowerShell wygeneruje błąd. Błąd zawiera informacje, że nie można znaleźć typu foo oraz że zestaw zawierający ten typ nie jest wczytany:

PS C:\> New-Object foo

New-Object : Nie można odnaleźć typu [foo]: upewnij się, że zestaw zawierający ten typ został załadowany.

At line:1 char:11

+ New-Object <<<<  foo

    + CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException

    + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

Aby ukryć ten błąd, należy ustawić wartość zmiennej automatycznej $ErrorActionPreference na SilentlyContinue. Widać to poniżej:

PS C:\> $ErrorActionPreference = "silentlycontinue"

PS C:\> New-Object foo

PS C:\>

To polecenie nie zapobiega wyświetlaniu wszystkich błędów. Wyświetlane są np. błędy dzielenia przez zero. Program Windows PowerShell generuje taki błąd niezależnie od ustawienia wartości zmiennej automatycznej $ErrorActionPreference. Jest to ukazane poniżej:

PS C:\> 1/0

Operacja próbowała wykonać dzielenie przez zero.

At line:1 char:3

+ 1/ <<<< 0

    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException

    + FullyQualifiedErrorId : RuntimeException



PS C:\> $ErrorActionPreference = silentlycontinue

Termin 'silentlycontinue' nie jest rozpoznawany jako aplet polecenia, funkcja, program operacyjny ani plik skryptu. Sprawdź pisownię nazwy lub_

jeśli została podana ścieżka, zweryfikuj jej poprawność i spróbuj ponownie.

At line:1 char:42

+ $ErrorActionPreference = silentlycontinue >>>>

    + CategoryInfo          : ObjectNotFound: (silentlycontinue:String) [], CommandNotFoundException

    + FullyQualifiedErrorId : CommandNotFoundException

Różnica w sposobie działania bierze się stąd, że zmienna automatyczna $ErrorActionPreference kontroluje raportowanie związane z apletami poleceń, ale nie z błędami systemu. Ponadto należy pamiętać, że zmienna automatyczna $ErrorActionPreference działa tylko dla błędów nieprzerywających. Na czym polega różnica między błędami przerywającymi a nieprzerywającymi? Błąd przerywający jest wywoływany przez aplet polecenia (który stosuje metodę ThrowTerminatingError (j.ang.)), kiedy niemożliwe jest dalsze przetwarzanie potoku lub skryptu przez aplet polecenia. Z reguły są to błędy składni.

Błąd nieprzerywający to taki, który nie powoduje przerwania wykonywania apletu polecenia lub skryptu. Próba np. odczytania nieistniejącego pliku tekstowego nie spowoduje, że aplet polecenia Get-Content przestanie działać. Jeśli podana będzie ścieżka do istniejącego pliku, skrypt zadziała bez problemu:

PS C:\> Get-Content foo

Get-Content : Nie można odnaleźć ścieżki 'C:\foo', ponieważ ona nie istnieje.

At line:1 char:12

+ Get-Content >>>>  foo

    + CategoryInfo          : ObjectNotFound: (C:\foo:String) [Get-Content], ItemNotFoundException

    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand

 

PS C:\> Get-Content C:\fso\Computers.txt

win7-pc

hyperv

PS C:\>

Dlatego też można ukryć komunikat o błędzie w pierwszym poleceniu, używając zmiennej automatycznej $ErrorActionPreference. Widać to poniżej:

PS C:\> $ErrorActionPreference = "SilentlyContinue"

PS C:\> Get-Content foo

PS C:\> Get-Content C:\fso\Computers.txt

win7-pc

hyperv

PS C:\>

Niekiedy warto wyświetlać komunikaty o błędach, np. jeśli piszemy skrypt i chcemy się upewnić, że wszystkie używane w nim elementy zależne znajdują się na swoich miejscach. Kiedy prowadziłem warsztaty z języka VBScript, często zdarzało się, że uczestnicy zgłaszali, że skrypt nie działa, ale nie są wyświetlane żadne błędy. Nie musiałem nawet wstawać od biurka — polecałem im tylko oznaczyć wiersz kodu On Error Resume Next jako komentarz. Jedną z wad skryptów publikowanych w Centrum skryptów jest nadużywanie polecenia On Error Resume Next, ponieważ ukrywanie błędów to jak zachęta do złych praktyk. Rozumiem, czemu to polecenie jest używane — nie ma sensu, aby początkujący musieli borykać się z mnóstwem komunikatów o błędach. Kiedyś jednak trzeba wyłączyć ukrywanie błędów i naprawić skrypt. Ukrywanie błędów nie jest problemem, jeśli wiemy, czemu to służy.

Domyślnie wartość zmiennej $ErrorActionPreference jest ustawiona na Continue, co oznacza, że błąd zostanie wyświetlony, ale wykonywanie skryptu (lub polecenia) będzie w miarę możliwości kontynuowane. Zmiennej $ErrorActionPreference można przypisać cztery wartości: SilentlyContinue, Continue, Stop i Inquire.

Ustawienie wartości zmiennej $ErrorActionPreference na Stop spowoduje, że wykonywanie skryptu po wystąpieniu błędu zostanie zatrzymane, nawet jeśli dalsze polecenia mogłyby działać. Widać to na poniższej grafice.

Jeśli chcemy, aby użytkownik skryptu otrzymywał monit o dalsze działanie po wystąpieniu błędu, możemy ustawić tę wartość na inquire. W razie uruchamiania z okna Windows PowerShell ISE spowoduje to wyświetlenie okna dialogowego z pytaniem o działanie, jakie ma zostać wykonane. Jest to ukazane poniżej.

Okno dialogowe jest nieco niejasne, ale jego tytuł to Potwierdzanie. Tak więc okno zawiera informację o nieistnieniu pliku i monit z opcjami dalszego rzetwarzania skryptu, zawieszenia go lub przerwania. Kliknięcie przycisku Tak spowoduje, że błąd zostanie wyświetlony, a skrypt będzie dalej wykonywany. Widać to poniżej.

W razie uruchamiania skryptu z powłoki programu Windows PowerShell (a nie z okna ISE) monit Potwierdzanie jest wyświetlany w obrębie powłoki, zgodnie z tym, co widać poniżej.

MW, to już wszystko, co musisz wiedzieć o używaniu zmiennej $ErrorActionPreference do kontroli obsługi błędów przez aplety poleceń. Jutro przedstawimy kolejny skrypt z serii poświęconej obsłudze błędów.

Skrypciarze Ed Wilson i Craig Liebendorfer

 Do początku strony Do początku strony

Centrum Skryptów - Systemy Operacyjne