Automating releases of PowerShell scripts
A Git-based workflow to automate versioning and publishing of PowerShellGet script packages
Published in Articles on by Michiel van Oosterhout ~ 5 min read
The PowerShellGet package provider can be used to publish a PowerShell script package to a package source. Using a Git-based workflow with branches, tags, and pull requests, we can define recipes for versioning and publishing a package to multiple release channels.

The Git repository
A Git repository can either be dedicated to a single PowerShell script package, or it can contain code for many types of deliverables, some of which are PowerShell script packages. This article assumes a dedicated repository.
Versioning
The Git-based workflow uses a main branch and other branches that are merged into the main branch via pull requests. The version in the script manifest on the main branch corresponds to the current stable release of the script package (for example 1.0.0
). The version in the script manifest on any other branch must be an increment of the version on the main branch. For example, if the version in the script manifest on the main branch is 1.0.0
, then the version in the script manifest on another branch must be 1.0.1
, 1.1.0
, or 2.0.0
.
The version of prerelease packages must include a prerelease label, consisting of the name of the source branch and a number that increments everytime a prerelease is made for that branch. For example, if the branch name is topic-x
, and the version in the script manifest is 1.1.0
, then the version of the first prerelease package for that branch would be 1.1.0-topicx01
1.
Release channels
Release channels are typically used to provide prereleases of a script package early so they can be tested by others. A simple workflow could use 2 release channels, whereas a more complex workflow could use up to 4 release channels. Each release channel can be carried by a separate PowerShellGet repository, or a single PowerShellGet repository can carry all release channels.
Example 1: prerelease/release
This relatively simple example uses a prerelease and a release channel. A push to the main branch results in a publish to the release channel. Opening a pull request for any other branch and pushing to it results in a publish to the prerelease channel.
The main branch should be protected, and changes on the main branch should retrigger version checks for open pull requests. This way multiple attempts at the same version can be 'in-flight' at one time. But once one of the attempts at this version succeeds, the other attempts must increment their version. In figure 1 both topic-y
and topic-z
branches attempt to increment the version on main. The topic-y
branch attempts version 2.0.0
, whereas the topic-z
branch attempts version 1.2.0
. As soon as the topic-y
branch is merged, topic-z
must increment its version to 2.1.0
.
Example 2: edge/nightly/preview//stable
This more complex example uses 4 releases channels. There is a main branch that is kept stable. An attempt at a new version is coordinated using an alpha and a beta branch. Topic branches initially target the alpha branch, and get published to the edge channel (named after the phrase bleeding edge
). The alpha branch is the target for multiple pull requests during a longer period of time. Every night at 3:00 AM, whatever is on the alpha branch is published to the nightly channel.
When the most important changes have landed on the alpha branch, and the branch is relatively stable, it is merged into the beta branch. From this moment on topic branches target the beta branch. Once a pull request from the beta branch to the main branch is opened, the beta branch gets published to the preview channel.
Channel | Versions | Trigger |
---|---|---|
Edge | 1.3.0-{branch}{nn} |
PR from topic branch to alpha or beta |
Nightly | 1.3.0-alpha{yyMMdd} |
Scheduled for alpha |
Preview | 1.3.0-beta{nn} |
PR from beta to main |
Preview | 1.3.0 |
Merge from beta into main |
Stable | 1.3.0 |
v1.3.0 tag on main |
When the beta branch is merged into the main branch, a release is published to the preview channel. After this release has been tested, the merge commit on the main branch is tagged. The version tag results in a publish to the stable channel. Using a version tag to trigger a stable release allows for an additional level of quality assurance before making a package generally available.
Summary
A typical Git-based workflow using branches, tags, and pull requests provides just the right triggers for automating the process of versioning and publishing a PowerShell script package. Here are some links to articles that describe how to implement this using a universal deployment script on some popular Git hosting providers specifically GitHub, Azure DevOps, and Bitbucket.
Updates
- Added diagrams to explain 2 different versioning schemes.
- Simplified the release channel example.
- Removed section on manifest validation and testing, since this is covered by a follow-up article
-
PowerShellGet has limited support for semantic versioning. Prerelease labels are limited to
^[a-zA-Z0-9]+$
. ↩︎