locked
How to get exit code from MSBuild when using Powershell and variables RRS feed

  • Question

  • Hi, I'm new with PowerShell. I'm trying to write a script related to MSBuild15.exe.

    I'm running PowerShell on a 64-bit Windows 10 machine that has VS17 installed.

    When using "x64 Native Tools command prompt for VS 2017" I could have just type msbuild to run MSBuild15.

    However, when working with PowerShell, I have to type the full path.

    $msbuild15EXE = 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe' & $msbuild15EXE MySolution.sln /m /t:rebuild ... Build succeeded. 0 Warning(s) 0 Error(s)

    ... or

    Build FAILED.

           "PROJECT_DIR\MySolution.sln" (rebuild target) (1) ->
           "PROJECT_DIR\MySolution\MySolution.vcxproj" (Rebuild target) (3) ->
           (Link target) -> ...

    main.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: ...

    1 Warning(s)
    2 Error(s)

    These are my questions.

    0) I'm not sure what error code is returned from MSBuild15 when an LNK2019 error is created.

    If the build is successful, the MSBuild returns 0, doesn't it?

    Anyways, after the MSBuild returns something, I want to store it in a variable to run a conditional script.

    For instance,

    $errCode = RETURN_VALUE_FROM_MSBUILD15
    # If the return code is 0, run VSTest.console.exe
    If ($FileExists -eq 0){
    # ...
    }
    Else{
    # exit PowerShell with the error code
    # for example, if the error code is 1
    # run "exit 1"
    }

    Is this possible? If so, how should I configure the script to get the exit code of MSBuild15?

    1) The variables are quite confusing to configure.

    $msbuild15EXE = 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe'
    $sol = 'C:\Users\USER0\Desktop\VCProj\MySolution.sln'
    $opt = '/m /t:rebuild'
    
    & $msbuild15EXE $sol $opt
    MSBUILD : error MSB1001: Unknown switch.
    Switch: /m /t:rebuild
    
    # Or
    $myCMD = "& $msbuild15EXE $sol $opt"
    Invoke-Expression $myCMD
    x86 : The term 'x86' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path
    was included, verify that the path is correct and try again.
    At line:1 char:21
    + & C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBui ...
    +                     ~~~
        + CategoryInfo          : ObjectNotFound: (x86:String) [], CommandNotFoundException
        + FullyQualifiedErrorId : CommandNotFoundException

    I wanted to create variables that store the solution name and options for building them.

    My methods returned errors.

    How can I configure options and solution names as variables to build them?


    -Best Regards


    Monday, July 24, 2017 5:29 AM

Answers

  • I usually end my scripts with something like:

    if (-not $?) { exit 1 }

    Then if I run it with 

    powershell -file ./scriptname.ps1

    Powershell will return a errorlevel of 1 to whatever executed it (if the last command had the error).


    • Edited by JS2010 Monday, July 24, 2017 5:41 PM
    • Marked as answer by DeveloperCCC Tuesday, July 25, 2017 8:04 AM
    Monday, July 24, 2017 5:41 PM
  • $? does not catch error for system utility programs.

    Just exit after the build with: "exit $LASTEXITTCODE"

    Add this line after the build:

    Write-Host "EXIT CODE = $LASTTEXITCODE"


    \_(ツ)_/

    • Marked as answer by DeveloperCCC Tuesday, July 25, 2017 8:04 AM
    Monday, July 24, 2017 5:44 PM

All replies

  • One way to control the execution of an external command or executable is to use the cmdlet Start-Process. Maybe like this:

    $Result = (Start-Process -FilePath 'Executable' -ArgumentList 'Options for the executable' -Wait -NoNewWindow -PassThru).ExitCode
    Now you have the exitcode in the variable $Result.


    Grüße - Best regards

    PS:> (79,108,97,102|%{[char]$_})-join''

    Monday, July 24, 2017 9:13 AM
  • The return code is in $LASTEXITCODE.  It is not returned from the execution.  The execution returns text messages output from the build and most are returned on the error channel and not directly to the console channel.  To get the results review the build log.

    How to use build in a script or in a batch is an issue you should post in the VS forum.  It is not a scripting issue.


    \_(ツ)_/

    Monday, July 24, 2017 9:20 AM
  • I usually end my scripts with something like:

    if (-not $?) { exit 1 }

    Then if I run it with 

    powershell -file ./scriptname.ps1

    Powershell will return a errorlevel of 1 to whatever executed it (if the last command had the error).


    • Edited by JS2010 Monday, July 24, 2017 5:41 PM
    • Marked as answer by DeveloperCCC Tuesday, July 25, 2017 8:04 AM
    Monday, July 24, 2017 5:41 PM
  • $? does not catch error for system utility programs.

    Just exit after the build with: "exit $LASTEXITTCODE"

    Add this line after the build:

    Write-Host "EXIT CODE = $LASTTEXITCODE"


    \_(ツ)_/

    • Marked as answer by DeveloperCCC Tuesday, July 25, 2017 8:04 AM
    Monday, July 24, 2017 5:44 PM
  • Hmm.  I have this simple C# program:

    using System;
    class Program {
      static void Main() { 
        Environment.ExitCode = 1;
      }
    }



    I compile it as a windows exe with (in cmd.exe)(/t:exe would make it command line):

    set PATH=%PATH%;C:\Windows\Microsoft.NET\Framework\v4.0.30319
    csc /t:winexe file.cs


    In cmd.exe, I can run it with

    start /wait file.exe


    and it will set the %errorlevel% to 1.  But it doesn't seem to change $? or $LASTEXITCODE in powershell:

    start -wait .\file.exe

    EDIT:

    Oh I see, you have to add -passthru, then $LASTEXITCODE gets set to 1:

    start -wait .\file.exe -passthru
    A "command line" exe would set both $? and $LASTEXITCODE.


    • Edited by JS2010 Monday, July 24, 2017 7:58 PM
    Monday, July 24, 2017 7:38 PM
  • $? is NOT set by external programs.  $LASTEXITCODE is the variable the returns the exitcode of the last utility to run.  It is the equivalent of   %errorlevel%.

    PS D:\scripts> cmd /c exit
    PS D:\scripts> $lastexitcode
    0
    PS D:\scripts>
    PS D:\scripts> cmd /c "dir x: && exit"
    The system cannot find the path specified.
    PS D:\scripts> $lastexitcode
    1



    \_(ツ)_/



    • Edited by jrv Monday, July 24, 2017 7:45 PM
    Monday, July 24, 2017 7:43 PM
  • In your own example, $? gets set to $false.

    Monday, July 24, 2017 8:01 PM
  • In your own example, $? gets set to $false.

    $? gets set to false if the exit code is not zero but it does not tell you what the exit code is.  MSbuild returns ddifferent exit codes for different issues.

    if($lastexitcode){
         Write-Host "EXITTCODE = $lastexitcode"
    }else{
        Write-Host 'No Error reported'
    }
    $? is the old P{S 1.0 method of testing for errors and it is not generally used anymore.  $LASTEXITCODE and Try/Catch have superseded it.


    \_(ツ)_/




    • Edited by jrv Monday, July 24, 2017 8:20 PM
    Monday, July 24, 2017 8:18 PM
  • Thanks, jrv!

    I received 0 after the MSBuild15 build successfully.

    I will use your tip. Thanks!


    -Best Regards

    Tuesday, July 25, 2017 8:03 AM