Patrząc na skrypt Get-WebFile na PoshCode, http://poshcode.org/3226 , zauważyłem to dziwne dla mnie urządzenie:
$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return
Jaki jest tego powód w przeciwieństwie do następującego?
$URL_Format_Error = [string]"..."
Throw $URL_Format_Error
Albo jeszcze lepiej:
$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error
Jak rozumiem, w przypadku błędów nie kończących się należy używać funkcji Write-Error, a do usuwania błędów Throw, więc wydaje mi się, że nie należy używać opcji Write-Error, po której następuje Return. Czy jest jakaś różnica?
powershell
error-handling
powershell-2.0
Bill Barry
źródło
źródło
return
nie nie powrócić do rozmówcy wprocess
blokowym (zaawansowane) funkcji; zamiast tego przechodzi do następnego obiektu wejściowego w potoku. Rzeczywiście, jest to typowy scenariusz generowania błędów nie kończących się: jeśli przetwarzanie dalszych obiektów wejściowych jest nadal możliwe.Throw
generuje błąd kończący skrypt , który nie jest tym samym, co błąd kończący instrukcję, wywołany na przykład przezGet-Item -NoSuchParameter
lub1 / 0
.Odpowiedzi:
Write-Error
powinien być używany, jeśli chcesz poinformować użytkownika o niekrytycznym błędzie. Domyślnie wszystko, co robi, to wyświetla na konsoli komunikat o błędzie w kolorze czerwonym. Nie zatrzymuje kontynuacji potoku lub pętli.Throw
z drugiej strony powoduje tak zwany błąd kończący. Jeśli użyjesz throw, potok i / lub pętla prądowa zostaną zakończone. W rzeczywistości całe wykonanie zostanie zakończone, chyba że użyjesz strukturytrap
lubtry/catch
do obsługi błędu zakończenia.Jest jedna rzecz, na którą należy zwrócić uwagę, jeśli ustawisz
$ErrorActionPreference
ją"Stop"
i użyjeszWrite-Error
, spowoduje to błąd zakończenia .W skrypcie, do którego utworzyłeś łącze, znajdujemy to:
Wygląda na to, że autor tej funkcji chciał zatrzymać wykonywanie tej funkcji i wyświetlić komunikat o błędzie na ekranie, ale nie chciał, aby cały skrypt przestał się wykonywać. Autor skryptu mógł użyć,
throw
jednak oznaczałoby to, żetry/catch
podczas wywoływania funkcji musiałbyś użyć a .return
opuści bieżący zakres, którym może być funkcja, skrypt lub blok skryptu. Najlepiej ilustruje to kod:Wyjście dla obu:
Jedna gotcha tutaj używa
return
zForEach-Object
. Nie przerwie przetwarzania, jak można by się spodziewać.Więcej informacji:
$ErrorActionPreference
: about_Preference_Variablestry/catch
: about_Try_Catch_Finallytrap
: about_Trapthrow
: about_Throwreturn
: about_Returnźródło
return
.Główna różnica między cmdletem Write-Error a słowem kluczowym throw w PowerShell polega na tym, że to pierwsze po prostu drukuje tekst do standardowego strumienia błędów (stderr) , podczas gdy drugie faktycznie kończy przetwarzanie uruchomionego polecenia lub funkcji, która jest następnie obsługiwana przez PowerShell, wysyłając informacje o błędzie do konsoli.
Możesz zaobserwować różne zachowanie tych dwóch w podanych przykładach:
W tym przykładzie
return
dodano słowo kluczowe, aby jawnie zatrzymać wykonywanie skryptu po wysłaniu komunikatu o błędzie do konsoli. Z drugiej strony w drugim przykładziereturn
słowo kluczowe nie jest konieczne, ponieważ zakończenie jest niejawnie wykonywane przezthrow
:źródło
[System.Management.Automation.ErrorRecord]
wystąpienia, które są domyślnie gromadzone w automatycznej$Error
kolekcji ($Error[0]
zawiera najnowszy błąd). Nawet jeśli użyjesz tylkoWrite-Error
z łańcuchem , ten ciąg zostanie zawinięty w[System.Management.Automation.ErrorRecord]
instancję.Ważne : istnieją 2 rodzaje błędów kończących , które niestety łączą aktualne tematy pomocy :
błędy kończące instrukcję , zgłaszane przez polecenia cmdlet w pewnych sytuacjach, których nie można odzyskać oraz przez wyrażenia, w których występuje wyjątek .NET / błąd wykonania PS; tylko instrukcja jest przerywana, a wykonywanie skryptu jest domyślnie kontynuowane .
Skrypt -terminating błędy (dokładniej: runspace kończącego ), jak też wywołane przez
Throw
lub eskalacji jeden z pozostałych typów błędów poprzez błędów działania preferencji wartości zmiennej / parametrówStop
.O ile nie zostaną złapane, kończą bieżący obszar roboczy (wątek); to znaczy, przerywają nie tylko bieżący skrypt, ale także wszystkie jego wywołania, jeśli ma to zastosowanie).
Aby uzyskać kompleksowe omówienie obsługi błędów programu PowerShell, zobacz ten problem z dokumentacją usługi GitHub .
Pozostała część tego postu koncentruje się na błędach nierozstrzygających i kończących instrukcje .
Aby uzupełnić istniejące pomocne odpowiedzi, skupiając się na sednie pytania: Jak zdecydować, czy zgłosić błąd kończący czy nie kończący wypowiedzi ?
Raportowanie błędów polecenia cmdlet zawiera pomocne wskazówki; spróbuję pragmatyczne podsumowanie :
Ogólną ideą niekończący błędów jest umożliwienie „Odporne na uszkodzenia” przetwarzanie dużych zbiorów wejściowych : niewydolność przetworzyć podzbiór obiektów wejściowych nie powinna (domyślnie) abort the - potencjalnie długotrwały - proces jako całość , co pozwala na sprawdzenie błędów i późniejsze ponowne przetworzenie tylko uszkodzonych obiektów - zgodnie z raportami błędów zgromadzonymi w zmiennej automatycznej
$Error
.Zgłoś błąd NIE ZAKOŃCZENIE , jeśli polecenie cmdlet / funkcja zaawansowana:
$PSCmdlet.WriteError()
do zgłaszania błędu nie kończącego się (Write-Error
niestety nie powoduje$?
to ustawienia$False
w zakresie wywołującego - zobacz ten problem na GitHubie ).$?
informuje, czy ostatnie polecenie zgłosiło przynajmniej jeden błąd niepowodujący zakończenia.$?
bycie$False
może oznaczać, że dowolny (niepusty) podzbiór obiektów wejściowych nie został poprawnie przetworzony, prawdopodobnie cały zbiór.$ErrorActionPreference
i / lub wspólny parametr polecenia cmdlet-ErrorAction
mogą modyfikować zachowanie niekończących błędów (tylko) pod względem zachowania wyjścia błędu oraz tego, czy błędy niekończące powinny być eskalowane do błędów kończących skrypt .Zgłoś błąd STATEMENT-TERMINATING we wszystkich innych przypadkach .
$PSCmdlet.ThrowTerminatingError()
, aby wygenerować błąd kończący instrukcję.Throw
słowo kluczowe generuje błąd kończący skrypt, który przerywa cały skrypt (technicznie: bieżący wątek ).try/catch
procedury obsługi lubtrap
instrukcji (której nie można używać z błędami nie kończącymi instrukcji ), ale należy zauważyć, że nawet domyślne błędy kończące instrukcję nie uniemożliwiają uruchomienia reszty skryptu. Podobnie jak w przypadku błędów nie kończących instrukcji ,$?
odzwierciedla,$False
czy poprzednia instrukcja wywołała błąd kończący instrukcję.Niestety, nie wszystkie podstawowe polecenia cmdlet programu PowerShell działają według następujących reguł :
Chociaż jest mało prawdopodobne, że się nie powiedzie,
New-TemporaryFile
(PSv5 +) zgłosi błąd nie kończący się, jeśli się nie powiedzie, pomimo braku akceptowania danych wejściowych potoku i wytwarzania tylko jednego obiektu wyjściowego - zostało to poprawione co najmniej od wersji PowerShell [Core] 7.0, jednak: zobacz ten GitHub problem .Resume-Job
Pomoc twierdzi, że przekazanie nieobsługiwanego typu zadania (takiego jak zadanie utworzone za pomocąStart-Job
, które nie jest obsługiwane, ponieważResume-Job
dotyczy tylko zadań przepływu pracy) powoduje błąd zakończenia, ale nie jest to prawdą w przypadku PSv5.1.źródło
Write-Error
umożliwia konsumentowi funkcji pominięcie komunikatu o błędzie za pomocą-ErrorAction SilentlyContinue
(alternatywnie-ea 0
). Chociażthrow
wymagatry{...} catch {..}
Aby skorzystać z try ... catch with
Write-Error
:źródło
Dodatek do odpowiedzi Andy'ego Arismendiego :
To, czy błąd zapisu kończy proces, czy nie, zależy od
$ErrorActionPreference
ustawienia.Skryptów nietrywialnych,
$ErrorActionPreference = "Stop"
jest zalecanym ustawieniem szybko zawieść.(z http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/ )
Jednak powoduje
Write-Error
zakończenie połączeń.Aby użyć błędu zapisu jako niezakończonego polecenia niezależnie od innych ustawień środowiska, można użyć wspólnego parametru
-ErrorAction
z wartościąContinue
:źródło
Jeśli odczytanie kodu jest poprawne, to masz rację. Kończenie błędów powinno być używane
throw
, a jeśli masz do czynienia z typami .NET, pomocne jest również przestrzeganie konwencji wyjątków .NET.źródło