Почему мои коды выхода powershell всегда "0"?
у меня есть сценарий 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:windirMicrosoft.NETFrameworkv4.0*") -eq $null ) {
throw "This project requires .NET 4.0 to compile. Unfortunatly .NET 4.0 doesn't appear to be installed on this machine."
##teamcity[buildStatus status='FAILURE' ]
}
##teamcity[progressMessage 'Setting up variables']
# Set up varriables for build script
$invocation = (Get-Variable MyInvocation).Value
$directorypath = Split-Path $invocation.MyCommand.Path
$v4_net_version = (ls "$env:windirMicrosoft.NETFrameworkv4.0*").Name
$nl = [Environment]::NewLine
Copy-Item -LiteralPath "$directorypathpackagesNUnit.2.6.2libnunit.framework.dll" "$directorypathPandell.Testsbindebug" -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:WindowsMicrosoft.NETFramework$v4_net_versionmsbuild.exe "$directorypathPandell.sln" /p:Configuration=Release
cmd /c C:WindowsMicrosoft.NETFramework$v4_net_versionmsbuild.exe "$directorypathPandell.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 $directorypathbuild_toolsnunitnunit-console.exe $directorypathPandell.TestsbindebugPandell.Tests.dll
# Break if the tests throw an error.
if(! $?) {
throw "Test run failed."
##teamcity[buildStatus status='FAILURE' ]
}
##teamcity[progressMessage 'Tests passed']
из того, во что я верю,непойманного Throw приведет к коду выхода 1, но, к сожалению, TeamCity говорит иначе.
[19:32:20]Test run failed.
[19:32:20]At C:BuildAgentworke903de7564e599c8build.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
возможно, также важно отметить, что мой Execution Mode установлено значение Execute .ps1 script with "-File" arguement.
Я попытался изменить его на Put script into PowerShell stdin with "-Command -" arguements но тогда это не удалось с кодом выхода 1 даже при прохождении тестов. Я уверен, что запуск его как -File будет правильный путь.
если я открою скрипт, расположенный по адресу C:BuildAgentworke903de7564e599c8build.ps1 и запустите его вручную в CMD, он делает то же самое... IE: неудачные тесты терпят неудачу, и %errorlevel% по-прежнему 0.
тем не менее, если я запускаю его в powershell и вызываю $LASTEXITCODE он возвращает правильный код каждый раз.
5 ответов:
Это известная проблема с PowerShell. Выполнение скрипта с помощью
-fileвозвращает код выхода 0, когда он не должен.(обновление: ссылки ниже больше не работают. Пожалуйста, найдите или сообщите об этой проблеме https://windowsserver.uservoice.com/forums/301869-powershell)
С помощью
-commandне работает для вас, вы можете попробовать добавить в ловушку в верхней части скрипта:trap { write-output $_ ##teamcity[buildStatus status='FAILURE' ] exit 1 }вышеизложенное должно привести к правильному коду выхода при возникновении исключения.
У меня была эта точная проблема во время работы с-файлом, но по какой-то причине синтаксис ловушки или синтаксис "выхода", предоставленный Кевином, не работал в моем сценарии. Не знаю почему, но на всякий случай кто-то другой попадает в ту же проблему, я использовал синтаксис ниже, и это сработало для меня:
try{ #DO SOMETHING HERE } catch { Write-Error $_ ##teamcity[buildStatus status='FAILURE'] [System.Environment]::Exit(1) }
пока это (предположительно) не будет закрыто как dup моего собственного ответа на старый вопрос, я подытожу самое чистое решение здесь:
большинство других ответов включают в себя излучение чего-то в
stderrиз бита PowerShell. Это может быть достигнуто непосредственно с TeamCity через формат вывода stderr как опция (установите его в вместо по умолчанию предупреждение)однако, критически, также необходимо включить " Fail build if: ... сообщение об ошибке регистрируется (sic) build runner" под "Неисправность" (если какой-либо из других ответов работает для вас, вы, вероятно, уже включили это, но IME это очень легко забыть!)
ни один из этих вариантов не работал для меня в моем сценарии powershell по какой-либо причине. Я потратил на это несколько часов.
для меня лучшим вариантом было поместить слой между TeamCity и Powershell. Поэтому я просто написал консольное приложение c#, которое вызывает скрипт powershell.
Как я это делаю, в teamcity мы называем скрипт с именем: RemoteFile. ps1
с аргументами скрипта: %system.RemoteServerFQDN% %система.RemoteUser% % system.RemoteUserPassword% %система.RemoteScriptName% % system.RemotePropertiesFile% % system.BuildVersion% %системы.RunList%
param ( [Parameter(Mandatory=$true)] $Computername, [Parameter(Mandatory=$true)] $Username, [Parameter(Mandatory=$true)] $Password, [Parameter(Mandatory=$true)] $ScriptName, [Parameter(Mandatory=$true)] $Propfile, [Parameter(Mandatory=$true)] $Version, [Parameter(Mandatory=$true)] [string[]]$DeploymentTypes ) $securePassword = ConvertTo-SecureString -AsPlainText -Force $Password $cred = New-Object System.Management.Automation.PSCredential $Username, $securePassword write-host "Readying to execute invoke-command..." Invoke-Command -ComputerName $Computername -Credential $cred -ScriptBlock { D:\Deployment\PowershellWrapper.exe $using:ScriptName $using:Propfile $using:Version $using:DeploymentTypes } -ArgumentList $ScriptName,$Propfile,$Version,$DeploymentTypesкоторая существует на удаленном сервере в указанном месте.
тогда этот файл вызывает это: powershellwrapper.exe также в указанном месте (мой скрипт имеет 4 параметра для передачи в powershell)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Diagnostics; namespace PowershellWrapper { class Program { static void Main(string[] args) { try { string argFull = @"""{0} {1} {2} {3}"""; string arg0 = args[0]; string arg1 = args[1]; string arg2 = args[2]; string arg3 = args[3]; string argFinal = string.Format(argFull, arg0, arg1, arg2, arg3); ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = @"powershell.exe"; startInfo.Arguments = argFinal; startInfo.RedirectStandardOutput = false; startInfo.RedirectStandardError = false; startInfo.UseShellExecute = false; startInfo.RedirectStandardInput = true; startInfo.CreateNoWindow = false; Process process = new Process(); process.StartInfo = startInfo; process.Start(); } catch (Exception e) { Console.WriteLine("{0} Exception caught.", e); Console.WriteLine("An error occurred in the deployment.", e); Console.WriteLine("Please contact [email protected] if error occurs."); } } }}
и это вызывает мой скрипт с 4 параметрами, скрипт является первым параметром, плюс 3 аргумента. Так что по существу что здесь происходит, так это то, что я выполняю PowershellWrapper.exe вместо самого сценария powershell, чтобы захватить ошибочный код выхода 0, и он по-прежнему сообщает о полном сценарии, запущенном обратно в журнал TeamCity.
надеюсь, что имеет смысл, это работает как шарм для нас.
используя
-ErrorAction stopпо команде возвращает код выхода 1 по умолчанию и показывает его также в TeamCity без добавления условия сбоя. Теперь мы будем реализовывать это поведение по умолчанию для каждой команды PowerShell с помощью$ErrorActionPreference = "Stop";.
Comments