Завершення сценарію в PowerShell


394

Я шукав спосіб припинити скрипт PowerShell (PS1), коли в функції виникає непоправна помилка. Наприклад:

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

Звичайно, такого немає $host.Exit(). Є $host.SetShouldExit(), але це фактично закриває вікно консолі, а це не те, що я хочу. Мені потрібно щось еквівалентне Python, sys.exit()що просто зупинить виконання поточного сценарію без додаткових зусиль.

Редагувати: Так, це просто exit. Дух.


8
Якщо ви хочете уникнути закриття вікна PowerShell або ISE в моєму випадку; використовувати замість "return". Це просто закінчує поточний контекст запуску. "Новий хлопець" ретельно пояснює всі варіанти навчальних цілей; ви можете подумати про зміну прийнятої відповіді (на даний момент набрав більше голосів) для майбутніх користувачів StackOverflow. Це дозволить також налагодити сценарій.
ZaxLofful

Чи відповідає це на ваше запитання? Що саме таке "вихід" в PowerShell?
Марк Шультейс

Відповіді:


389

Ви повинні використовувати в exitключове слово .


15
Святе дерьмо, якби мене не так наздогнали, намагаючись розібратися, як це робити розумно, я б, мабуть, спробував це для початку і зрозумів, що це працює :) Дякую.
kprobst

118
Як це прийнята відповідь? Це спеціально "закриває вікно консолі", яке запитувач сказав: "Це не те, що я хочу".
claudekennilol

3
@claudekennilol Відповісти може прийняти лише той, хто ставить запитання. Або вони пропустили той факт, що вихід повинен закрити вікно, або вони передумали і вважали прийнятним для своєї мети.
Іссі

3
Він не закриває вікно консолі в v3 або v4, яке я використовую. Що ж, це буде, якщо запустити скрипт від провідника, але як би ви не закінчили сценарій, це зробить це. Якщо ви працюєте з вікна команди PowerShell, воно не закриває вікно.
Джошуа Нурчик

14
Відповідь Нового Гая набагато ретельніша, і десерти відзначаються як прийняті.
Джим Ахо

585

Я розумію, що це стара публікація, але я дуже часто повертаюся до цієї теми, оскільки це один із найкращих результатів пошуку при пошуку цієї теми. Однак я завжди залишаю більше заплутаним, ніж тоді, коли приїхав через конфліктну інформацію. Зрештою, мені завжди доводиться робити власні тести, щоб зрозуміти це. Тож цього разу я опублікую свої висновки.

TL; DR Більшість людей захочуть використовувати Exitдля припинення запущених сценаріїв. Однак якщо ваш скрипт є лише оголошенням функцій, які згодом будуть використані в оболонці, ви хочете використовувати Returnу визначеннях зазначених функцій.

Вихід проти повернення проти перерви

  • Вихід: це "вийде" з поточного контексту. Якщо ви зателефонуєте до цієї команди зі скрипту, вона вийде із сценарію. Якщо ви викликаєте цю команду з оболонки, вона вийде з оболонки.

    Якщо функція викликає команду Exit, вона вийде з будь-якого контексту, в якому вона запущена. Тож якщо ця функція буде викликана тільки з запущеного сценарію, вона вийде з цього сценарію. Однак якщо ваш скрипт просто оголошує функцію, щоб вона могла бути використана з поточної оболонки, і ви запустите цю функцію з оболонки, вона вийде з оболонки, оскільки оболонка - це контекст, в якому виконується функція, що містить Exitкоманду.

    Примітка. Якщо ви натиснете правою кнопкою миші на скрипт, щоб запустити його в PowerShell, після запуску сценарію PowerShell автоматично закриється. Це не має нічого спільного з Exitкомандою або чим-небудь іншим у вашому сценарії. Це просто поведінка PowerShell за замовчуванням для сценаріїв, які виконуються за допомогою цього конкретного методу запуску сценарію. Те саме стосується пакетних файлів та вікна командного рядка.

  • Повернення: Це повернеться до попереднього пункту дзвінка. Якщо ви викликаєте цю команду зі скрипту (поза будь-якими функціями), вона повернеться до оболонки. Якщо ви викликаєте цю команду з оболонки, вона повернеться до оболонки (яка є попередньою точкою виклику для однієї команди, запущеної з оболонки). Якщо ви викликаєте цю команду з функції, вона повернеться туди, куди колись ця функція викликалася.

    Виконання будь-яких команд після точки виклику, до якої вона повертається, триватиме з цієї точки. Якщо скрипт викликається з оболонки, і він містить Returnкоманду поза будь-якими функціями, тоді, коли він повертається до оболонки, більше немає команд для запуску, завдяки чому Returnвикористовуваний таким чином по суті такий же, як Exit.

  • Перерва: це вирветься з циклів і перемикаються випадки. Якщо ви викликаєте цю команду, не перебуваючи в циклі або випадку переключення, вона вийде з сценарію. Якщо ви зателефонуєте Breakвсередину циклу, який вкладений всередині циклу, він вирветься лише з циклу, в який він був викликаний.

    Також є цікава особливість того, Breakде ви можете встановити цикл з міткою, а потім ви можете вийти з цього міченого циклу, навіть якщо Breakкоманда викликається в межах декількох вкладених груп у межах зазначеного циклу.

    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
    }

39
Також варто зазначити, що Exitможе бути прийнятий код повернення як параметр (за замовчуванням до 0) - наприклад Exit 3.
аукупарія

2
Я згоден, це набагато краща відповідь. "Перерва" може мати непередбачувані наслідки.
iagomartinez

Я не впевнений, що ваш коментар про "Вихід" є абсолютно правильним, хоча це загалом чудова відповідь. Схоже, вихід змушує ISE закритись так, що, схоже, нічого іншого не робить. Просто вихід із контексту (наприклад, завершення сценарію) цього не робить.
Білл К

