为什么我的PowerShell退出代码始终为"0"?

Cha*_*ell 71 powershell teamcity exit-code

我有一个PowerShell脚本如下

##teamcity[progressMessage 'Beginning build']
# If the build computer is not running the appropriate version of .NET, then the build will not run. Throw an error immediately.
if( (ls "$env:windir\Microsoft.NET\Framework\v4.0*") -eq $null ) {
    throw "This project requires .NET 4.0 to compile. Unfortunately .NET 4.0 doesn't appear to be installed on this machine."
    ##teamcity[buildStatus status='FAILURE' ]
}

##teamcity[progressMessage 'Setting up variables']
# Set up variables for the build script
$invocation = (Get-Variable MyInvocation).Value
$directorypath = Split-Path $invocation.MyCommand.Path
$v4_net_version = (ls "$env:windir\Microsoft.NET\Framework\v4.0*").Name
$nl = [Environment]::NewLine

Copy-Item -LiteralPath "$directorypath\packages\NUnit.2.6.2\lib\nunit.framework.dll" "$directorypath\Pandell.Tests\bin\debug" -Force

##teamcity[progressMessage 'Using msbuild.exe to build the project']
# Build the project using msbuild.exe.
# Note we've already determined that .NET is already installed on this computer.
cmd /c C:\Windows\Microsoft.NET\Framework\$v4_net_version\msbuild.exe "$directorypath\Pandell.sln" /p:Configuration=Release
cmd /c C:\Windows\Microsoft.NET\Framework\$v4_net_version\msbuild.exe "$directorypath\Pandell.sln" /p:Configuration=Debug

# Break if the build throws an error.
if(! $?) {
    throw "Fatal error, project build failed"
    ##teamcity[buildStatus status='FAILURE' ]
}

##teamcity[progressMessage 'Build Passed']
# Good, the build passed
Write-Host "$nl project build passed."  -ForegroundColor Green


##teamcity[progressMessage 'running tests']
# Run the tests.
cmd /c $directorypath\build_tools\nunit\nunit-console.exe $directorypath\Pandell.Tests\bin\debug\Pandell.Tests.dll

# Break if the tests throw an error.
if(! $?) {
    throw "Test run failed."
    ##teamcity[buildStatus status='FAILURE' ]
}

##teamcity[progressMessage 'Tests passed']
Run Code Online (Sandbox Code Playgroud)

从我所能Throw相信的,未被捕获将导致退出代码1,但不幸的是TeamCity说不然.

[19:32:20]Test run failed.
[19:32:20]At C:\BuildAgent\work\e903de7564e599c8\build.ps1:44 char:2
[19:32:20]+     throw "Test run failed."
[19:32:20]+     ~~~~~~~~~~~~~~~~~~~~~~~~
[19:32:20]    + CategoryInfo          : OperationStopped: (Test run failed.:String) [],
[19:32:20]   RuntimeException
[19:32:20]    + FullyQualifiedErrorId : Test run failed.
[19:32:20]
[19:32:20]Process exited with code 0
[19:32:20]Publishing internal artifacts
[19:32:20][Publishing internal artifacts] Sending build.finish.properties.gz file
[19:32:20]Build finished
Run Code Online (Sandbox Code Playgroud)

值得注意的是,我Execution Mode的设置也是如此Execute .ps1 script with "-File" argument.

我尝试将其更改为Put script into PowerShell stdin with "-Command -" arguments,但随后1通过测试退出代码失败.我确信-File以正确的方式运行它.

如果我打开位于C:\BuildAgent\work\e903de7564e599c8\build.ps1CMD 的脚本并在CMD中手动运行它,它会做同样的事情......也就是说,失败的测试失败了,而且%errorlevel%仍然是0.

但是,如果我在PowerShell中运行并调用$LASTEXITCODE它,它每次都会返回正确的代码.

Kev*_*son 93

这是PowerShell的一个已知问题.执行脚本-file时,如果不应该返回退出代码为0 的脚本.

(更新:以下链接不再有效.请在PowerShell上查找或报告此问题:Hot(1454个想法) - Windows Server)

由于使用-command不适合您,您可以尝试在脚本顶部添加陷阱:

trap
{
    write-output $_
    ##teamcity[buildStatus status='FAILURE' ]
    exit 1
}
Run Code Online (Sandbox Code Playgroud)

抛出异常时,上面应该会产生正确的退出代码.

  • 虽然建议`write-output $ _`正在工作`Write-Error -ErrorRecord $ _`产生奇特的错误输出,就像PowerShell本身一样 (5认同)
  • 你能解释“为什么”这个陷阱会起作用吗?明天我回到项目时会测试它。 (2认同)
  • 如果使用@Mike建议的`Write-Error`确保你的`$ ErrorActionPreference`没有设置为"Stop",否则会导致脚本以代码0退出并且永远不会到达`exit 1`. (2认同)

Jay*_*y S 24

我在运行时遇到了这个问题-file,但由于某些原因,凯文提供的陷阱语法或"退出"语法在我的场景中无效.

我不知道为什么,但是为了防止其他人遇到同样的问题,我使用了下面的语法,它对我有用:

try{
    #DO SOMETHING HERE
}
catch
{
    Write-Error $_
    ##teamcity[buildStatus status='FAILURE']
    [System.Environment]::Exit(1)
}
Run Code Online (Sandbox Code Playgroud)


Rub*_*ink 15

直到这个(大概)被关闭作为我对旧问题的自我回答的重复,我将总结这里最干净的解决方案:

  • 大多数其他答案涉及stderr从PowerShell位发出一些东西.这可以通过Format stderr输出作为选项直接使用TeamCity完成(将其设置为Error而不是默认值,即Warning)

  • 但是,关键的是,还必须在" 失败条件 " 下打开"失败构建如果:...... (sic)构建运行程序记录错误消息 "(如果其他任何答案对您有用,您将会可能已经打开了,但IME 容易忘记!)

  • 这是迄今为止这个页面上最干净的解决方案 (2认同)