【问题标题】:How to get status of "Invoke-Expression", successful or failed?如何获得“Invoke-Expression”的状态,成功还是失败?
【发布时间】:2015-09-02 08:58:24
【问题描述】:

Invoke-Expression 将返回正在调用的命令的所有文本。

但是如何获取该命令执行成功还是失败的系统返回值呢?在 CMD 中,我可以使用 %errorlevel% 来获取外部命令执行状态。 PowerShell 呢?

【问题讨论】:

    标签: powershell exit-code


    【解决方案1】:

    通常你会使用$? 来检查最后执行的语句的状态:

    PS C:\> Write-Output 123 | Out-Null; $?
    True
    PS C:\> Non-ExistingCmdlet 123 | Out-Null; $?
    False
    

    但是,这不适用于 Invoke-Expression,因为即使传递给 Invoke-Expression 的表达式中的语句可能会失败,但 Invoke-Expression 调用它自己将成功(即表达式,虽然无效/非功能性的被调用了)


    对于Invoke-Expression,你必须使用try:

    try {
        Invoke-Expression "Do-ErrorProneAction -Parameter $argument"
    } catch {
        # error handling go here, $_ contains the error record
    }
    

    或陷阱:

    trap {
        # error handling goes here, $_ contains the error record
    }
    Invoke-Expression "More-ErrorProneActions"
    

    替代方法是将";$?" 附加到您要调用的表达式:

    $Expr  = "Write-Host $SomeValue"
    $Expr += ';$?'
    
    $Success = Invoke-Expression $Expr
    if(-not $Success){
        # seems to have failed
    }
    

    但依赖于没有任何管道输出

    【讨论】:

    • 最后一个例子的第二行必须是$Expr += ';$?'以避免立即解释$?
    • @letmaik 很好地发现,完全忽略了这一点
    【解决方案2】:

    在 PowerShell 中,您可以通过检查 automatic variables 来评估执行状态

    $?
       Contains True if last operation succeeded and False otherwise.
    

    和/或

    $LASTEXITCODE
       Contains the exit code of the last Win32 executable execution.
    

    前者用于 PowerShell cmdlet,后者用于外部命令(如批处理脚本中的 %errorlevel%)。

    这对你有帮助吗?

    【讨论】:

    • Invoke-Expression 总是将$? 设置为$true 无论如何,所以$? 在这种情况下无济于事。
    • $? 适用于我的调用,例如 &'path/to/exe' -params,它返回 True 用于退出代码 0 和 False 用于任何其他退出代码。
    【解决方案3】:

    如果Invoke-Expression调用的可执行文件支持,可以使用$LASTEXITCODE。不过,您必须小心变量范围。

    function foo 
    {
        $global:LASTEXITCODE = 0 # Note the global prefix.
        Invoke-Expression "dotnet build xyz" # xyz is meaningless, to force nonzero exit code.
        Write-Host $LASTEXITCODE
    }
    
    foo
    

    如果你运行它,输出将是:

    Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Core
    Copyright (C) Microsoft Corporation. All rights reserved.
    
    MSBUILD : error MSB1009: Project file does not exist.
    Switch: xyz
    1
    

    注意末尾的 1 表示非零退出代码。

    如果您忘记了 global: 前缀,则输出将为 0。我相信这是因为您对 LASTEXITCODE 的函数范围定义会隐藏全局设置的定义。

    【讨论】:

      【解决方案4】:

      我找到了一种简单的方法,可以保持 STDOUT 的完整性。

      $Expr="MY EXPRESSION"
      $Expr += '; $Success=$?'
      Invoke-Expression $Expr
      

      Success 现在是 True 或 False,所有 IO 保持不变。

      【讨论】:

      • 天哪,如果我们用 $LastExitCode 而不是 $?似乎工作
      【解决方案5】:

      $LASTEXITCODE 不能与 Invoke-Expression 一起使用,因为无论调用的表达式是成功还是失败,它都会为零:

      PS C:\Users\myUserAccount> touch temp.txt
      PS C:\Users\myUserAccount> Invoke-Expression "Remove-Item .\temp.txt"
      PS C:\Users\myUserAccount> echo $LASTEXITCODE
      0
      
      PS C:\Users\myUserAccount> Invoke-Expression "Remove-Item .\temp.txt"
      Remove-Item : Cannot find path 'C:\Users\myUserAccount\temp.txt' because it does not 
      exist.
      At line:1 char:1
      + Remove-Item .\temp.txt
      + ~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : ObjectNotFound: (C:\Users\myUserAccount\temp.txt:String) [Remove-Item], ItemNotFoundException
         + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
      
      PS C:\Users\myUserAccount> echo $LASTEXITCODE
      0
      

      【讨论】:

      猜你喜欢
      • 2023-01-08
      • 2011-04-23
      • 2012-10-22
      • 1970-01-01
      • 1970-01-01
      • 2012-08-19
      • 2019-02-09
      • 1970-01-01
      • 2021-10-03
      相关资源
      最近更新 更多