1
@BillK Дійсно. Я оновив відповідь. Коли я вперше написав це, я пам'ятаю, що не знайшов жодної офіційної документації на Exit. Потім я зробив Get-Command Exitі Get-Alias Exitбез результатів. Потім я подивився, чи це ключове слово, і не знайшов офіційної документації на нього. Однак, дивлячись на це зараз, я не знаю, як я прийшов до цього висновку. Зрозуміло, що це ключове слово ( technet.microsoft.com/en-us/library/hh847744.aspx ). Можливо, тому, що Exit - це одне з єдиних ключових слів, яке не має власної довідкової теми about_, і тому список тем у лівій бічній панелі не містив його.
Новий хлопець

6
А як же кинути?
JDC

80

Exitтакож вийде з PowerShell. Якщо ви хочете "вирватися" з лише поточної функції або сценарію - використовуйте 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..."
}

5
Будь ласка, не використовуйте, breakколи ви хочете просто вирватися з поточної функції ... сценарії виклику також можуть бути порушені!
DannyMeister

49

Помилка запису - це помилки , що не припиняються, а кидок - для припинення помилок

Командлет Write-Error оголошує непомилкову помилку. За замовчуванням помилки надсилаються в потоці помилок до хост-програми, що відображається, разом із висновком.

Нескорочені помилки записують помилку в потік помилок, але вони не припиняють обробку команд. Якщо непомітна помилка оголошена на одному елементі в колекції вхідних елементів, команда продовжує обробляти інші елементи колекції.

Щоб оголосити помилку закінчення, використовуйте ключове слово Throw. Для отримання додаткової інформації див. Про_Throw ( http://go.microsoft.com/fwlink/?LinkID=145153 ).


4
Це видається найбільш правильним способом припинити діяльність з помилкою. Він делегує абоненту, щоб спробувати впоратися з помилкою, що набагато краще, ніж просто намагатися припинити різко.
Пол Тернер

Для мене, принаймні, в модульних функціях, кидають виходи, але не встановлюють вихідний код. Це було виконано за допомогою CLI, наприклад powershell -command "& module-function ...". Мені потрібно було перетворити ці функції, щоб перекинути його на завершальний спробу виходу та вийти з цього обгорткового улову, щоб фактично вивести код виходу з помилки.
Джош

2
Не забувайте $PSCmdlet.ThrowTerminatingError()про ті випадки, коли кидок просто не може виконати роботу (відома проблема без жодних кінцевих помилок throw)
Джарід

33

Припиняє цей процес і надає базовій операційній системі вказаний код виходу.

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

[Environment]::Exit(1)

Це дозволить вам вийти з певним кодом виходу, який можна отримати у абонента.


3
У PowerShell ви можете просто використовувати для цього вбудований Exit, наприклад Exit 1.
Йонас

3
вбудований вихід не завжди працюватиме так, як ви очікували. Спробуйте це в PowerShell: "Вихід 5"> test1.ps1 powershell.exe \ test1.ps1 $ lastexitcode "[Environment] :: Вихід (5)"> test2.ps1 powershell.exe \ test2.ps1 $ lastexitcode ..
gabriwinter

1
[Environment]::Exit(1)має побічний ефект від виходу з мого вікна оболонки повноважень, коли я викликаю його в сценарії, де, як користування exit, не здається цього робити.
Джош Десмонд

25

Я думаю, що ви шукаєте Returnзамість цього Break. Розрив зазвичай використовується для циклів і розривається лише з найпотужнішого кодового блоку. Використовуйте Return для виходу з функції або сценарію.


7
Це не правильно - ОП спеціально просить вийти зі сценарію з функції . Returnпросто повернеться з функції, а не зі сценарію. ( Returnна найвищому рівні сценарій припиняє сценарій, але це не питання.)
Майкл Соренс

1
ця відповідь насправді коментує відповідь EverydayNerd?
тікасіх

22

Викинути виняток буде добре, особливо якщо ви хочете уточнити причину помилки:

throw "Error Message"

Це призведе до помилки закінчення.


3
Я не думаю, що це додає більше відповіді Грега Брея майже на рік раніше stackoverflow.com/a/20556550/695671
Jason S

12

Можливо, краще використовувати «пастку». Пастка PowerShell задає блок-код, який потрібно запустити, коли відбувається закінчення або помилка. Тип

Get-Help about_trap

щоб дізнатися більше про заяву про пастку.


10

Я випадково виявив, що (наприклад , там , де мітка не існує ), як видається, вибивається з усього сценарію (навіть з-за функції) та зберігає хост живим. Таким чином, ви можете створити функцію, яка розбиває сценарій з будь-якого місця (наприклад, рекурсивний цикл), не знаючи поточного обсягу (і створюючи мітки):Break <UnknownLabel>Break ScriptScript

Function Quit($Text) {
    Write-Host "Quiting because: " $Text
    Break Script
} 

1
Ваш відповідь вірно, але знайте , що це може викликати проблеми для абонентів вашого скрипта , якщо вони НЕ згодні з вашим бажанням вийти весь сценарій: stackoverflow.com/questions/45746588 / ...
DannyMeister

5

Я використовував це для повторної програми. Я не знаю, чи це допомогло б, але це просто, якщо заява вимагає лише двох різних записів. Для мене це працювало в силі.

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

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

Не знаю, чи це допомагає, але я вважаю, що це буде відповідно до припинення програми після запуску програми. Однак у цьому випадку для кожного визначеного входу потрібен перерахований та категоризований вихід. Ви також можете мати виклик виходу на новий рядок підказок та припиняти програму таким чином.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.