Publishing your private modules to PSGallery
The psgalleryRelease.yml workflow publishes a tagged release from your GitHub Packages feed directly to PSGallery. It is included in the ModuleForge GitHub scaffold and is triggered manually - you choose which release to publish and when.
PSGallery is permanent. Once a version is published it cannot be deleted, only unlisted. Publish intentionally.
Step 1 - Get the workflow file
The psgalleryRelease.yml file is bundled with ModuleForge’s GitHub scaffold. If you have already run Add-MFGithubScaffold, run it again without -Force to pick up any new workflow files while leaving your existing customised workflows untouched:
Add-MFGithubScaffold
Files that already exist in your .github/ folder are skipped. Only missing files - including psgalleryRelease.yml if it wasn’t there before - are copied.
Commit the new file to main before continuing:
chore: add PSGallery release workflow
Step 2 - Add a PSGallery API key secret
The workflow reads your PSGallery API key from a repository secret named PSGALLERY.
To get your API key:
- Log in at powershellgallery.com
- Go to your account settings - the API Keys section is on the right side of the page
- Create a key scoped to Push new packages and package versions for your module (or all packages)
To add it to your repository:
- Go to your repository → Settings → Secrets and variables → Actions
- Click New repository secret
- Name:
PSGALLERY - Value: your API key
- Save
Step 3 - Run the workflow
Navigate to Actions → PSGallery Release → Run workflow.
Inputs
release_selector (required)
Controls which tagged release is published. The workflow fetches your full release list and filters it accordingly.
| Option | What it selects |
|---|---|
latest-release (default) | The most recently created release, regardless of stable or prerelease status |
latest-stable | The most recent release that is not marked as a prerelease |
latest-prerelease | The most recent release that is marked as a prerelease |
If you publish a prerelease version to PSGallery, it will appear there as a prerelease - hidden from
Find-PSResource/Find-Moduleunless-AllowPrereleaseis passed. Uselatest-stableunless you specifically intend to publish a prerelease to PSGallery.
moduleforge_release_toggle (optional)
Controls which version of ModuleForge is used internally by the workflow itself. Leave this at the default (moduleforge-latest-stable-only) unless you are testing a ModuleForge prerelease build.
What the workflow does
- Reads the release list - uses the
ghCLI to list releases and selects one based on yourrelease_selectorchoice - Installs ModuleForge and PSResourceGet
- Registers your GitHub Packages feed as a PSResource repository using the built-in
GITHUB_TOKEN - Finds the specific version in GitHub Packages by matching the release tag
- Installs the module from GitHub Packages locally on the runner
- Resolves module case - calls
Resolve-MFModuleCaseto handle NuGet’s case-insensitive install behaviour, ensuring the module folder name matches the manifest exactly for PSGallery compatibility - Checks for duplicates - queries PSGallery to confirm the version does not already exist; throws if it does, preventing accidental republishing
- Publishes to PSGallery using
Publish-PSResourcewith yourPSGALLERYAPI key
Troubleshooting
“No matching release found” - No release exists that matches the selector. Check that at least one release has been created via the Build and Release workflow.
“Version X already exists on PSGallery” - The version tag you selected has already been published. You cannot republish the same version. Increment the version with a new Build and Release run before publishing again.
“Module not found after install” - The case resolution step failed. Check that moduleForgeConfig.xml is present and moduleName matches the module’s manifest name exactly.
Workflow passes but module doesn’t appear on PSGallery - PSGallery indexing can take several minutes. Wait a few minutes and search again. If the module is a prerelease, use Find-PSResource -Name YourModule -AllowPrerelease to find it.
Verifying without publishing
To do a dry run - install and inspect the module without pushing to PSGallery - comment out the Publish-PSResource call in psgalleryRelease.yml temporarily and inspect the verbose output from the install step. Revert the comment before merging.