Skip to content

Latest commit

Β 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧰 PowerShell Module Template

A batteries-included starting point for PowerShell modules.

Build with ModuleBuilder, test with Pester, lint with PSScriptAnalyzer, and ship to the PowerShell Gallery from a git tag.

CI License PowerShell Platforms


✨ Features

πŸ—οΈ ModuleBuilder Builds your module from source into a clean, versioned Dist output
πŸ§ͺ Pester 5 Test runner wired to Tests/: behaviour tests run against the source tree (failures name a source file and line), artifact checks against the built module
πŸ” PSScriptAnalyzer Style and correctness pass, plus a compatibility pass against your target hosts
πŸ“Š Code coverage Per-file coverage report over the source tree with an optional minimum-percentage gate
🎯 Task runner One entry point (tasks.ps1) for every tool
πŸ€– GitHub Actions CI matrix across your target hosts, plus a tag-driven Gallery release
🧩 Platform presets PowerShell5.1, PowerShell7, or both. One key sets the manifest, the lint targets, and the CI matrix
πŸͺ„ prepare task Renames and stamps the whole template from a single module.psd1
πŸ” Hardening guide The GitHub rulesets and settings that make publishing to the Gallery safe
πŸ“ Structured source Source/ layout with Enum, Classes, Private, and Public. Classes and enums have rules of their own: see Docs/CLASSES_AND_ENUMS.md

πŸš€ Quick Start

1️⃣ Create your repository

Use as a template (recommended)

Use this template > Create a new repository

Use_Template

Or clone it
git clone https://github.com/ArchitektApx/PowershellModuleTemplate
cd PowershellModuleTemplate

2️⃣ Configure your module

Edit module.psd1 at the repository root:

Property Description
ModuleName Your module name (no spaces, must start with a letter)
ModuleDescription Short description of the module
ModuleTargetPlatform Which PowerShell hosts you target. See Target platforms
ModuleAuthor Your name or team
ModuleCompanyName Company or vendor. Also becomes the LICENSE copyright holder
ModuleProjectUri Your repository URL. Becomes ProjectUri/LicenseUri and the changelog compare links
ModuleRequiredModules Extra development-time dependencies, on top of the fixed base set
ModuleRequiredPowershellVersion Optional. Pin a higher minimum than the platform default; empty uses the default

Note

CompatiblePSEditions and PowerShellVersion are derived from ModuleTargetPlatform, so there is no separate key for them.

3️⃣ Run the prepare task

./tasks.ps1 prepare
./tasks.ps1 prepare -Platform PowerShell7   # override the platform for this run

This renames Source/ModuleTemplate.ps[dm]1, generates a fresh GUID, stamps the manifest, build.psd1 and LICENSE, generates Tools/PSScriptAnalyzer.psd1 and the CI matrix for your target platform, renders a README.md and CHANGELOG.md for your module, deletes the template-only scaffolding (res/, Tools/templates/, Tools/platforms/), and installs the dev requirements.

Warning

prepare overwrites README.md, CHANGELOG.md, Tools/PSScriptAnalyzer.psd1 and .github/workflows/ci.yml. Run it on a fresh clone, before you have written anything of your own.

4️⃣ Write and verify

Add one .ps1 per function under Source/Public (exported) or Source/Private (internal), then:

./tasks.ps1 build
./tasks.ps1 test
./tasks.ps1 lint

The built module lands in Dist/<ModuleName>/<ModuleVersion>. πŸŽ‰


πŸ–₯ Target platforms

ModuleTargetPlatform selects one of the presets in Tools/platforms/:

Preset Manifest Lint targets CI hosts
πŸͺŸ PowerShell5.1 Desktop, 5.1.0 5.1 win / WinPS 5.1
🌍 PowerShell7 Core, 7.0.0 7.0 win, linux, macos / pwsh 7
πŸ”€ PowerShell5.1And7 Core, Desktop, 5.1.0 5.1 + 7.0 all four (default)

The lint step enforces the preset. A ternary or ?? in Source/ passes under PowerShell7 and fails under PowerShell5.1And7.

Tip

Retargeting after prepare means editing Tools/PSScriptAnalyzer.psd1 and the ci.yml matrix by hand, since Tools/platforms/ is gone by then.


πŸ“‚ Project Structure

See ModuleBuilder for how the source tree is assembled into the built module.

