Powershell奇怪的错误处理行为

时间:2014-11-02 19:57:35

标签: powershell error-handling

我发现Powershell错误非常奇怪。请考虑以下脚本:

function ProduceError {
  [CmdletBinding()]
  param()
  #write-error a1
  #throw "a2"
  #a3.exe
}

function TestError {
  ProduceError -ea stop
  ProduceError -ea stop
}

TestError

我使用停止首选项调用ProduceError cmdlet,因此无论是否发生终止或非终止错误,它都应该表现相同,但它不会。

我正在观察Powershell v3(确保a3.exe不存在):

  • 取消注释write-error:它会打印一次a1然后停止。
  • 取消注释throw:它会打印一次a2然后停止。
  • 取消注释a3.exe:它会抱怨两次关于找不到a3.exe。

为什么调用不存在的命令似乎会导致非终止错误,即使我将错误首选项设置为停止? (我知道我可以设置EA停在TestError内,但我想知道ProduceError内部不一致的原因。)

1 个答案:

答案 0 :(得分:1)

这是一个范围问题,请参阅about_Scopes

它正在发生,因为您在调用&时隐式使用了调用运算符a3.exe。您可以通过更改代码来明确使用它来证明这一点:

function ProduceError {
  [CmdletBinding()]
  param()
  & a3.exe
}

这将产生相同的行为。正如帮助页面所说:

  

使用调用运算符(&)运行函数或脚本时,它不会添加到当前作用域。以下示例使用调用运算符:

& c:\scripts.sample.ps1
  

Sample.ps1脚本创建的任何别名,函数或变量在当前作用域中不可用。

要解决此问题,您可以使用Invoke-ExpressionStart-Process

function ProduceError {
  [CmdletBinding()]
  param()
  Invoke-Expression a3.exe
}

function ProduceError {
  [CmdletBinding()]
  param()
  Start-Process a3.exe
}

这些应该按您期望的方式工作,因为cmdlet在您的范围内。

根据您的评论进行编辑:

使用呼叫运算符不会创建子范围(或子范围),它是一个新会话:

  

会话,模块和嵌套提示是自包含环境,但它们不是会话中全局范围的子范围。

     

会话:   会话是运行Windows PowerShell的环境。在远程计算机上创建会话时,Windows PowerShell会建立与远程计算机的持久连接。持久连接允许您将会话用于多个相关命令。

     

由于会话是包含的环境,因此它具有自己的范围,但会话不是创建该会话的会话的子范围。会话以其自己的全局范围开始。此范围独立于会话的全局范围。您可以在会话中创建子范围。例如,您可以运行脚本在会话中创建子范围。