How to get status of “Invoke-Expression”, successful or failed?

前端 未结 5 1200
故里飘歌
故里飘歌 2021-01-01 17:19

Invoke-Expression will return all the text of the command being invoked.

But how can I get the system return value of whether this command has been exec

相关标签:
5条回答
  • 2021-01-01 17:48

    $LASTEXITCODE cannot be used with Invoke-Expression, as it will be zero regardless of whether the expression invoked succeeds or fails:

    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
    
    0 讨论(0)
  • 2021-01-01 17:49

    I found a simple way to do it, which keeps STDOUT in tact.

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

    Success is now True or False, and all IO remains intact.

    0 讨论(0)
  • 2021-01-01 18:04

    In PowerShell you can evaluate execution status by inspecting the automatic variables

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

    and/or

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

    The former is for PowerShell cmdlets, the latter for external commands (like %errorlevel% in batch scripts).

    Does this help you?

    0 讨论(0)
  • 2021-01-01 18:05

    If the executable called by Invoke-Expression supports it, you can use $LASTEXITCODE. You have to be careful about variable scoping, though.

    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
    

    If you run it, the output will be:

    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
    

    Observe the 1 at the end denoting nonzero exit code.

    If you would forget the global: prefix, instead the output would have 0. I believe this is because your function-scoped definition of LASTEXITCODE would hide the globally-set one.

    0 讨论(0)
  • 2021-01-01 18:10

    Normally you would use $? to inspect the status of the last statement executed:

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

    However, this won't work with Invoke-Expression, because even though a statement inside the expression passed to Invoke-Expression may fail, the Invoke-Expression call it self will have succeeded (ie. the expression, although invalid/non-functional was invoked none the less)


    With Invoke-Expression you'll have to use try:

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

    or a trap:

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

    The alternative is the append ";$?" to the expression you want to invoke:

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

    but relies on there not being any pipeline output

    0 讨论(0)
提交回复
热议问题