.
β”œβ”€β”€ πŸ“„ module.psd1          # Module metadata consumed by the tooling
β”œβ”€β”€ πŸ“„ build.psd1           # ModuleBuilder build config (manifest path, output, SemVer)
β”œβ”€β”€ 🎯 tasks.ps1            # Task runner
β”œβ”€β”€ πŸ“ Source/
β”‚   β”œβ”€β”€ ModuleTemplate.psd1   # Becomes <YourModuleName>.psd1 after prepare
β”‚   β”œβ”€β”€ ModuleTemplate.psm1   # Becomes <YourModuleName>.psm1 after prepare
β”‚   β”œβ”€β”€ Enum/
β”‚   β”œβ”€β”€ Classes/
β”‚   β”œβ”€β”€ Private/
β”‚   └── Public/
β”œβ”€β”€ πŸ§ͺ Tests/
β”‚   β”œβ”€β”€ _TestHelpers.ps1      # Target selection and import helpers; no module name hardcoded
β”‚   β”œβ”€β”€ Harness.Tests.ps1     # Tests for the test harness itself
β”‚   └── Module.Tests.ps1      # Artifact checks against the BUILT module, green on a fresh clone
β”œβ”€β”€ πŸ”§ Tools/
β”‚   β”œβ”€β”€ platforms/          # Target-platform presets (removed by prepare)
β”‚   β”œβ”€β”€ templates/          # Skeletons rendered by prepare (removed by prepare)
β”‚   └── ...                 # See Tools/README.md
β”œβ”€β”€ πŸ” Docs/HARDENING.md    # GitHub settings to set before publishing (survives prepare)
β”œβ”€β”€ πŸ“š Docs/CLASSES_AND_ENUMS.md  # Class/enum rules and limits (removed by prepare)
β”œβ”€β”€ πŸ€– .github/workflows/   # ci.yml (matrix from the platform) and release.yml (tag -> PSGallery)
└── πŸ“¦ Dist/                # Build output (gitignored, created by build)

πŸŽ› Tasks Reference

./tasks.ps1 <TaskName>
Task Description
πŸͺ„ prepare One-time template setup. Run once, after editing module.psd1. -Platform <name> overrides ModuleTargetPlatform.
🧹 cleanup One-time teardown. Deletes prepare.ps1 and itself and strips both tasks out of tasks.ps1. Run once the repo is prepared and hardened.
πŸ“₯ install_dev_requirements Installs ModuleBuilder, Configuration, Pester 5+, PSScriptAnalyzer, plus your extras. Once per host per PowerShell edition.
πŸ—οΈ build Clears Dist/, builds with ModuleBuilder into Dist/<ModuleName>/<ModuleVersion>.
πŸ§ͺ test Builds, then runs the Pester suite. -Target Source (default) or Dist picks the tree the behaviour tests import; -Path <file-or-dir> picks which tests execute. Fails on an empty run.
πŸ” lint PSScriptAnalyzer over Source/: style and correctness, then compatibility against your target platform.
πŸ“Š coverage Per-file coverage report over the source tree. -MinimumPercent 90 to gate.
🚒 prepare_release ./tasks.ps1 prepare_release 1.1.0. Gates, promotes the changelog, stamps the version, rebuilds, verifies.

πŸ“– Full tool reference: Tools/README.md


πŸ€– CI and Releases

ci.yml runs lint, build, and test on every push and pull request. Which hosts it runs on comes from your ModuleTargetPlatform; the template's own default is all four (Windows PowerShell 5.1, and pwsh 7 on Windows, Linux, and macOS).

release.yml fires on a vX.Y.Z tag. It requires the tagged commit to be on the default branch, requires the tag to match the built manifest version, runs the full CI matrix, then publishes to the PowerShell Gallery and creates a GitHub release whose body is that version's CHANGELOG.md section.

The release flow after prepare_release has stamped the version and the PR is merged:

git checkout master
git pull origin master
git tag v1.1.0
git push origin v1.1.0

The generated module README documents this in full. Pull first: the tag has to land on the merged commit, not on whatever you had locally.

Important

Publishing needs a repository secret PSGALLERY_API_KEY. The workflow also refuses to release while module.psd1 still names the module ModuleTemplate.


πŸ” Hardening the repository

Caution

The release workflow publishes to the PowerShell Gallery, where a version number can never be reused and consumers install without reviewing what they get. That makes push access to your default branch equivalent to push access to everyone's machines.

Docs/HARDENING.md covers how to close that path:

πŸ”‘ the publishing secret Β β€’Β  πŸ›‘οΈ a default-branch ruleset with an empty bypass list Β β€’Β  🏷️ immutable release tags Β β€’Β  πŸ€– read-only Actions permissions Β β€’Β  πŸ”Ž secret scanning with push protection Β β€’Β  ✍️ commit signing

Each step says what it does and why it matters, and most come with a gh command.

None of it is on by default, and none of it survives "Use this template". It is GitHub configuration rather than repository content, so you have to redo it per repo. Do it before the first tag.


πŸ“¦ Build Output

  • πŸ”’ Version is controlled in build.psd1 via the SemVer key, which prepare_release stamps for you.
  • πŸ“€ Copy Dist/<ModuleName>/<ModuleVersion> to a module path, or let the release workflow publish it.

πŸ“œ License

MIT. See the LICENSE file in this repository.

About

Starting point for new PowerShell modules, with build, test and publish wired up from the first commit

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages