如何在没有附带堆栈跟踪的情况下在PowerShell中显示"裸"错误消息?

Pet*_*ale 17 error-handling powershell exit-code stderr

如何从PowerShell写入stderr,或者捕获这样的错误

  • 错误消息显示为错误(真正写入stderr,以便TeamCity和Octopus将其视为错误)
  • 没有堆栈跟踪垃圾混淆了我美丽,简洁的错误信息

这些年来,我throw通过错误或写作经历幸存下来Write-Error,但我已经厌倦了,而且在我的脚本中我只想看到一条简洁的错误信息.我一直在努力的每个组合trap,throw,Write-Error,和-ErrorAction,但无济于事:

try {
  throw "error" # Sample code for a stack overflow. In the theater
  # of your mind, imagine there is code here that does something real and useful
} catch {
  Write-Error "An error occurred attempting to 'do something.' Have you tried rebooting?"
}
Run Code Online (Sandbox Code Playgroud)

这是我想看到的用户体验:

C:\> & .\Do-Something.ps1
An error occurred attempting to 'do something.' Have you tried rebooting?

C:\> ?
Run Code Online (Sandbox Code Playgroud)

相反,我得到:

C:\> & .\Do-Something.ps1
An error occurred attempting to 'do something.' Have you tried rebooting?
At line:1 char:1
+ Do-RealWork
+ ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Do-RealWork

C:\> ?
Run Code Online (Sandbox Code Playgroud)

mkl*_*nt0 14

设置自动$ErrorView变量会'CategoryView'导致PowerShell输出简洁的单行错误表示,但此表示可能并不总是包含足够的信息,因为通常包含错误消息 ; 在正面,传递给的文本反映,但相反,输出在生效时包含特定信息.正在为v6讨论 向PowerShell添加新的错误视图,该视图是单行的,但始终包含所有重要信息.Throw "..." Write-Error'CategoryView'

如果您的PowerShell代码是从控制台运行(使用控制台主机),请使用[Console]::Error.WriteLine(),无条件地写入外部世界的 stderr(标准错误流):

[Console]::Error.WriteLine("An error occurred ... Have you tried rebooting?")
Run Code Online (Sandbox Code Playgroud)

注意:

  • 这不适用于非控制台主机,例如PowerShell ISE.

  • [Console]::Error.WriteLine()控制台[1]中的输出不会以红色打印.


可悲的是,没有这两个作品从单一解决方案的PowerShell(跨主机)外面:

  • [Console]::Error.WriteLine()在为外部世界正确编写stderr时,无法 PowerShell中捕获或抑制其输出,并且只能与PowerShell 控制台主机一起使用.

  • 同样,$host.ui.WriteErrorLine()即使适用于所有主机,它也是一种在PowerShell流系统之外工作的UI方法,因此在PowerShell中也无法捕获或抑制其输出.
    更重要的是,它不会写入外部世界的stderr(它的行为就像Write-Error在这方面,见下文).

  • PowerShell 内部,只Write-Error写入PowerShell的错误流,因此可以捕获/抑制其输出.
    然而,不幸的是,Write-Error(除了吵闹)并没有写入外部世界的标准错误,除非,奇怪的是,标准错误明确地重定向 -看到这个答案的详细信息我的.


[1]彼得(OP本人)为此提供了一个解决方法:

[Console]::ForegroundColor = 'red'
[Console]::Error.WriteLine("An error occurred ... Have you tried rebooting?")
[Console]::ResetColor()
Run Code Online (Sandbox Code Playgroud)

suneg的有用答案为它提供了一个函数包装器.

幸运的是,PowerShell在检测到输出被重定向(到文件)时会自动省略颜色代码.

  • 很好的答案。在不添加新答案的情况下,我想推荐另一种方法,而不是使用 `[Console]::Error.WriteLine`。除了它在 ISE 中不起作用之外,它不会添加到 $Error 变量中。如果我曾经使用过 Write-Error,那是因为我想稍后使用 $Error 变量处理错误,然后我会完全隐藏输出:`Write-Error "hmm" -ErrorAction SilentlyContinue`,并且还可以选择显示此时错误文本为红色,我将使用 `Write-Host "hmm" -ForegroundColor Red`,但要注意,Write-Host 文本不会通过管道传输,也无法重定向到文件 (3认同)

sun*_*neg 9

基于上一个答案中想法,您可以使用自定义函数临时覆盖内置的Write-Error cmdlet.

# Override the built-in cmdlet with a custom version
function Write-Error($message) {
    [Console]::ForegroundColor = 'red'
    [Console]::Error.WriteLine($message)
    [Console]::ResetColor()
}

# Pretty-print "Something is wrong" on stderr (in red).
Write-Error "Something is wrong"

# Setting things back to normal 
Remove-Item function:Write-Error

# Print the standard bloated Powershell errors
Write-Error "Back to normal errors"
Run Code Online (Sandbox Code Playgroud)

有了这个,你就会利用Powershell函数优先于cmdlet这一事实.

https://technet.microsoft.com/en-us/library/hh848304.aspx

这是我能够提出的最优雅的方法,既可以显示漂亮而简洁的错误消息,也可以让TeamCity轻松检测到问题.