windows 如何在第一个错误时停止 PowerShell 脚本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9948517/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to stop a PowerShell script on the first error?
提问by Andres Riofrio
I want my PowerShell script to stop when any of the commands I run fail (like set -e
in bash). I'm using both Powershell commands (New-Object System.Net.WebClient
) and programs (.\setup.exe
).
我希望我的 PowerShell 脚本在我运行的任何命令失败时停止(例如set -e
在 bash 中)。我同时使用 Powershell 命令 ( New-Object System.Net.WebClient
) 和程序 ( .\setup.exe
)。
回答by Keith Hill
$ErrorActionPreference = "Stop"
will get you part of the way there (i.e. this works great for cmdlets).
$ErrorActionPreference = "Stop"
会让你在那里做一部分(即这对 cmdlet 很有用)。
However for EXEs you're going to need to check $LastExitCode
yourself after every exe invocation and determine whether that failed or not. Unfortunately I don't think PowerShell can help here because on Windows, EXEs aren't terribly consistent on what constitutes a "success" or "failure" exit code. Most follow the UNIX standard of 0 indicating success but not all do. Check out the CheckLastExitCode function in this blog post. You might find it useful.
但是,对于 EXE,您将需要$LastExitCode
在每次 exe 调用后检查自己并确定是否失败。不幸的是,我不认为 PowerShell 可以提供帮助,因为在 Windows 上,EXE 在构成“成功”或“失败”退出代码的内容方面并不是非常一致。大多数遵循 0 表示成功的 UNIX 标准,但并非所有人都这样做。查看此博客文章中的CheckLastExitCode 函数。你可能会发现它很有用。
回答by goric
You should be able to accomplish this by using the statement $ErrorActionPreference = "Stop"
at the beginning of your scripts.
您应该能够通过使用$ErrorActionPreference = "Stop"
脚本开头的语句来完成此操作。
The default setting of $ErrorActionPreference
is Continue
, which is why you are seeing your scripts keep going after errors occur.
的默认设置$ErrorActionPreference
是Continue
,这就是为什么您会看到脚本在发生错误后继续运行的原因。
回答by aggieNick02
Sadly, due to buggy cmdlets like New-RegKey and Clear-Disk, none of these answers are enough. I've currently settled on the following lines at the top of any powershell script to maintain my sanity.
可悲的是,由于像 New-RegKey 和 Clear-Disk 这样的错误 cmdlet,这些答案都不够。我目前已经在任何 powershell 脚本的顶部确定了以下几行,以保持我的理智。
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
and then any native call gets this treatment:
然后任何本地调用都会得到这种处理:
native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
throw 'error making native call'
}
That native call pattern is slowly becoming common enough for me that I should probably look into options for making it more concise. I'm still a powershell newbie, so suggestions are welcome.
这种原生调用模式对我来说慢慢变得足够普遍,我可能应该研究使其更简洁的选项。我仍然是一个 powershell 新手,所以欢迎提出建议。
回答by alastairtree
You need slightly different error handling for powershell functions and for calling exe's, and you need to be sure to tell the caller of your script that it has failed. Building on top of Exec
from the library Psake, a script that has the structure below will stop on all errors, and is usable as a base template for most scripts.
您需要对 powershell 函数和调用 exe 的错误处理略有不同,并且您需要确保告诉脚本的调用者它已失败。构建在Exec
库 Psake 之上,具有以下结构的脚本将停止所有错误,并可用作大多数脚本的基本模板。
Set-StrictMode -Version latest
$ErrorActionPreference = "Stop"
# Taken from psake https://github.com/psake/psake
<#
.SYNOPSIS
This is a helper function that runs a scriptblock and checks the PS variable $lastexitcode
to see if an error occcured. If an error is detected then an exception is thrown.
This function allows you to run command-line programs without having to
explicitly check the $lastexitcode variable.
.EXAMPLE
exec { svn info $repository_trunk } "Error executing SVN. Please verify SVN command-line client is installed"
#>
function Exec
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
[Parameter(Position=1,Mandatory=0)][string]$errorMessage = ("Error executing command {0}" -f $cmd)
)
& $cmd
if ($lastexitcode -ne 0) {
throw ("Exec: " + $errorMessage)
}
}
Try {
# Put all your stuff inside here!
# powershell functions called as normal and try..catch reports errors
New-Object System.Net.WebClient
# call exe's and check their exit code using Exec
Exec { setup.exe }
} Catch {
# tell the caller it has all gone wrong
$host.SetShouldExit(-1)
throw
}
回答by Lucas
A slight modification to the answerfrom @alastairtree:
对@alastairtree的回答稍作修改:
function Invoke-Call {
param (
[scriptblock]$ScriptBlock,
[string]$ErrorAction = $ErrorActionPreference
)
& @ScriptBlock
if (($lastexitcode -ne 0) -and $ErrorAction -eq "Stop") {
exit $lastexitcode
}
}
Invoke-Call -ScriptBlock { dotnet build . } -ErrorAction Stop
The key differences here are:
这里的主要区别是:
- it uses the Verb-Noun (mimicing
Invoke-Command
) - implies that it uses the call operatorunder the covers
- mimics
-ErrorAction
behavior from built in cmdlets - exits with same exit code rather than throwing exception with new message
- 它使用动词-名词(模仿
Invoke-Command
) - 意味着它使用的电话运营商在幕后
- 模仿
-ErrorAction
内置 cmdlet 的行为 - 以相同的退出代码退出,而不是用新消息抛出异常
回答by Peter L
I'm new to powershell but this seems to be most effective:
我是 powershell 的新手,但这似乎是最有效的:
doSomething -arg myArg
if (-not $?) {throw "Failed to doSomething"}
回答by harvey263
I came here looking for the same thing. $ErrorActionPreference="Stop" kills my shell immediately when I'd rather see the error message (pause) before it terminates. Falling back on my batch sensibilities:
我来这里寻找同样的东西。$ErrorActionPreference="Stop" 当我宁愿在它终止之前看到错误消息(暂停)时立即杀死我的 shell。回到我的批次敏感性:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
I found that this works pretty much the same for my particular ps1 script:
我发现这对于我的特定 ps1 脚本几乎相同:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
回答by ubi
Redirecting stderr
to stdout
seems to also do the trick without any other commands/scriptblock wrappers although I can't find an explanation why it works that way..
重定向stderr
到stdout
似乎也可以在没有任何其他命令/脚本块包装器的情况下解决问题,尽管我找不到解释为什么它会这样工作..
# test.ps1
$ErrorActionPreference = "Stop"
aws s3 ls s3://xxx
echo "==> pass"
aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"
This will output the following as expected (the command aws s3 ...
returns $LASTEXITCODE = 255
)
这将按预期输出以下内容(命令aws s3 ...
返回$LASTEXITCODE = 255
)
PS> .\test.ps1
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass