PowerShell exit code - Calling from MSBuild
This question is the top answer on a major search engine. The best answer is this from James Kovacs (of psake fame - i.e., he's kinda FizzBinned on PowerShell and MSBuild integration).
In summary, in a ps1 file:
- stick a
$ErrorActionPreference='Stop'
at the top of your script so it's not the default, which isSilentlyContinue
(thetrap
bit in the accepted answer has the same effect but is far more indirect and confusing) - stick in his
function exec {...
(or use psake itself) - wrap invocations of external EXEs in an
exec { x.exe }
- don't need to do any explicit
exit ...
stuff
The default error handling propagates an exception up as an ERRORLEVEL
of 1 from the powershell.exe myscript.ps1
, i.e. in an MSBuild <Exec
you don't need to do any trickery re telling it to ignore exit codes etc. (unless you want to do something conditional on the specific exit code, in which you want to do IgnoreExitCode="true"
and capture it with an <Output
element)
A final important thing to understand is that within PowerShell, there's a $?
which is the outcome of the last expression (which is not relevant if you're in ErrorAction='Stop'
mode) which changes with every thing you do, whereas $LastExitCode is the 'DOS' exit code of the last .exe triggered in the system. Details here - be sure to read the comments
Add exit $lastexitcode
to test.ps1
After comment:
Try this in test.ps1:
trap {Write-Host -foreground red $_.Exception.Message; exit 1; continue} Invoke-command {Powershell.exe C:\a.ps1} -computername $computers
Basically, I don't think MSBuild is at fault here.
I tried your wrong Invoke-Command
and the $lastexitcode
was set to 0 even though the Invoke-Command had failed! You can test whether this works or not from cmd itself by doing echo %errorlevel%
and see you get 1.
I tried several options but none works for me.
To capture the powershell error on msbuild target, best way is to return the error code from powershell script like $host.SetShouldExit($remotelastexitcode).
e.g.test1.ps1
function CallFromMSBuild { Invoke-command {Powershell.exe C:\a.ps1} -computername $computers $host.SetShouldExit(1)} <Target Name="AfterDropBuild" > <Exec Command="powershell.exe -NoProfile -Noninteractive -command "& { $(ScriptLocation)%3Bexit $LASTEXITCODE }" " > <Output TaskParameter="ExitCode" PropertyName="ErrorCode"/> </Exec> </Target>
Worth to have a look at https://snagify.wordpress.com/2008/04/06/teambuild-powershell-and-exit-codes/