代码之家  ›  专栏  ›  技术社区  ›  mark

无论脚本是在“常规”PowerShell控制台中运行还是在PowerShell ISE中运行,如何以相同的方式处理错误?

  •  0
  • mark  · 技术社区  · 6 年前

    我有一个简单的脚本:

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

    (文件datasvc.sln存在)

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

    ISE:

    enter image description here

    常规:

    enter image description here

    我该怎么写才能在这两种情况下打印“失败”?

    编辑1

    必须在关闭Windows 10开发人员模式的情况下以常规帐户(不提升)的身份运行它。如果您不知道什么是Windows10开发人员模式,那么您就可以了(对于这个问题)。

    1 回复  |  直到 6 年前
        1
  •  1
  •   mklement0    6 年前

    不幸的是,不同的主人对待 标准错误 输出来自 外部程序 不同的是。

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

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

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

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

    然而,我不会依赖它,因为这个bug可能——而且希望——会得到修复。

    后退一步:正如注释中的链接所暗示的,外部程序是否失败应该只从其 退出代码 ,而不是来自stderr输出的存在,因为许多程序使用stderr输出来报告信息 除错误外 (如诊断信息或警告)。

    因此, if ($LASTEXITCODE -ne 0) 应单独使用以确定故障。


    如果,出于某种原因,你 需要根据stderr输出的存在来推断故障-例如,因为某些程序在退出代码中没有正确反映故障-您可以尝试以下方法,该方法现在以及在修复上述错误之后都可以工作:

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

    这依赖于将错误流合并到成功流中,然后根据其类型检测stderr源行。

    请注意,在PowerShell内部,您可以在 变量 带公共参数 -ErrorVariable / -ev ,调用时没有类似的机制 外部的 但是,在 this GitHub issue .