ChatGPT解决这个技术问题 Extra ChatGPT

在 PowerShell 中终止脚本

我一直在寻找一种方法来在函数中发生不可恢复的错误时终止 PowerShell (PS1) 脚本。例如:

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

当然,没有 $host.Exit() 这样的东西。有 $host.SetShouldExit(),但这实际上关闭了控制台窗口,这不是我想要的。我需要的是与 Python 的 sys.exit() 等效的东西,它只会停止执行当前脚本而无需进一步告别。

编辑: 是的,它只是 exit。呃。

如果您想避免在我的情况下关闭 PowerShell 窗口或 ISE;改用“返回”。它只是结束当前运行的上下文。 “新人”彻底解释了所有用于教育目的的选择;您可能需要考虑为未来的 StackOverflow 用户更改您接受的答案(目前有更多的赞成票)。它还允许您调试脚本。
这回答了你的问题了吗? What exactly is "exit" in PowerShell?

N
New Guy

我意识到这是一篇旧帖子,但我发现自己经常回到这个帖子,因为它是搜索这个主题时最热门的搜索结果之一。但是,由于信息相互矛盾,我总是比我来时更加困惑。最终,我总是必须执行自己的测试才能弄清楚。所以这次我将发布我的发现。

TL;DR 大多数人都希望使用 Exit 来终止正在运行的脚本。但是,如果您的脚本只是声明稍后在 shell 中使用的函数,那么您将希望在所述函数的定义中使用 Return

退出 vs 返回 vs 休息

退出:这将“退出”当前运行的上下文。如果您从脚本调用此命令,它将退出脚本。如果您从 shell 调用此命令,它将退出 shell。如果一个函数调用 Exit 命令,它将退出它正在运行的任何上下文。因此,如果仅从正在运行的脚本中调用该函数,它将退出该脚本。但是,如果您的脚本仅声明该函数以便可以在当前 shell 中使用它,并且您从 shell 运行该函数,它将退出 shell,因为 shell 是包含 Exit 命令的函数正在运行的上下文。注意:默认情况下,如果您右键单击脚本在 PowerShell 中运行它,一旦脚本运行完毕,PowerShell 将自动关闭。这与 Exit 命令或脚本中的任何其他内容无关。对于使用这种运行脚本的特定方法运行的脚本来说,这只是默认的 PowerShell 行为。批处理文件和命令行窗口也是如此。

Return:这将返回到上一个调用点。如果您从脚本(在任何函数之外)调用此命令,它将返回到 shell。如果您从 shell 调用此命令,它将返回到 shell(这是从 shell 运行的单个命令的前一个调用点)。如果您从函数调用此命令,它将返回到调用函数的位置。在返回的调用点之后执行任何命令将从该点继续。如果从 shell 调用脚本并且它在任何函数之外包含 Return 命令,那么当它返回到 shell 时,就没有更多命令可以运行,因此以这种方式使用的 Return 与 Exit 基本相同。

Break:这将打破循环并切换案例。如果您在不在循环或 switch case 中调用此命令,它将跳出脚本。如果您在嵌套在循环内的循环内调用 Break,它只会跳出被调用的循环。Break 还有一个有趣的功能,您可以在循环前加上标签,然后您可以跳出即使在该标记循环内的多个嵌套组中调用了 Break 命令,该标记循环也是如此。 While ($true) { # 这里的代码将运行 :myLabel While ($true) { # 这里的代码将运行 While ($true) { # 这里的代码将运行 While ($true) { # 这里的代码将运行 Break myLabel # 代码这里不会运行 } # 这里的代码不会运行 } # 这里的代码不会运行 } # 这里的代码会运行 }


另外值得注意的是,Exit 可以将返回码作为参数(默认为 0) - 例如 Exit 3
我同意,这是一个更好的答案。 “中断”可能会产生意想不到的后果。
@BillK 确实。我已经更新了答案。当我第一次写这篇文章时,我记得在 Exit 上没有找到任何官方文档。然后我做了 Get-Command ExitGet-Alias Exit 没有结果。然后我查看它是否是一个关键字,并没有找到关于它的官方文档。然而,现在看它,我不知道我是如何得出这个结论的。显然它是一个关键字 (technet.microsoft.com/en-us/library/hh847744.aspx)。可能是因为 Exit 是唯一没有自己的 about_ 帮助主题的关键字之一,因此左侧边栏中的主题列表不包括它。
投掷呢?
是否适用于返回 0、1 或 2,以指示传统的错误代码 la exit
S
StackzOfZtuff

您应该使用 the exit keyword


这是如何被接受的答案?它确实“关闭了控制台窗口”,提问者说“这不是我想要的”。
@claudekennilol 只有提问者才能接受答案。要么他们错过了出口应该关闭窗户的事实,要么他们改变了主意并认为这是可以接受的。
它不会关闭我使用的 v3 或 v4 中的控制台窗口。好吧,如果您从资源管理器运行脚本,它会,但无论您如何结束脚本,它都会这样做。如果从 PowerShell 命令窗口运行,它不会关闭窗口。
如果您因异常情况退出,请考虑添加错误代码。像 Exit -1Exit 10 以外的任何数字都将 $? 解析为 False
@claudekennilol 当您从控制台运行脚本时,它不会退出控制台窗口。正如所要求的,这与 python 的 sys.exit 的行为类似。 $host.SetShouldExit() 在从控制台运行脚本时关闭控制台窗口。他不想要的。这似乎有我想要的行为......
P
Peter Mortensen

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..."
}

