在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,请执行以下操作:使用“返回”代替。它只是结束当前正在运行的上下文。“新人”彻底解释了出于教育目的的所有选择;您可能要考虑为将来的StackOverflow用户更改您接受的答案(目前仍有更多的赞成票)。它还将允许您调试脚本。
ZaxLofful

Answers:


389

您应该使用exit关键字


15
天哪,如果我不是那么想尝试如何聪明地做这些事情,我可能会尝试从一开始就弄清楚它是可行的:)谢谢。
kprobst 2010年

118
这是如何被接受的答案?它确实确实“关闭了控制台窗口”,询问者说“这不是我想要的”。
claudekennilol 2013年

3
@claudekennilol只有提问者可以接受答案。他们或者错过了退出本来可以关闭窗户的事实,或者他们改变了主意,认为对于他们的目的而言是可以接受的。
Iszi 2013年

3
它不会关闭我使用的v3或v4中的控制台窗口。好吧,如果您从资源管理器中运行脚本,它将成功,但是无论您如何结束脚本,它都会做到这一点。如果从PowerShell命令窗口运行,则不会关闭该窗口。
Joshua Nurczyk 2015年

14
New Guy的答案要彻底得多,删除者将被标记为已接受。
Jim Aho

585

我意识到这是一篇过时的文章,但是我发现自己回到了这个话题很多,因为它是搜索该主题时最热门的搜索结果之一。但是,由于信息冲突,我总是比来时更加困惑。最终,我总是必须执行自己的测试才能弄清楚。所以这次我将发表我的发现。

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

退出vs回归vs休息

  • 退出:这将“退出”当前正在运行的上下文。如果您从脚本中调用此命令,它将退出脚本。如果从外壳程序调用此命令,它将退出外壳程序。

    如果一个函数调用Exit命令,它将退出正在运行的上下文。因此,如果仅从正在运行的脚本中调用该函数,它将退出该脚本。但是,如果您的脚本仅声明了该函数以便可以在当前shell中使用它,而您在shell中运行了该函数,则它将退出shell,因为shell是包含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
aucuparia

2
我同意,这是一个更好的答案。“断裂”会产生意想不到的后果。
iagomartinez

我不确定您对“退出”的评论是否完全正确,尽管总体而言这是一个很好的答案。退出似乎导致ISE关闭,而似乎没有其他动作。仅仅退出上下文(例如,脚本完成)不会执行此操作。
比尔K

1
@BillK确实。我已经更新了答案。当我第一次写这篇文章时,我记得在Exit上找不到任何官方文档。然后我做了Get-Command Exit,并Get-Alias Exit没有结果。然后,我查看了它是否是关键字,却没有找到任何官方文档。但是,现在来看,我不知道我是如何得出这个结论的。显然,它是一个关键字(technet.microsoft.com/zh-cn/library/hh847744.aspx)。可能是因为Exit是唯一没有自己的about_ help主题的关键字之一,因此左侧边栏中的主题列表未包含该主题。
新家伙

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用于终止错误

Write-Error cmdlet声明一个非终止错误。默认情况下,错误会在错误流中发送到要显示的主机程序以及输出。

非终止错误将错误写入错误流,但是它们不会停止命令处理。如果在输入项集合中的一个项上声明了非终止错误,则该命令将继续处理该集合中的其他项。

要声明终止错误,请使用Throw关键字。有关更多信息,请参见about_Throw(http://go.microsoft.com/fwlink/?LinkID=145153)。


4
这似乎是错误终止活动的最正确方法。它委派给调用方以尝试处理错误,这比简单地尝试突然终止要好得多。
保罗·特纳

对我来说,至少在模块函数中,抛出出口但不设置出口代码。这是通过CLI执行的,例如powershell -command "& module-function ..."。我需要将这些函数转换为抛出包装的try-catch并从该包装的catch中退出,以便实际输出错误退出代码。
乔什

2
不要忘记$PSCmdlet.ThrowTerminatingError()为那些无法完成工作的实例(已知问题,没有终止错误throw
Djarid

33

终止此过程,并为基础操作系统提供指定的退出代码。

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

[Environment]::Exit(1)

这将允许您使用可以从呼叫者处提取的特定退出代码退出。


3
在PowerShell中,您只需为此使用内置的Exit即可Exit 1
乔纳斯(Jonas)

3
内置的Exit并不总是能如您所愿。在powershell中尝试以下操作:“退出5”> test1.ps1 powershell.exe。\ test1.ps1 $ lastexitcode“ [环境] :: Exit(5)”> test2.ps1 powershell.exe。\ test2.ps1 $ lastexitcode
gabriwinter

1
[Environment]::Exit(1)当我在脚本中调用Powershell窗口时,它的副作用是退出该窗口,而using exit似乎没有这样做。
乔什·戴斯蒙德

25

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


7
这是不正确的-OP专门要求从函数中退出脚本。Return只会从函数而不是脚本返回。(Return在脚本的顶层将终止脚本,但这不是问题。)
Michael Sorens 2014年

1
这个“答案”实际上是对EverydayNerd答案的评论吗?
tkokasih 2014年

22

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

throw "Error Message"

这将产生一个终止错误。


3
我认为这与Greg Bray近一年前的回答没有多大
Jason S

12

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

Get-Help about_trap

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


10

我偶然发现(例如,简单地,标签不存在的地方)似乎脱离了整个脚本(甚至从函数内部)并保持了主机的生命。 这样,您可以创建一个可以从任何地方中断脚本的函数(例如,递归循环),而无需知道当前作用域(并创建标签):Break <UnknownLabel>Break ScriptScript

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

1
您的回答是正确的,但是请注意,如果脚本调用者不同意您退出整个脚本的愿望,这可能
会给

5

我用它来重新运行程序。我不知道这是否有帮助,但这是一个仅需两个不同条目的if语句。它对我来说很强大。

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

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.