我试图弄清楚如何确定使用Invoke-Expression的命令是否失败。 即使变量$?,$ LASTEXITCODE或-ErrorVariable也无法帮助我。
例如:
PS C:\> $cmd="cat c:\xxx.txt"
使用Invoke-Expression
调用$ cmd PS C:\> Invoke-Expression $cmd -ErrorVariable err
Get-Content : Cannot find path 'C:\xxx.txt' because it does not exist.
At line:1 char:4
+ cat <<<< c:\xxx.txt
+ CategoryInfo : ObjectNotFound: (C:\xxx.txt:String) [Get-Content], ItemNotFoundExcep
tion
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
$?是真的
PS C:\> $?
True
$ LASTEXITCODE为0
PS C:\> $LASTEXITCODE
0
$ err是空的
PS C:\> $err
PS C:\>
我找到的唯一方法是在文件中重定向STD_ERR并测试此文件是否为空
PS C:\> Invoke-Expression $cmd 2>err.txt
PS C:\> cat err.txt
Get-Content:找不到路径'C:\ xxx.txt',因为它不存在。 在行:1 char:4 + cat&lt;&lt;&lt;&lt; C:\ xxx.txt + CategoryInfo:ObjectNotFound:(C:\ xxx.txt:String)[Get-Content],ItemNotFoundExcep 重刑 + FullyQualifiedErrorId:PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
这是唯一且最好的方法吗?
答案 0 :(得分:3)
我疯狂地尝试将STDERR流捕获到变量工作中。我终于解决了。 invoke-expression命令中存在一个怪癖,它使整个2&amp;&gt; 1重定向失败,但是如果省略1则它会做正确的事。
function runDOScmd($cmd, $cmdargs)
{
# record the current ErrorActionPreference
$ep_restore = $ErrorActionPreference
# set the ErrorActionPreference
$ErrorActionPreference="SilentlyContinue"
# initialize the output vars
$errout = $stdout = ""
# After hours of tweak and run I stumbled on this solution
$null = iex "& $cmd $cmdargs 2>''" -ErrorVariable errout -OutVariable stdout
<# these are two apostrophes after the >
From what I can tell, in order to catch the stderr stream you need to try to redirect it,
the -ErrorVariable param won't get anything unless you do. It seems that powershell
intercepts the redirected stream, but it must be redirected first.
#>
# restore the ErrorActionPreference
$ErrorActionPreference=$ep_restore
# I do this because I am only interested in the message portion
# $errout is actually a full ErrorRecord object
$errrpt = ""
if($errout)
{
$errrpt = $errout[0].Exception
}
# return a 3 member arraylist with the results.
$LASTEXITCODE, $stdout, $errrpt
}
答案 1 :(得分:1)
听起来你在尝试捕获变量中的native的错误输出而不捕获stdout。如果捕获标准输出是可以接受的,则使用2&gt;&amp; 1。
重定向到文件可能是最简单的。使用Invoke-Expression为它的-ErrorVariable参数几乎看起来是个好主意,但是Invoke-Expression有很多问题,我通常不鼓励它。
另一种选择看起来有点麻烦,但它可以作为一种功能考虑在内。该想法是使用2&gt;&amp; 1合并输出流,但是然后基于对象的类型再次拆分它们。它可能看起来像这样:
function Split-Streams
{
param([Parameter(ValueFromPipeline=$true)]$InputObject)
begin
{
$stdOut = @()
$stdErr = @()
}
process
{
if ($InputObject -is [System.Management.Automation.ErrorRecord])
{
# This works well with native commands but maybe not as well
# for other commands that might write non-strings
$stdErr += $InputObject.TargetObject
}
else
{
$stdOut += $InputObject
}
}
end
{
,$stdOut
,$stdErr
}
}
$o, $e = cat.exe c:\xxx.txt 2>&1 | Split-Streams