Kończenie skryptu w PowerShell

394

Szukałem sposobu na zakończenie skryptu PowerShell (PS1), gdy wystąpi niemożliwy do naprawienia błąd w funkcji. Na przykład:

function foo() {
    # Do stuff that causes an error
    $host.Exit()
}

Oczywiście nie ma czegoś takiego jak $host.Exit(). Jest $host.SetShouldExit(), ale tak naprawdę zamyka okno konsoli, czego nie chcę. Potrzebuję czegoś równoważnego do Pythona, sys.exit()które po prostu zatrzyma wykonanie bieżącego skryptu bez dalszego adieu.

Edycja: Tak, to tylko exit. Duh.

kprobst
źródło
8
Jeśli chcesz uniknąć zamykania okna PowerShell lub ISE w moim przypadku; zamiast tego użyj „return”. To po prostu kończy bieżący kontekst działania. „Nowy facet” dokładnie wyjaśnia wszystkie opcje do celów edukacyjnych; możesz rozważyć zmianę zaakceptowanej odpowiedzi (obecnie i tak ma więcej głosów) dla przyszłych użytkowników StackOverflow. Umożliwi to również debugowanie skryptu.
ZaxLofful
Czy to odpowiada na twoje pytanie? Czym dokładnie jest „exit” w PowerShell?
Mark Schultheiss

Odpowiedzi:

389

Należy użyć do exitsłowa kluczowego .

Michael Bray
źródło
15
Cholera jasna, gdybym nie był tak przyłapany na próbowaniu wymyślenia, jak zrobić te rzeczy sprytnie, prawdopodobnie spróbowałbym tego na początku i doszedł do wniosku, że to działa :) Dzięki.
kprobst
118
Jak to jest akceptowana odpowiedź? W szczególności „zamyka okno konsoli”, które pytający powiedział „co nie jest tym, czego chcę”.
claudekennilol
3
@claudekennilol Tylko pytający może zaakceptować odpowiedź. Albo przeoczyli fakt, że wyjście ma zamknąć okno, albo zmienili zdanie i uznali to za dopuszczalne.
Iszi
3
Nie zamyka okna konsoli w v3 lub v4, których używam. Cóż, zrobi to, jeśli uruchomisz skrypt z Eksploratora, ale bez względu na to, jak zakończysz skrypt, zrobi to. Jeśli działa z okna poleceń PowerShell, nie zamyka okna.
Joshua Nurczyk
14
Odpowiedź New Guya jest o wiele dokładniejsza i dezerterzy są oznaczani jako zaakceptowani.
Jim Aho
585

Zdaję sobie sprawę, że to stary post, ale często wracam do tego wątku, ponieważ jest to jeden z najlepszych wyników wyszukiwania podczas wyszukiwania tego tematu. Jednak zawsze zostaję bardziej zdezorientowany niż wtedy, gdy przybyłem z powodu sprzecznych informacji. Ostatecznie zawsze muszę przeprowadzić własne testy, aby to rozgryźć. Więc tym razem opublikuję swoje wyniki.

TL; DR Większość osób będzie chciała użyć Exitdo zakończenia uruchomionych skryptów. Jeśli jednak twój skrypt jedynie deklaruje funkcje do późniejszego użycia w powłoce, będziesz chciał użyć ich Returnw definicjach tych funkcji.

