我正在使用 Jenkins PowerShell 插件构建项目。
然而,我发现无论我在
Windows PowerShell
命令中输入什么,Jenkins 总是认为我的构建成功。
举个例子:
如您所见,
asdf
不是合法的命令。詹金斯应该在构建后给我FAILURE
。
但是控制台输出给我:
Started by user admin
Building in workspace C:\Users\Administrator\.jenkins\jobs\Test\workspace
[workspace] $ powershell.exe -NonInteractive -ExecutionPolicy ByPass "& 'C:\Users\ADMINI~1\AppData\Local\Temp\hudson2092642221832331776.ps1'"
The term 'asdf' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At C:\Users\ADMINI~1\AppData\Local\Temp\hudson2092642221832331776.ps1:1 char:5
+ asdf <<<<
+ CategoryInfo : ObjectNotFound: (asdf:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Finished: SUCCESS
我觉得PowerShell的执行结果应该取决于
$lastexitcode
.
这是PowerShell插件的bug吗?
从 1.3 开始,插件将不会处理诸如缺少命令的异常。你可以自己做这个
try/catch
:
try
{
asdf
}
catch
{
write-host "Caught an exception"
exit 1
}
有关更多信息,请参阅MSDN。
对我来说,我希望脚本在遇到错误时立即停止并在 Jenkins 中失败。这是通过将其添加到脚本的开头来完成的:
$ErrorActionPreference = "停止"
此处讨论:[如何在出现第一个错误时停止 PowerShell 脚本?][1]
[1]:如何在出现第一个错误时停止 PowerShell 脚本?。 ...................
根据插件的最新版本(2015 年 9 月 18 日 1.3 版),您必须使用 $LastExitCode 才能使构建失败。
1.3 版(2015 年 9 月 18 日)
- PowerShell 现在以非交互模式运行,以防止交互提示挂起构建
- PowerShell 现在在 ExcecutionPolicy 设置为“绕过”的情况下运行以避免执行策略问题
- 脚本现在以 $LastExitCode 退出,导致非零退出代码将构建标记为失败
- 添加了可用环境变量的帮助和列表(包括英文和法文翻译)
我想在这里补充一点,我刚刚遇到了一个怪癖:你必须让 powershell 脚本以
exit
而不是 return
结尾。
我的詹金斯管道看起来像:
script {
result = powershell(returnStatus: true, script: '''...if(error condition) { return 1 }''')
if(result) { error }
}
我正在使用
if(error condition) { return 1 }
,虽然 1 在 jenkins 控制台中显示为返回值,但 not 构建失败。当我使用if(error condition) { exit 1 }
时,构建如预期的那样失败了。
我认为这是对该线程的有益补充-需要使用
exit
而不是return
。但我不明白这部分:管道正在检查 result
是否为非零。 exit
和 return
在 powershell 指令中有什么区别,这使得 if(result) { error }
在使用 return
时无法按预期工作?
2021 年 2 月 16 日更新: 回到这里根据我的经验添加更多注释:我认为我正在做的事情和很多人所做的事情混淆了事情,就是使用
returnStdout
或 returnStatus
并且不检查它们和/或不完全了解会返回什么。
如果您使用这些参数中的任何一个,Jenkins 将not 根据它们的值为您做任何事情。你必须自己检查它们并采取相应的行动。另一方面,如果你不使用它们,詹金斯will识别失败代码并在管道返回时失败。
想一想:如果您设置
returnStatus
,您将从该步骤返回退出代码作为返回值,而不是 Jenkins 本身需要担心的事情。如果您设置 returnStdout
,您将获得 stdout
流 - 并且 not 任何错误代码或来自 stderr
的任何内容。所以你必须检查你想要的回报,否则你不会得到你期望的行为。
我一段时间以来一直在做的实际上是没有设置这些参数中的任何一个,并确保在我的管道中运行的任何和所有 PowerShell 脚本的开头设置
$ErrorActionPreference = 'Stop'
。这样,任何 powershell 故障都会按预期自动使管道失效,而无需检查它。
我就是这样实现RRIROWER的解决方案的。希望能帮助到你。
<yourscript>.ps1; exit $lastexitcode
确保您的 powershell 脚本确实以所需的值退出。
运行
"exit <value>"
作为最后一行。
最终,我不得不求助于 Jenkins 中的以下配置,因为这里的解决方案都不适合我。 Chris Nelson 的回答让我走上了正确的轨道。我们正在远程调用 chef-client,因此我们必须施展魔法让远程 PS 会话与本地对话,然后将状态传递给 Jenkins。
当然,您必须提供自己的环境变量! :)
Write-host "Deploying $env:Computer with $env:Databag data bag... "
$secstr = ConvertTo-SecureString $env:Password -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $env:User, $secstr
$s = New-PSSession -ComputerName $env:Computer -Credential $cred
$res = Invoke-Command -Session $s -ScriptBlock { try {chef-client} catch {exit 1}}
$lastsuccess = Invoke-Command -Session $s -ScriptBlock {$?}
Remove-PSSession $s
write-host " --- "
write-host $res
write-host " --- "
if($lastsuccess)
{
write-host "chef deployment completed"
exit 0
}
write-host "chef deployment had errors"
exit 1
以下示例显示 Powershell cmdlet 未设置
$LASTEXITCODE
。因此,它只有在运行可执行文件时才有用。
$LASTEXITCODE = 0 # Success
try {
CommandDoesntExist
} catch {
# Exit code is unchanged
Write-Error $Error[0]
Write-Host "Exit Code $LASTEXITCODE"
}
>> Error Message...
>> Exit Code 0
对于纯 Powershell,您需要自己处理错误并提供退出代码。为避免将整个脚本嵌套在 try/catch 中,您可以改用 trap。本地 try/catch 仍然可以用于处理您预计会失败的块。
# Global error handling avoids nesting all
# code in a try/catch/finally.
trap { Write-Error $Error[0]; exit 1 }
# Block specific error handling
try {
throw "Worst case scenario"
} catch {
write-host "Handled error doesn't trigger trap"
}
# Finally example
try {
throw "Worst case scenario"
} finally {
write-host "I still cleanup"
}
exit 0