23
votes

I'm using Jenkins PowerShell plugin to build a project.

However, I found that Jenkins always considers my build successful no matter what I type inside Windows PowerShell command.

Here's an example:

enter image description here

As you can see, asdf isn't a legal command. Jenkins should give me FAILURE after the build.

But the console output gives me:

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

I think the execution result of PowerShell should depend on $lastexitcode.

Is this a bug of PowerShell plugin?

6
In your powershell script when an error occurs use "exit x" where x is a non-zero number. See if Jenkins considers it failed then. - DanL
Yes, Jenkins considers exit 1 as failed. - Brian
Then change your scripts to exit with a non-zero error code if an error occurs. If you want it to depend only on $lastexitcode then at the bottom of your script check $lastexitcode and use exit 1 if applicable. - DanL
Finally, I add exit $LastExitCode at the end of my script. - Brian

6 Answers

12
votes

As of 1.3, the plugin will not handle exceptions such as those from missing commands. You can do this yourself with try/catch:

try
{
    asdf
}
catch
{
    write-host "Caught an exception"
    exit 1
}

See MSDN for more.

9
votes

For me, I wanted the script to stop and fail in Jenkins soon as it hit an error. This was accomplished by adding this to the start of the script:

$ErrorActionPreference = "Stop"

This is discussed here: How to stop a PowerShell script on the first error?

5
votes

Per the latest version of the plugin (Version 1.3 Sept 18 2015), you must use $LastExitCode to fail a build.

Version 1.3 (Sept 18 2015)

  • PowerShell now runs in Non-Interactive mode to prevent interactive prompts from hanging the build
  • PowerShell now runs with ExcecutionPolicy set to "Bypass" to avoid execution policy issues
  • Scripts now exit with $LastExitCode, causing non-zero exit codes to mark a build as failed
  • Added help and list of available environment variables (including English and French translations)
1
votes

I want to add here that I just ran into a quirk: you must have the powershell script end with exit and not return.

My jenkins pipe looked like:

script {
  result = powershell(returnStatus: true, script: '''...if(error condition) { return 1 }''')
  
  if(result) { error }
}

I was using if(error condition) { return 1 } and while the 1 was showing up as the return value in the jenkins console, it was not failing the build. When i used if(error condition) { exit 1 }, the build failed as expected.

I think this is a helpful addition to this thread - the need to use exit and not return. But I don't understand this part: the pipe is checking for result to be non-zero. What is the difference between exit and return in a powershell directive that makes if(result) { error } not work as expected when using return?

Update Feb-16-2021: Coming back to this to add some more notes from my experience: I think what I was doing and what a lot of people do that confuses things, is to use returnStdout or returnStatus and not check them and/or not fully understand what's coming back.

If you use either of those params, Jenkins will not do anything for you based on their value. You have to check them yourself and act accordingly. On the other hand, if you don't use them, Jenkins will recognize a failure code and fail the pipe if one comes back.

Think about it: If you set returnStatus, you're getting the exit code back from the step as a return value and not as something for Jenkins itself to worry about. If you set returnStdout, you're getting the stdout stream - and not any error codes or anything from stderr. So you must check the return for what you want or you will not get the behavior you are expecting.

What I've been doing for a while is actually not setting either of those params and making sure to set $ErrorActionPreference = 'Stop' at the start of any and all PowerShell scripts running in my pipes. That way any powershell failures automatically fail the pipe as expected, without having to check it.

0
votes

This is how I implemented RRIROWER's solution. Hope it helps.

<yourscript>.ps1; exit $lastexitcode

Make sure your powershell scripts does exit with the desired value.
Run "exit <value>" as the last line.

0
votes

Ultimately, I had to resort to the following configuration in Jenkins as none of the solutions here worked for me. Chris Nelson's answer got me on the right track. We're invoking chef-client remotely so we had to do a little magic to get the remote PS session to talk the local and then pass status on to Jenkins.

  • $res gives the output of chef-client.
  • $lastsuccess is true or false according to PS rules of engagment.

Of course, you'll have to supply your own evironment variables! :)

 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