Wyjście vs powrót vs przerwa

  • Wyjdź: spowoduje to „wyjście” z aktualnie uruchomionego kontekstu. Wywołanie tego polecenia ze skryptu spowoduje jego zamknięcie. Jeśli wywołasz to polecenie z powłoki, opuści powłokę.

    Jeśli funkcja wywoła polecenie Exit, wyjdzie z dowolnego kontekstu, w którym działa. Jeśli więc funkcja ta zostanie wywołana tylko z działającego skryptu, zakończy działanie tego skryptu. Jeśli jednak skrypt po prostu deklaruje funkcję, aby można jej było użyć z bieżącej powłoki, a ty uruchomisz tę funkcję z powłoki, opuści powłokę, ponieważ powłoka jest kontekstem, w którym działa funkcja obsługująca Exitpolecenie.

    Uwaga: Domyślnie, jeśli klikniesz skrypt prawym przyciskiem myszy, aby uruchomić go w programie PowerShell, po zakończeniu działania skryptu program PowerShell zamknie się automatycznie. Nie ma to nic wspólnego z Exitpoleceniem ani czymkolwiek innym w twoim skrypcie. Jest to tylko domyślne zachowanie programu PowerShell dla skryptów uruchamianych przy użyciu tej konkretnej metody uruchamiania skryptu. To samo dotyczy plików wsadowych i okna wiersza poleceń.

  • Powrót: Powróci do poprzedniego punktu wywoławczego. Jeśli wywołasz to polecenie ze skryptu (poza funkcjami), powróci ono do powłoki. Jeśli wywołasz to polecenie z powłoki, powróci ono do powłoki (która jest poprzednim punktem wywoławczym dla pojedynczego polecenia uruchamianego z powłoki). Wywołanie tego polecenia z funkcji spowoduje powrót do miejsca, z którego funkcja została wywołana.

    Wykonanie wszelkich poleceń po punkcie połączenia, do którego jest zwracany, będzie kontynuowane od tego miejsca. Jeśli skrypt jest wywoływany z powłoki i zawiera Returnpolecenie poza funkcjami, to po powrocie do powłoki nie ma więcej poleceń do uruchomienia, dzięki czemu Returnużywany jest w ten sam sposób jak Exit.

  • Przerwa: spowoduje to wyrwanie się z pętli i zmianę przypadków. Wywołanie tego polecenia, gdy nie jest ono w pętli lub zmieniono wielkość liter, spowoduje wyrwanie się ze skryptu. Jeśli wywołujesz Breakwewnątrz pętli zagnieżdżonej w pętli, wyłamie się ona tylko z pętli, w której została wywołana.

    Istnieje również interesująca funkcja Break której można poprzedzić pętlę etykietą, a następnie wyjść z tej pętli z etykietą, nawet jeśli Breakpolecenie jest wywoływane w kilku zagnieżdżonych grupach w tej pętli z etykietą.

    While ($true) {
        # Code here will run
    
        :myLabel While ($true) {
            # Code here will run
    
            While ($true) {
                # Code here will run
    
                While ($true) {
                    # Code here will run
                    Break myLabel
                    # Code here will not run
                }
    
                # Code here will not run
            }
    
            # Code here will not run
        }
    
        # Code here will run
    }
Nowy chłopak
źródło
39
Warto również zauważyć, że Exitmożna przyjąć kod powrotu jako parametr (domyślnie 0) - np Exit 3.
aucuparia,
2
Zgadzam się, to jest o wiele lepsza odpowiedź. „Przerwa” może mieć niezamierzone konsekwencje.
iagomartinez
Nie jestem pewien, czy Twój komentarz na temat „Wyjdź” jest całkowicie poprawny, chociaż ogólnie jest to świetna odpowiedź. Wyjście wydaje się powodować zamknięcie ISE w sposób, w jaki wydaje się, że nic innego się nie dzieje. Samo wyjście z kontekstu (na przykład ukończenie skryptu) tego nie robi.
Bill K,
1
@BillK Rzeczywiście. Zaktualizowałem odpowiedź. Kiedy pisałem to po raz pierwszy, nie pamiętam, aby znaleźć oficjalną dokumentację dotyczącą Exit. Zrobiłem wtedy Get-Command Exiti Get-Alias Exitbez rezultatów. Następnie sprawdziłem, czy jest to słowo kluczowe, i nie znalazłem na nim oficjalnej dokumentacji. Patrząc na to teraz, nie wiem jednak, jak doszedłem do tego wniosku. Oczywiście jest to słowo kluczowe ( technet.microsoft.com/en-us/library/hh847744.aspx ). Być może dlatego, że Exit jest jednym z niewielu słów kluczowych, które nie mają własnego tematu about_ help, dlatego też lista tematów na lewym pasku bocznym go nie zawierała.
Nowy facet
6
Co z rzutem?
JDC
80

Exitzamknie również PowerShell. Jeśli chcesz „zerwać” z bieżącej funkcji lub skryptu - użyj Break:)

If ($Breakout -eq $true)
{
     Write-Host "Break Out!"
     Break
}
ElseIf ($Breakout -eq $false)
{
     Write-Host "No Breakout for you!"
}
Else
{
    Write-Host "Breakout wasn't defined..."
}
EverydayNerd
źródło
5
Nie używaj, breakjeśli chcesz po prostu wyjść z bieżącej funkcji ... skrypty wywoływania również mogą zostać zakłócone!
DannyMeister
49

Błąd zapisu dotyczy błędów nie kończących się, a błąd rzucania błędów

Polecenie cmdlet Write-Error deklaruje błąd nie kończący się. Domyślnie błędy są przesyłane w strumieniu błędów do wyświetlanego programu hosta wraz z danymi wyjściowymi.

Błędy nie kończące się zapisują błąd do strumienia błędów, ale nie przerywają przetwarzania poleceń. Jeśli zadeklarowany zostanie błąd nie kończący się na jednym elemencie w kolekcji elementów wejściowych, polecenie kontynuuje przetwarzanie pozostałych elementów w kolekcji.

