我可以在脚本和交互模式下使PowerShell $ error对象表现一致吗?

时间:2012-07-25 16:32:01

标签: powershell exception-handling powershell-ise

我正在编写一个使用$error来检测和响应错误的PowerShell脚本。我的问题是我根据运行脚本的方式为$error对象获得了不同的行为。如果我以交互方式运行它(特别是从PowerShell ISE),那么错误会被添加到集合中,但是如果我从命令行运行相同的脚本,则会发生相同的错误,但不会添加到集合中。

这是脚本(缩小以说明问题):

# export_exception_test.ps1

# show me how many errors before we start
"Count = " + $error.Count

try {
    # treat non-terminating errors as terminating errors.
    $ErrorActionPreference = "Stop"
    # echo the setting to output
    $ErrorActionPreference

    # use sqlcmd to save the output of stored procedures to text files.
    # The first and third call will fail because the output folder does not exist.
    # The second call will succeed.
    'first call to sqlcmd'
    sqlcmd -S myserver\myinstance -E -s `"`t`" -Q "EXEC mydatabase.dbo.FI_Codes" -b -o "B:\Exports_new\FI_Codes.txt"
    'second call to sqlcmd'
    sqlcmd -S myserver\myinstance -E -s `"`t`" -Q "EXEC mydatabase.dbo.FI_Codes" -b -o "B:\Exports_newt\FI_Codes.txt"
    'third call to sqlcmd'
    sqlcmd -S myserver\myinstance -E -s `"`t`" -Q "EXEC mydatabase.dbo.FI_Codes" -b -o "B:\Exports_new\FI_Codes.txt"
    # and a whole bunch more of these...

    # The error count should be two more than when we started.
    "Count = " + $error.Count
    # And this should be the most recent error message
    "Message = " + $error[0].Message

}
catch [Exception]
{
    'exception was caught!!!'
    "Count in catch clause = " + $error.Count
    $_.Exception.Message
    # the ultimate goal is to return a non-successful return code when the exports fail
    exit 1
}
finally {
    # set this back to what it was
    $ErrorActionPreference = "Continue"

    # primitive trace output
    'finally.'
}

当我从PowerShell ISE运行它时,它的行为与预期一致。 SQLCMD引发一个非终止错误,该错误被捕获并处理。这是输出:

PS U:\> C:\Users\etmatt\Documents\PowerShellScripts\export_exception_test.ps1
Count = 0
Stop
first call to sqlcmd
exception was caught!!!
Count in catch clause = 1
Sqlcmd: Error: Error occurred while opening or operating on file B:\Exports_new\FI_Codes.txt (Reason: The system cannot find the path specified).
finally.

但是当我从命令行运行它时,就像我要设置一个计划任务一样,没有任何内容添加到$error,也没有引发异常。这是输出:

C:\Users\etmatt>powershell.exe -file "C:\Users\etmatt\Documents\PowerShellScripts\export_exception_test.ps1"
Count = 0
Stop
first call to sqlcmd
Sqlcmd: Error: Error occurred while opening or operating on file B:\Exports_new\FI_Codes.txt (Reason: The system cannot find the path specified).
second call to sqlcmd
third call to sqlcmd
Sqlcmd: Error: Error occurred while opening or operating on file B:\Exports_new\FI_Codes.txt (Reason: The system cannot find the path specified).
Count = 0
Message =
finally.

C:\Users\etmatt>

如果我从powershell命令行运行脚本文件而不是cmd.exe(这是有意义的),我也会得到相同的结果。例如:

PS C:\> ."C:\Users\etmatt\Documents\PowerShellScripts\export_exception_test.ps1"

我怀疑这与执行上下文有关,或者可能与解析器模式有关,我仍然不太喜欢,甚至可能是我的个人资料(尽管到目前为止我一直在运行同一台PC下的所有内容)同一帐户)。我在网上看到很多使用try/catch$ErrorActionPreference = "Stop"的基本方法的示例,所以看起来我应该能够做到这一点。

所以我的问题基本上是:我可以让这个脚本像我认为的那样工作吗?如果没有,我有什么误解?我如何捕捉这些错误?如果它有帮助,我不需要对此进行超级详细的异常处理,我只需要知道什么时候出错,以便我的任务监视器可以提醒我。来自powershell.exe的非零返回码就足够了。

我正在调查使用$?$LASTEXITCODE,但我打赌$?会遇到与$error相同的问题,而且两者都只适用于执行的最后一个语句,这是不太理想的,因为我的真实脚本比这个例子长得多。

修改
好的,我已经了解到Windows可执行文件(例如sqlcmd),从不向$error集合添加任何内容,即使它们返回非零退出代码。如果我理解正确,$error仅由cmdlet使用。我让我的脚本重复使用$LASTEXITCODE,虽然我也可以使用$?,因为它识别Windows可执行退出代码,并且对于非零值设置为false。

总而言之,从命令行运行时脚本的行为是正确的预期行为。但仍然不知道为什么我从PowerShell ISE得到了不同的结果。

1 个答案:

答案 0 :(得分:0)

对我来说,我使用cmd /C <command>调用批处理命令,我遇到了类似的问题。对于非零返回代码$?已正确设置但没有$error对象(powershell如何知道?所以这没关系)并且代码在ISE和命令行执行中表现相似。

我的问题是,在$ErrorActionPreference = "Stop"这种情况下,它不会抛出异常。可能是因为它没有$error对象抛出。所以现在我需要在每次调用其他不完整的脚本或程序后检查$?。他们应该为这种情况提出一个很好的解决方案(可能通过抛出内置异常,说调用外部脚本/程序失败)