Reputation: 67
I have a simple PS script:
[CmdletBinding()]
param(
[Parameter()]
[String] $CodeCoverageXmlReportPath,
[Parameter()]
[Int32] $MinimumLineCoverage = 100
)
Write-Host $"MinimumLineCoverage = $MinimumLineCoverage"
Write-Host $"Reading CodeCoverage XML report: {$CodeCoverageXmlReportPath}"
### logic to calculate code coverage from report ###
if ($lineCoverageNum -lt $MinimumLineCoverage)
{
Write-Host $"Code coverage of this build ($lineCoverageNum) is below the expected value ($MinimumLineCoverage). Please add tests to validate new code."
exit 1
}
else
{
Write-Host $"Code coverage check (($lineCoverageNum)) for this build is at par with the ($MinimumLineCoverage). Great job!."
exit 0
}
These are the two ways I have tried to execute it from a .cmd file:
%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -NonInteractive -ExecutionPolicy Unrestricted -File ValidateCodeCoverage.ps1 -CodeCoverageXmlReportPath "%TestResultsDir%\Cobertura.xml" -MinimumLineCoverage 57
ECHO ErrorLevel=%errorlevel%
and
%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -NonInteractive -
ExecutionPolicy Unrestricted -Command "& {.\ValidateCodeCoverage.ps1 -CodeCoverageXmlReportPath "%TestResultsDir%\Cobertura.xml" -MinimumLineCoverage 57; exit $LASTEXITCODE}"
ECHO ErrorLevel=%errorlevel%
In both these cases, checking the value of %errorlevel%
right after the .ps1 execution remains 0 no matter what. I tried tested it with always exiting with return code 1, using trap, throwing an exception, etc. The %errorlevel% in cmd file is always set to 0.
What could I be missing? :(
Upvotes: 1
Views: 2082
Reputation: 437052
Your PowerShell commands correctly set the exit code, so the problem must be in the way your batch file checks it.
The only scenario in which your code doesn't work is if it is inside a (...)
block, where variable references such as %errorlevel%
are expanded before the commands in the block execute; e.g.:
@echo off
REM # Does NOT work as expected, because %ErrorLevel% is expanded
REM # BEFORE the powershell command excutes.
for /l %%i in (1,1,1) do (
powershell.exe -ExecutionPolicy Bypass -Command "exit 5"
echo ErrorLevel=%ErrorLevel%
)
Output is ErrorLevel=0
, namely the value of %errorlevel%
before the PowerShell command, which sets the exit code (error level) to 5
, is executed.
To solve this problem:
You must use setlocal enableDelayedExpansion
at the start of your batch file...
setlocal
part implies that whatever custom variables you set in your batch file will be local to your batch file, which is generally preferable anyway; see setlocal /?
... and then use !ErrorLevel!
rather than %ErrorLevel%
, because only the former guarantees dynamic expansion of the error level (exit code):
@echo off
setlocal enableDelayedExpansion
REM # OK - thanks to enableDelayedExpansion and !...!,
REM # powershell.exe's exit code is dynamically evaluated.
for /l %%i in (1,1,1) do (
powershell.exe -ExecutionPolicy Bypass -Command "exit 5"
echo ErrorLevel=!ErrorLevel!
)
Output is ErrorLevel=5
, which now correctly reflects the PowerShell command's exit code.
Upvotes: 2