PowerShell:使用 Invoke-Expression 管理错误

use*_*628 3 powershell

我试图弄清楚如何确定使用 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 <<<< c:\xxx.txt + CategoryInfo : ObjectNotFound: (C:\xxx.txt:String) [Get-Content], ItemNotFoundException +fullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell .Commands.GetContentCommand

这是唯一和最好的方法吗?

小智 6

试图将 STDERR 流捕获为可变的工作,我快疯了。我终于解决了。invoke-expression 命令中有一个怪癖,它会使整个 2&>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
 }
Run Code Online (Sandbox Code Playgroud)