如果只想跳出当前函数,请不要使用 break...调用脚本也可能会中断!
C
Community

Write-Error 用于非终止错误,throw 用于终止错误

Write-Error cmdlet 声明一个非终止错误。默认情况下,错误在错误流中发送到要显示的主机程序,以及输出。非终止错误将错误写入错误流,但它们不会停止命令处理。如果在输入项集合中的一项上声明了非终止错误,则该命令将继续处理该集合中的其他项。要声明终止错误,请使用 Throw 关键字。有关详细信息,请参阅 about_Throw (http://go.microsoft.com/fwlink/?LinkID=145153)。


这似乎是终止出现错误的活动的最正确方法。它委托调用者尝试处理错误,这比简单地尝试突然终止要好得多。
对我来说,至少在模块函数中,抛出退出但不设置退出代码。这是通过 CLI 执行的,例如 powershell -command "& module-function ..."。我需要将这些函数转换为 throw 到一个包装 try-catch 并从该包装 catch 中退出,以便实际输出错误退出代码。
当 throw 无法完成工作时,不要忘记 $PSCmdlet.ThrowTerminatingError()(已知问题,没有来自 throw 的终止错误)
g
gabriwinter

终止此进程并为底层操作系统提供指定的退出代码。

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

[Environment]::Exit(1)

这将允许您使用特定的退出代码退出,该代码可以从调用者处获取。


在 PowerShell 中,您可以简单地为此使用内置的 Exit,例如 Exit 1
内置的 Exit 并不总是像您期望的那样工作。在 powershell 中试试这个: "Exit 5" > test1.ps1 powershell.exe .\test1.ps1 $lastexitcode "[Environment]::Exit(5)" > test2.ps1 powershell.exe .\test2.ps1 $lastexitcode
当我在脚本中调用它时,[Environment]::Exit(1) 具有退出我的 powershell 窗口的副作用,而使用 exit 似乎不会这样做。
P
Peter Mortensen

抛出异常会很好,特别是如果您想澄清错误原因:

throw "Error Message"

这将产生终止错误。


我认为这不会比格雷格布雷近一年前的回答增加更多stackoverflow.com/a/20556550/695671
我用它来做,例如:抛出“我的变量的当前值:$MyVariable”,这对我很有帮助
R
Rob

我认为您正在寻找 Return 而不是 Break。 Break 通常用于循环,并且仅从最里面的代码块中断。使用 Return 退出函数或脚本。


这是不正确的——OP 专门要求退出脚本从函数内Return 只会从函数返回,而不是从脚本返回。 (脚本 top 级别的 Return 将终止脚本,但这不是问题所在。)
这个“答案”实际上是对 EverydayNerd 答案的评论吗?
@tkokasih 也许它的目的是作为评论,但它的出现方式,它是一个非常棒的答案。它不仅解决了实际问题(使其成为答案)。它还提供了额外的相关信息(因此阁下)。最重要的是,它在两行文本中完成(绝对是kickass'y,如果可以理解的话很容易被误认为是评论)。你会同意吗?
i
iRon

我巧合地发现 Break <UnknownLabel>(例如只是 Break Script标签 Script 不存在的地方)似乎脱离了整个脚本(甚至从函数内部)并保持主机活着。
这样,您可以创建一个函数,在不知道当前范围(并创建标签)的情况下从任何地方(例如递归循环)中断脚本:

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

您的回答是正确的,但请注意,如果您的脚本调用者不同意您退出整个脚本的愿望,这可能会给他们带来问题:stackoverflow.com/questions/45746588/…
f
fpschultze

使用“陷阱”可能会更好。 PowerShell 陷阱指定在发生终止或错误时运行的代码块。类型

Get-Help about_trap

了解有关陷阱语句的更多信息。


M
Michael Meli

我用它来重新运行程序。我不知道它是否会有所帮助,但这是一个简单的 if 语句,只需要两个不同的条目。它对我来说在powershell中工作。

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

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

不知道这是否有帮助,但我相信这类似于在您运行程序后终止程序。但是,在这种情况下,每个定义的输入都需要列出和分类的输出。您还可以让 exit 调用一个新的提示行并以这种方式终止程序。


V
Vopel

我想出了一个巧妙的小技巧来做到这一点,当我想要一个函数退出脚本而不抛出错误,但如果从那里使用该函数则不退出控制台。它涉及仅在运行脚本时定义的 $PSScriptRoot 自动变量。

if($PSScriptRoot){exit}