Pourquoi mes PowerShell codes de sortie toujours à “0”?
J'ai un script PowerShell comme suit
##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']
De ce que je suis porté à croire, un uncaught Jet
entraînera un code de sortie de 1
, mais malheureusement, TeamCity est en train de dire le contraire.
[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
Il pourrait également être important de noter que mon Execution Mode
est fixé à Execute .ps1 script with "-File" argument
.
J'ai essayé de la modifier à Put script into PowerShell stdin with "-Command -" arguments
, mais ensuite il a échoué avec le code de sortie 1
même avec le passage des tests. Je suis sûr qu'en l'exécutant en tant -File
va être la bonne façon.
Si j'ouvre le script situé à C:\BuildAgent\work\e903de7564e599c8\build.ps1
et de l'exécuter manuellement dans CMD, il fait la même chose... I. e., l'échec des tests échouent, et la %errorlevel%
est encore 0
.
Encore, si je le lance en PowerShell et appel $LASTEXITCODE
, il renvoie le bon code à chaque fois.
- J'ai même essayé d'ajouter
[Environment]::Exit(1)
juste après chaquethrow
, mais il ne fonctionne toujours pas. - Le code après
throw
n'est pas exécutée. - Si vous modifiez le niveau d'erreur pour l'étape de génération de "avertissement" "erreur", fait-il une différence?
- J'ai rencontré le même problème. Il suffit de remplacer votre lancer avec un simple "exit -1".
- connexes: stackoverflow.com/questions/11647987/...
- Post de Blog qui répond à cette question: chuchuva.com/pavel/2012/05/powershell-exit-codes
- Double Possible de Comment puis-je obtenir erreurs pour se propager dans le TeamCity PowerShell runner
Vous devez vous connecter pour publier un commentaire.
C'est un problème connu avec PowerShell. L'exécution d'un script avec
-file
retourne le code de sortie 0 quand il ne devrait pas.(Mise à jour: Les liens ci-dessous ne fonctionnent plus. Veuillez rechercher ou signaler ce problème sur PowerShell: Chaud (1454 idées) – Windows Server)
https://connect.microsoft.com/PowerShell/feedback/details/777375/powershell-exe-does-not-set-an-exit-code-when-file-is-used
https://connect.microsoft.com/PowerShell/feedback/details/750653/powershell-exe-doesn-t-return-correct-exit-codes-when-using-the-file-option
Depuis l'utilisation de
-command
n'étais pas de travail pour vous, vous pourriez essayer d'ajouter un piège en haut du script:Ci-dessus devrait en résulter un bon code de sortie lorsqu'une exception est levée.
throw
ne permet pas d'obtenir le code de sortie correct, nous avons pour attraper les exceptions et de sortie manuellement.trap
est PowerShell original exception d'un mécanisme de gestion. (try
/catch
est apparu en V2.) Pensez-y comme uncatch
pour toute exception levée dans le même champ d'application pour lequel letrap
est défini. Bonne info surtrap
: huddledmasses.org/trap-exception-in-powershell et blogs.msdn.com/b/powershell/archive/2009/06/17/...write-output $_
travailleWrite-Error -ErrorRecord $_
produit de la fantaisie de la sortie d'erreur comme PowerShell lui-mêmetrap
. Vous pouvez structurer la sortie de la façon dont vous le souhaitez et/ou de faire d'autres choses avant de quitter.Write-Error
comme suggéré par @Mike assurez-vous que votre$ErrorActionPreference
n'est pas réglé sur "Arrêt", sinon que va provoquer le script de sortie avec le code 0 etexit 1
ne sera jamais atteint.J'ai eu ce problème précis lors de l'exécution avec les
-file
, mais pour une raison quelconque, le piège de la syntaxe ou de la "sortie" de la syntaxe fournie par Kevin n'était pas de travail dans mon scénario.Je ne suis pas sûr pourquoi, mais juste au cas où quelqu'un d'autre frappe le même problème, j'ai utilisé la syntaxe suivante et cela a fonctionné pour moi:
Jusqu'à ce que (probablement) se ferme comme dup de mon auto-réponse à une ancienne question, je vais résumer la solution la plus propre ici:
La plupart des autres réponses impliquent émettant quelque chose à la
stderr
de l'PowerShell peu. Cela peut être fait directement avec TeamCity via le Format de sortie stderr comme option (à régler à Erreur au lieu de la valeur par défaut, qui est Avertissement)Cependant, de façon critique, il est également nécessaire d'allumer le "Fail compilation si: ... Un message d'erreur est consigné par (sic) construire coureur" sous "Conditions d'Échec" (si l'une des autres réponses travailler pour vous, vous aurez probablement cette allumé déjà mais IME c'est très facile d'oublier!)
Aucune de ces options n'a fonctionné pour moi dans mon script PowerShell pour quelque raison que ce soit. J'ai passé des heures sur elle.
Pour moi, la meilleure option est de mettre une couche entre TeamCity et PowerShell. Alors j'ai tout simplement écrit une application console C# qui appelle le script PowerShell.
La façon dont je le fais, c'est, dans TeamCity nous appeler un script nommé:
RemoteFile.ps1
Avec les arguments du script: %système.RemoteServerFQDN% %système.RemoteUser% %système.RemoteUserPassword% %système.RemoteScriptName% %système.RemotePropertiesFile% %système.BuildVersion% %système.Liste%
Qui existe sur le serveur distant à l'emplacement spécifié.
Ensuite ce fichier appelle cela: powershellwrapper.exe également dans l'emplacement spécifié (mon script a quatre paramètres à passer au script PowerShell)
Et qui appelle mon script avec quatre paramètres. Le script étant le premier paramètre, en plus de trois arguments. Donc, essentiellement, ce qui se passe ici, c'est que je suis de l'exécution de la PowershellWrapper.exe au lieu de le PowerShell script lui-même de la capture de l'erreur de code de sortie 0, et il rapporte encore le script complet de la course de retour à la TeamCity journal.
J'espère qu'un sens. Il fonctionne comme un charme pour nous.
À l'aide de
-ErrorAction stop
sur une commande renvoie un code de Sortie 1 par défaut et le montrent également dans TeamCity sans l'ajout d'une Condition d'Échec. Nous allons maintenant mettre en place ce comportement par défaut pour chaque commande PowerShell à l'aide de$ErrorActionPreference = "Stop";
.