我在 ISE 中开发了一个程序,但从命令行运行它时没有得到相同的行为(例如,
> .\script.ps1 -ProjectDirectoryPath .\project
)。也就是说,异常不会重定向到 try/catch 中的错误日志,并且 $Error 为空。
# Loop start time
$starttime = Get-Date
foreach($thing in $things) {
Write-Host "comment about $thing..."
try {
$ErrorActionPreference = "Stop"
#does stuff
} catch {
$_.Exception | Out-File $ProjectDirectoryPath\error.log -Append
}
}
# Print processing statistics and notify user if there were errors
Write-Host "Processed $($things.Count) files in $(((Get-Date) - $starttime).Minutes) minute(s). There were $($Error.Count) error(s). Check error.log in the project directory to view them."
我得到的输出基本上如下,并且没有 error.log 写入项目目录。
E: There was 1 error
Processed 1 files in 0 minute(s). There were 0 error(s). Check error.log in the project directory to view them.
我尝试更改执行策略(RemoteSigned 和 Unrestricted),但这似乎对解决问题没有帮助。我认为问题归结于环境之间的差异。我错过了什么?
首先,让我提供标准建议:
您在 ISE 和常规 PowerShell 控制台之间看到的行为差异是导致 ISE 出现问题的几个差异之一(而 Visual Studio Code 的集成终端却表现出没有此类差异。)
您没有显示
#does stuff
代表什么,但暗示您正在调用一个 外部(本机)程序,它会产生 stderr 输出。
在使用
Windows PowerShell ISE Host
PowerShell 主机的 ISE 中(而在常规控制台窗口/Windows 终端中运行的 PowerShell 使用 ConsoleHost
),stderr 输出通过 PowerShell 的 error 输出流进行路由,这意味着,使用 $ErrorActionPreference = "Stop"
实际上,任何 stderr 输出都会升级为(脚本)终止错误,因此可以使用 try
语句来处理。$LASTEXITCODE
变量中所反映。
相比之下,在常规 PowerShell 控制台/Windows 终端中,默认情况下,stderr 适当地不通过错误流路由,[1],因此永远不会在那里触发
catch
块。
因此,请使用如下内容:
try {
$ErrorActionPreference = "Stop"
# Some external-program call
if ($LASTEXITCODE) { throw "External program 'foo' reported exit code $LASTEXITCODE." }
} catch {
$_.Exception | Out-File $ProjectDirectoryPath\error.log -Append
}
如果您运行的是 PowerShell 7 v7.4+,您也可以将 首选项变量
$PSNativeCommandUseErrorActionPreference
设置为 $true
,在这种情况下,任何报告非零退出代码的外部程序调用都会触发非终止错误表明这一事实,与 $ErrorActionPreference = "Stop"
结合使用 - 然后触发一个(脚本)终止错误,可以通过 try
语句捕获该错误 - 有关详细信息,请参阅 这个答案。
[1] 由于 Windows PowerShell 中的错误,当涉及
2>
重定向 时,仍然会发生此路由。此问题已在 PowerShell 7 中得到修复,但请注意,此路由仍然发生在 remoting 和 jobs 的上下文中 - 尽管不受 $ErrorActionPreference = "Stop"
的影响 - 有关详细信息,请参阅 this answer。