我发现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
内部不一致的原因。)
答案 0 :(得分:1)
这是一个范围问题,请参阅about_Scopes。
它正在发生,因为您在调用&
时隐式使用了调用运算符a3.exe
。您可以通过更改代码来明确使用它来证明这一点:
function ProduceError {
[CmdletBinding()]
param()
& a3.exe
}
这将产生相同的行为。正如帮助页面所说:
使用调用运算符(&)运行函数或脚本时,它不会添加到当前作用域。以下示例使用调用运算符:
& c:\scripts.sample.ps1
Sample.ps1脚本创建的任何别名,函数或变量在当前作用域中不可用。
要解决此问题,您可以使用Invoke-Expression
或Start-Process
:
function ProduceError {
[CmdletBinding()]
param()
Invoke-Expression a3.exe
}
或
function ProduceError {
[CmdletBinding()]
param()
Start-Process a3.exe
}
这些应该按您期望的方式工作,因为cmdlet在您的范围内。
使用呼叫运算符不会创建子范围(或子范围),它是一个新会话:
会话,模块和嵌套提示是自包含环境,但它们不是会话中全局范围的子范围。
会话: 会话是运行Windows PowerShell的环境。在远程计算机上创建会话时,Windows PowerShell会建立与远程计算机的持久连接。持久连接允许您将会话用于多个相关命令。
由于会话是包含的环境,因此它具有自己的范围,但会话不是创建该会话的会话的子范围。会话以其自己的全局范围开始。此范围独立于会话的全局范围。您可以在会话中创建子范围。例如,您可以运行脚本在会话中创建子范围。