Microsoft PowerShell Support for Pipeline
-
I am pleased to announce Microsoft PowerShell support for Jenkins Pipeline! As of Durable Task 1.14 and Pipeline Nodes and Processes Plugin 2.12, you will now be able to run Microsoft PowerShell scripts directly in your Jenkins Pipeline projects. This blog post covers the basics of getting started with Microsoft PowerShell in Pipeline and provides some basic examples.
Introduction to Microsoft PowerShell
PowerShell is Microsoft’s open source and cross platform command line shell, as well as an automation and configuration tool/framework which has a broad user base. PowerShell can be used to perform common system administration tasks in Windows, macOS, and Linux environments. It can also be used as a general purpose scripting language. Now that Jenkins Pipeline supports PowerShell, you can enjoy the rich set of features in PowerShell for your daily DevOps work.
Before diving into using PowerShell in your Pipeline, I recommend reading the Windows PowerShell Reference as well as the PowerShell Team Blog for an introduction to PowerShell features, utilities, and as a quick look into the PowerShell language. Microsoft also has an active PowerShell community on GitHub, which I highly recommend visiting to submitting feature requests and bug reports as you see fit. Jenkins Pipeline currently supports Microsoft PowerShell 3.0 or higher, so also be sure to check which version of PowerShell is installed on your system in order to take advantage of PowerShell in your Pipeline. Please note that we recommend that you upgrade to the latest stable version of PowerShell available, which as of this writing is version 5.1.14393.
The
powershell
stepnode { powershell 'Write-Output "Hello, World!"' }
Using Microsoft PowerShell in Pipeline
Writing PowerShell code as part of your pipeline is incredibly simple. The step that you will use is simply
powershell
, and it includes the same optional parameters as the Windows Batch (bat
) step, including:-
returnStdout: Returns the standard output stream with a default encoding of UTF-8 (alternative encoding is optional)
-
returnStatus: Returns the exit status (integer) of the PowerShell script
Examples
Capture exit status of a PowerShell script
node { def status = powershell(returnStatus: true, script: 'ipconfig') if (status == 0) { // Success! } }
Capture and print the output of a PowerShell script
node { def msg = powershell(returnStdout: true, script: 'Write-Output "PowerShell is mighty!"') println msg }
Which streams get returned when I use
returnStdout
?Until the release of PowerShell 5, there were five distinct output streams. PowerShell 5 introduced a sixth stream for pushing "informational" content, with the added benefit of being able to capture messages sent to Write-Host. Each row of the following table describes a PowerShell stream along with the corresponding Cmdlet used for writing to the stream for that particular row. Please keep in mind that stream 6 and associated cmdlets either do not exist or exhibit alternate behavior in versions of PowerShell earlier than version 5.
<table class="tableblock frame-topbot grid-all" style="width: 40%;"><colgroup><col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"></colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Stream</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Cmdlet</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top">
1
</td>
<td class="tableblock halign-left valign-top">
Output stream (e.g. stdOut)
</td>
<td class="tableblock halign-left valign-top">
Write-Output
</td>
</tr>
<tr>
<td class="tableblock halign-left valign-top">
2
</td>
<td class="tableblock halign-left valign-top">
Error stream (e.g. stdErr)
</td>
<td class="tableblock halign-left valign-top">
Write-Error
</td>
</tr>
<tr>
<td class="tableblock halign-left valign-top">
3
</td>
<td class="tableblock halign-left valign-top">
Warning stream
</td>
<td class="tableblock halign-left valign-top">
Write-Warning
</td>
</tr>
<tr>
<td class="tableblock halign-left valign-top">
4
</td>
<td class="tableblock halign-left valign-top">
Verbose stream
</td>
<td class="tableblock halign-left valign-top">
Write-Verbose
</td>
</tr>
<tr>
<td class="tableblock halign-left valign-top">
5
</td>
<td class="tableblock halign-left valign-top">
Debug stream
</td>
<td class="tableblock halign-left valign-top">
Write-Debug
</td>
</tr>
<tr>
<td class="tableblock halign-left valign-top">
6
</td>
<td class="tableblock halign-left valign-top">
Information stream
</td>
<td class="tableblock halign-left valign-top">
Write-Information (or Write-Host with caveats)
</td>
</tr>
</tbody>
</table>
If you are using the
returnStdout
option of thepowershell
Pipeline step then only stream 1 will be returned, while streams 2-6 will be redirected to the console output. For example:Write to all available streams and return the standard output
node { def stdout = powershell(returnStdout: true, script: ''' # Enable streams 3-6 $WarningPreference = 'Continue' $VerbosePreference = 'Continue' $DebugPreference = 'Continue' $InformationPreference = 'Continue' Write-Output 'Hello, World!' Write-Error 'Something terrible has happened!' Write-Warning 'Warning! There is nothing wrong with your television set' Write-Verbose 'Do not attempt to adjust the picture' Write-Debug 'We will control the horizontal. We will control the vertical' Write-Information 'We can change the focus to a soft blur or sharpen it to crystal clarity.' ''') println stdout }
Console output:
[Pipeline] { [Pipeline] powershell [TestStreams] Running PowerShell script <Jenkins Home>\workspace\TestStreams@tmp\durable-4d924c2d\powershellScript.ps1 : Something terrible has happened! At <Jenkins Home>\workspace\TestStreams@tmp\durable-4d924c2d\powershellMain.ps1:2 char:1 + & ' <Jenkins Home>\workspace\TestStreams@tmp\durable-4d924c ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,powershellScript.ps1 Warning! There is nothing wrong with your television set Do not attempt to adjust the picture We will control the horizontal. We will control the vertical We can change the focus to a soft blur or sharpen it to crystal clarity. Hello, World! [Pipeline] } [Pipeline] // node [Pipeline] End of Pipeline ERROR: script returned exit code 1 Finished: FAILURE
Note that "Hello, World!" gets printed last even though it is the first output statement in my script. Another interesting aspect of this example is that the
powershell
step failed, which ultimately caused the job to fail. The failure in this example is due to the PowerShell error stream being non-empty, which therefore caused the step to result in a non-zero exit status. However, as you will soon discover, there are a variety of causes for a failingpowershell
step.What causes a failing exit status?
When you execute a
powershell
step, it may produce a non-zero exit code and fail your pipeline build. This is very similar to other shell steps with some interesting caveats. Yourpowershell
step may produce a failing exit status in the following instances:-
Something in your PowerShell script has thrown an exception
-
Your PowerShell script explicitly calls
exit
with a non-zero exit code -
Your PowerShell script calls a native application that produces a non-zero
$LastExitCode
- $LastExitCode is an automatic variable that is set after executing a native application
-
Your PowerShell script results in a non-empty error stream (with or without throwing an exception)
Overriding the exit status behavior of your
powershell
step can be achieved by explicitly exiting from your script as long as the failure was not caused by an unhandled exception. For example:Unavoidable failure caused by an unhandled exception
node { powershell ''' throw 'Error! Problem Exists Between Keyboard And Chair' exit 0 # Unreachable code ''' }
Failed step caused by a non-empty error stream
node { powershell ''' Write-Error 'Error! Problem Exists Between Keyboard And Chair' ''' }
Failure prevented by an explicit exit
node { powershell ''' Write-Error 'Error! Problem Exists Between Keyboard And Chair' exit 0 ''' }
Scripts vs. Cmdlets
A Cmdlet is a small lightweight utility written in either C#, and compiled, or written in PowerShell directly. Depending on what your goal is in your pipeline you can make use of Cmdlets directly in your pipeline code, call a self contained PowerShell script, or some mixture of the two. If your strategy is to keep each
powershell
step as short and succinct as possible then it may make sense for you to write a library of Cmdlets, but if you have monolithic scripts then it may make sense for you to call those scripts directly from your pipeline. The choice is entirely up to you, as both scenarios are supported.Thanks for reading, and have fun!
I sincerely hope that this post has encouraged you to try using PowerShell in your Jenkins Pipeline. Please do not hesitate to file an issue against the durable-task plugin on JIRA if you have discovered any problem that you suspect is related to the
powershell
step. For general PowerShell related issues or inquiries please route your questions to the PowerShell community.http://feedproxy.google.com/~r/ContinuousBlog/~3/fGOL8XA4qKk/
-
© Lightnetics 2024