Published in Articles on by Michiel van Oosterhout ~ 3 min read
The previous article described the process of creating, publishing, and installing a PowerShell module. Since we'll likely need our PowerShell modules to evolve over time, adding features and fixing bugs, we will have to publish new versions somewhat regularly. In this article we'll look at a script that we can use to implement Git-based versioning and publishing to multiple release channels.

Git-based versioning and automation
Automation is key to make sure our process is
- safe: only publish if all tests pass;
- correct: ensure we publish prereleases and releases to separate channels;
- and easy: automatically publish when changes are committed and/or approved.
In the past we've already looked at two different recipes for Git-based versioning and publishing to release channels, and we implemented one of them for PowerShell script packages, which we then used in a GitHub workflow, as well as Azure DevOps, Bitbucket, and GitLab pipelines. We even made it work for repositories with multiple scripts.
All of these techniques can be applied PowerShell modules as well. That just leaves us with some small modifications to Publish-PowerShellScript.ps1
, so it can be used to publish a module instead of a script package.
Publish-PowerShellModule
The name of the cmdlet will change from Publish-PowerShellScript
to Publish-PowerShellModule
, but the Param
block does not change.
The first significant change is the $manifestPath
which changes to the .psd1
file path. Note that, although a module manifest is optional, to publish a module it is required. After determining the path to the manifest, we change the call to validate the manifest from Test-ScriptFileInfo
to Test-ModuleManifest
.
The code analysis for a script package is invoked on all .ps1
files, excluding .Tests.ps1
files. For a module it should also be invoked on .psm1
and .psd1
files.
When publishing a prerelease we need to update the manifest. For a module we need to use Update-ModuleManifest
instead of Update-ScriptFileInfo
. And instead of setting the version to include a prerelease label (e.g. 1.2.0-beta0001
), we can simply use the -Prerelease
Finally, we use Publish-Module
instead of Publish-Script
, and we provide the path to the manifest's parent directory.
With those relatively small changes we get Publish-PowerShellModule.ps1
, a script to publish a PowerShell module, using a Git-based workflow to choose the release channel.
Caveats and improvements
For simple scenarios the script will work, but there are a few caveats, as well as a few possible improvements:
- Any
.Tests.ps1
files will be included in the NuGet package. - Dependencies (
RequiredModules
) should be installed and imported into the session before running the script.
(The script could perform these actions automatically, except it may not be clear what the source repository for each dependency should be.) - Dependencies from the PowerShell Gallery must be available in the target repository.
(This is only an issue when publishing to a private repository. One solution is to add the name of each dependency to thePrivateData.PSData.ExternalModuleDependencies
array.) - The script has not been tested with nested modules.
- The script could auto-generate the informational lists of files (
FileList
) and modules (ModuleList
).
Conclusion
The workflow for publishing a PowerShell module is very similar to that for publishing a PowerShell script package. The original script requires only minor adjustments for the simple scenario of publishing a single module, with no nested modules or dependencies.