无论脚本以“常规”方式运行,如何以相同的方式处理错误。 powershell控制台还是在powershell ISE中? [英] How to handle errors in a way that works the same whether the script runs in "regular" powershell console or in powershell ISE?

查看:75
本文介绍了无论脚本以“常规”方式运行,如何以相同的方式处理错误。 powershell控制台还是在powershell ISE中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的脚本:

  $ ErrorActionPreference = Stop 
试试
{
cmd / c mklink a .\DataSvc.sln
}
catch
{
失败
}

(文件DataSvc.sln存在)



当我在ISE powershell控制台中运行它时它会显示失败,当我从常规 powershell控制台执行此操作时,它会输出您没有足够的权限执行此操作。:



ISE:





常规:





我应该怎么写,以便在两种情况下都显示失败?



编辑1



您必须在Windows 10中将其作为普通帐户运行(不提升权限)开发人员模式已关闭。如果您不知道Windows 10开发人员模式是什么,那么就可以(针对此问题)。

解决方案

不幸的是,不同主机对外部程序 stderr 输出进行不同的处理。




  • ISE将stderr输出路由到PowerShells自己的错误流,这解释了为什么写入stderr的任何内容都会触发 try / catch 处理程序。 / p>


    • 在侧节点上:考虑从过时的ISE切换到 Visual Studio代码及其 PowerShell扩展。将来的开发工作集中在此,并且行为与控制台没有什么不同(至少在这方面)。


  • 常规控制台将stderr输出修补到控制台,在这种情况下不会触发错误。




由于 bug ,您可以当前(Windows PowerShell v5.1 / PowerShell Core v6.1)仅通过在PowerShell中重定向流号 2 触发控制台中的错误:

  $ ErrorActionPreference =停止 
尝试{
cmd / c'echo tostderr>& 2 '2>& 1#甚至2> $ null都会触发错误(!)
} catch {
Failed
}

但是,我不会依赖它,因为该错误可能会-并希望会得到修复。



退后一步:如评论中的链接所示,是否外部程序失败应仅从其退出代码派生,而不应从stderr输出的存在而派生,因为许多程序使用stderr输出来报告错误以外的信息 (例如诊断程序)信息或纯警告)。



因此,如果仅使用($ LASTEXITCODE -ne 0)来确定






如果出于某种原因,您要做需要从存在中推断出失败stderr输出的结果-例如,由于某些程序无法正确反映其退出代码中的错误-您可以尝试以下方法,该方法现在应该可以正常工作,并且可以修复上述错误:

  $ ErrorActionPreference =停止 
试试{
cmd / c'echo tostderr&& 2'2>& 1 | ForEach-Object {
if($ _ -is [System.Management.Automation.ErrorRecord]){抛出$ _}
$ _
}
} catch {
失败
}

这取决于将错误流合并到成功流中,并且然后按它们的类型检测源自stderr的行。



请注意,虽然PowerShell在内部运行,但您可以将命令的错误输出收集在变量中,参数 -ErrorVariable / -ev ,调用外部程序时没有类似的机制;但是,已经在此GitHub问题中提出了引入这种机制的建议。


I have this simple script:

$ErrorActionPreference = "Stop"
try 
{ 
    cmd /c mklink a .\DataSvc.sln 
} 
catch 
{ 
    "Failed" 
}

(file DataSvc.sln exists)

When I run it in ISE powershell console it prints "Failed", when I do it from the "regular" powershell console it outputs "You do not have sufficient privilege to perform this operation.":

ISE:

Regular:

How am I supposed to write it so that it prints "Failed" in both cases?

EDIT 1

You must run it as a regular account (not elevated) with Windows 10 Developer Mode turned off. If you do not know what Windows 10 Developer Mode is, then you are fine (for this question).

解决方案

Unfortunately, different hosts treat stderr output from external programs differently.

  • The ISE routes stderr output to PowerShells own error stream, which explains why anything written to stderr triggers the try / catch handler.

    • On a side node: Consider switching from the obsolescent ISE to Visual Studio Code with its PowerShell extension. Future development efforts are focused there, and the behavior doesn't differ from the console (at least in this respect).
  • The regular console patches stderr output through to the console, in which case no error is triggered.

Due to a bug, you can currently (Windows PowerShell v5.1 / PowerShell Core v6.1) trigger an error in the console just by redirecting stream number 2 in PowerShell:

$ErrorActionPreference = "Stop"
try {
  cmd /c 'echo tostderr >&2' 2>&1 # even 2>$null would trigger an error(!)
} catch {
  "Failed"
}

However, I wouldn't rely on that, as the bug may - and hopefully will - get fixed.

Taking a step back: As implied by the link in the comments, whether an external program failed should only ever derived from its exit code, not from the presence of stderr output, as many program use stderr output to report information other than errors (such as diagnostic information or mere warnings).

Thus, if ($LASTEXITCODE -ne 0) alone should be used to determine failure.


If, for some reason, you do need to infer failure from the presence of stderr output - e.g., because some programs don't properly reflect failure in their exit codes - you can try the following approach, which should work now as well as after the aforementioned bug is fixed:

$ErrorActionPreference = "Stop"
try {
  cmd /c 'echo tostderr >&2' 2>&1 | ForEach-Object {
    if ($_ -is [System.Management.Automation.ErrorRecord]) { Throw $_ }
    $_
  }
} catch {
  "Failed"
}

This relies on merging the error stream into the success stream and then detecting stderr-originated lines by their type.

Note that while PowerShell-internally you can collect a command's error output in a variable with common parameter -ErrorVariable / -ev, there is no analogous mechanism when calling external programs; however, introducing such a mechanism has been proposed in this GitHub issue.

这篇关于无论脚本以“常规”方式运行,如何以相同的方式处理错误。 powershell控制台还是在powershell ISE中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