Aby zgłosić błąd zakończenia, użyj słowa kluczowego Rzut. Aby uzyskać więcej informacji, zobacz about_Throw ( http://go.microsoft.com/fwlink/?LinkID=145153 ).

Greg Bray
źródło
4
To wydaje się najbardziej prawidłowym sposobem zakończenia działania z błędem. Deleguje na osobę dzwoniącą próbę obsłużenia błędu, co jest znacznie lepsze niż po prostu próba nagłego zakończenia.
Paul Turner
Dla mnie, przynajmniej w funkcjach modułu, wyrzucaj wyjścia, ale nie ustawiam kodu wyjścia. Zostało to wykonane przez CLI np powershell -command "& module-function ...". Musiałem przekonwertować te funkcje, aby rzucić do owijającego try-catch i wyjść z tego owijającego catch, aby faktycznie wyprowadzić kod wyjścia błędu.
Josh
2
Nie zapomnij $PSCmdlet.ThrowTerminatingError()o przypadkach, gdy rzut nie może wykonać zadania (znany problem bez błędów kończących od throw)
Djarid
33

Kończy ten proces i nadaje bazowemu systemowi operacyjnemu określony kod wyjścia.

https://msdn.microsoft.com/en-us/library/system.environment.exit%28v=vs.110%29.aspx

[Environment]::Exit(1)

Umożliwi to wyjście z określonym kodem wyjścia, który można odebrać od dzwoniącego.

gabriwinter
źródło
3
W PowerShell możesz po prostu użyć do tego wbudowanego wyjścia, np Exit 1.
Jonas,
3
wbudowane wyjście nie zawsze będzie działać zgodnie z oczekiwaniami. Spróbuj tego w PowerShell: „Exit 5”> test1.ps1 powershell.exe. \ Test1.ps1 $ lastexitcode „[Środowisko] :: Exit (5)”> test2.ps1 powershell.exe. \ Test2.ps1 $ lastexitcode
gabriwinter
1
[Environment]::Exit(1)ma efekt uboczny wychodzenia z mojego okna PowerShell, gdy wywołuję go w skrypcie, ponieważ używanie exitgo nie wydaje się robić.
Josh Desmond
25

Myślę, że Returnzamiast tego szukasz Break. Przerwa jest zwykle używana w przypadku pętli i przerywa tylko od najbardziej wewnętrznego bloku kodu. Użyj Return, aby wyjść z funkcji lub skryptu.

Obrabować
źródło
7
To nie jest poprawne - OP konkretnie prosi o wyjście ze skryptu z funkcji . Returnpo prostu powróci z funkcji, a nie ze skryptu. ( Returnna najwyższym poziomie skryptu skrypt zostanie zakończony, ale to nie było pytanie.)
Michael Sorens,
1
czy ta „odpowiedź” faktycznie komentuje odpowiedź EverydayNerd?
tkokasih
22

Zgłoszenie wyjątku będzie dobre, szczególnie jeśli chcesz wyjaśnić przyczynę błędu:

throw "Error Message"

Spowoduje to wygenerowanie błędu zakończenia.

Amr Bahaa
źródło
3
Nie sądzę, żeby to dodało więcej niż odpowiedź Grega Braya prawie rok wcześniej stackoverflow.com/a/20556550/695671
Jason S
12

Być może lepiej jest użyć „pułapki”. Pułapka programu PowerShell określa blok kodu do uruchomienia, gdy wystąpi błąd lub błąd. Rodzaj

Get-Help about_trap

aby dowiedzieć się więcej o instrukcji pułapki.

fpschultze
źródło
10

Przypadkowo odkryłem, że (np. Po prostu tam , gdzie etykieta nie istnieje ) wydaje się, że wyłamuje się z całego skryptu (nawet z funkcji) i utrzymuje hosta przy życiu. W ten sposób możesz stworzyć funkcję, która łamie skrypt z dowolnego miejsca (np. Pętla rekurencyjna) bez znajomości bieżącego zakresu (i tworzenia etykiet):Break <UnknownLabel>Break ScriptScript

Function Quit($Text) {
    Write-Host "Quiting because: " $Text
    Break Script
} 
żelazo
źródło
1
Twoja odpowiedź jest prawdziwa, ale pamiętaj, że może to powodować problemy dla osób wywołujących skrypt, jeśli nie zgadzają się z twoją chęcią wyjścia z całego skryptu: stackoverflow.com/questions/45746588/...
DannyMeister
5

Użyłem tego do ponownego uruchomienia programu. Nie wiem, czy to by pomogło, ale jest to prosta instrukcja if wymagająca tylko dwóch różnych wpisów. Dla mnie działało to w PowerShell.

$rerun = Read-Host "Rerun report (y/n)?"

if($rerun -eq "y") { Show-MemoryReport }
if($rerun -eq "n") { Exit }

Nie wiem, czy to pomaga, ale wierzę, że byłoby to zgodne z zakończeniem programu po jego uruchomieniu. Jednak w tym przypadku każde zdefiniowane wejście wymaga wyszczególnionego i skategoryzowanego wyniku. Możesz również poprosić exit o wywołanie nowego wiersza polecenia i zakończenie programu w ten sposób.

Michael Meli
źródło