내 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: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']
내가 믿기 때문에 잡히지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
my Execution Mode
가로 설정되어 있다는 점도 중요 합니다 Execute .ps1 script with "-File" argument
.
로 변경하려고 시도했지만 테스트를 통과해도 Put script into PowerShell stdin with "-Command -" arguments
종료 코드로 실패했습니다 1
. 나는 그것을 실행하는 것이 -File
올바른 방법 이라고 확신합니다 .
에있는 스크립트를 열고 C:\BuildAgent\work\e903de7564e599c8\build.ps1
CMD에서 수동으로 실행하면 동일한 작업을 수행합니다. 즉, 실패한 테스트가 실패하고 %errorlevel%
여전히 0
.
그러나 PowerShell에서 실행하고을 호출 $LASTEXITCODE
하면 매번 올바른 코드가 반환됩니다.
이것은 PowerShell의 알려진 문제입니다. 로 스크립트를 실행하면 -file
안될 때 종료 코드 0 이 반환됩니다.
(업데이트 : 아래 링크는 더 이상 작동하지 않습니다. PowerShell 에서이 문제를 찾거나보고하십시오 . Hot (1454 개 아이디어) – Windows Server )
사용 -command
이 작동하지 않았기 때문에 스크립트 상단에 트랩을 추가해 볼 수 있습니다.
trap
{
write-output $_
##teamcity[buildStatus status='FAILURE' ]
exit 1
}
위의 결과는 예외가 발생할 때 적절한 종료 코드가됩니다.
를 실행하는 동안이 정확한 문제가 발생 -file
했지만 어떤 이유로 Kevin이 제공 한 트랩 구문 또는 '종료'구문이 내 시나리오에서 작동하지 않았습니다.
이유는 잘 모르겠지만 다른 사람이 같은 문제에 부딪 힐 경우를 대비하여 아래 구문을 사용했으며 저에게 효과적이었습니다.
try{
#DO SOMETHING HERE
}
catch
{
Write-Error $_
##teamcity[buildStatus status='FAILURE']
[System.Environment]::Exit(1)
}
이것이 (아마도) 이전 질문에 대한 내 자체 답변의 복제 로 닫힐 때까지 여기에 가장 깨끗한 해결책을 요약하겠습니다.
다른 답변의 대부분은
stderr
PowerShell 비트에서 무언가를 방출하는 것과 관련이 있습니다 . 이는 Format stderr output as 옵션을 통해 TeamCity에서 직접 수행 할 수 있습니다 ( 기본값 인 Warning 대신 오류로 설정 ).However, critically, it's also necessary to switch on the "Fail build if: ... An error message is logged by (sic) build runner" under "Failure Conditions" (if any of the other answers work for you, you'll likely have this switched on already but IME it's very easy to forget!)
None of these options worked for me in my PowerShell script for whatever reason. I spent hours on it.
For me the best option was to put a layer between TeamCity and PowerShell. So I simply wrote a C# console application which calls the PowerShell script.
The way I do it is, in TeamCity we call a script named: RemoteFile.ps1
With script arguments: %system.RemoteServerFQDN% %system.RemoteUser% %system.RemoteUserPassword% %system.RemoteScriptName% %system.RemotePropertiesFile% %system.BuildVersion% %system.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
Which exists on the remote server in the specified location.
Then that file calls this: powershellwrapper.exe also in the specified location (my script has four parameters to pass to the PowerShell script)
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 test@test.com if error occurs.");
}
}
}
}
And that calls my script with four parameters. The script being the first parameter, plus three arguments. So essentially what is going on here is that I'm executing the PowershellWrapper.exe instead of the PowerShell script itself to capture the erroneous exit code 0's, and it still reports the full script running back to the TeamCity log.
I hope that makes sense. It works like a charm for us.
Using -ErrorAction stop
on a command returns an Exit code 1 by default and is showing it also in TeamCity without adding a Failure Condition. We will now implement this behaviour by default for every PowerShell command using $ErrorActionPreference = "Stop";
.
참고URL : https://stackoverflow.com/questions/15777492/why-are-my-powershell-exit-codes-always-0
'Nice programing' 카테고리의 다른 글
C ++에서 인터페이스를 구현하는 방법? (0) | 2020.11.04 |
---|---|
중첩 된 객체를 사용할 때 AngularJS에서 재귀 템플릿을 어떻게 만들 수 있습니까? (0) | 2020.11.04 |
파이썬으로 새 텍스트 파일을 만들 때 오류가 발생합니까? (0) | 2020.11.04 |
Mixins는 무엇입니까 (개념으로) (0) | 2020.11.04 |
Pandas에서 시계열도에 수직선을 어떻게 그리나요? (0) | 2020.11.04 |