Module Requirements#
How a script or test file declares the modules it needs, and how tightly it constrains their versions. Dependencies are declared with #Requires -Modules; the value is a module name or a module-specification hashtable. This page is the reference for the version-specification forms and which to choose. It builds on Security → Supply chain (the why) and the per-construct rules in Scripts and Functions (the where).
Valid version specifications#
| Intent | #Requires -Modules value |
Resolves to | Use when |
|---|---|---|---|
| Any version | 'Pester' or @{ ModuleName = 'Pester' } |
any installed version | almost never — only when literally any version works |
| Minimum (floor) | @{ ModuleName = 'Pester'; ModuleVersion = '6.0.0' } |
highest installed ≥ 6.0.0 | default — lets patches, minors, and majors flow in |
| Major lock (floor + wildcard ceiling) | @{ ModuleName = 'Pester'; ModuleVersion = '6.0.0'; MaximumVersion = '6.*' } |
highest installed 6.x (≥ 6.0.0, < 7.0.0) | a new major would break you — test frameworks are the typical case |
| Ceiling only | @{ ModuleName = 'Pester'; MaximumVersion = '6.*' } |
highest installed ≤ 6.x (also accepts 5.x, 4.x …) | avoid — no floor, so older majors also satisfy it |
| Exact | @{ ModuleName = 'Pester'; RequiredVersion = '6.0.0' } |
exactly 6.0.0 | avoid unless strict reproducibility demands it — fragile (breaks the moment that exact build isn't present) |
| + Identity | add GUID = 'a699dea5-2c73-4616-a270-1f7abb777e71' to any of the above |
additionally requires that module GUID | optional, stricter — anti-name-squat; independent of the version |
Why MaximumVersion = '6.*' is valid (and the sentinel 6.999.999 is not needed)#
The three version keys are not the same type on Microsoft.PowerShell.Commands.ModuleSpecification:
ModuleVersion(minimum) andRequiredVersion(exact) are parsed as[System.Version]— no wildcards.MaximumVersionis astring— specifically so it can carry a wildcard.MaximumVersion = '6.*'is valid and idiomatic; it means "any6.x". A sentinel upper bound like6.999.999works too but is unnecessary.
Other rules:
RequiredVersioncannot be combined withModuleVersionorMaximumVersion. To express a range, useModuleVersion(floor) andMaximumVersion(ceiling) together.- A major lock needs both bounds:
MaximumVersion = '6.*'alone still accepts 5.x and below, so pair it withModuleVersion = '6.0.0'. GUIDpins module identity, which is orthogonal to the version — a wrong GUID blocks even a version match, and omitting it is fine. It is a supply-chain control, not part of the version lock (see Security → Supply chain).- Requirements are enforced by the engine at parse/discovery time: if no installed module satisfies the specification, the script is not run at all.
Choosing the tightness (risk appetite)#
Match the constraint to how much drift you can safely absorb:
- Modules — declare a minimum by default so security patches flow in; major-lock (
ModuleVersion+MaximumVersion = 'N.*') a dependency whose next major would break you; avoid exact pins. Add aGUIDonly when identity assurance is required. - GitHub Actions / container images — pin to an immutable commit SHA / digest, not a moving tag (see Security → Supply chain and GitHub Actions).
- Keep pins current with automated update PRs — see Dependency Updates.
Proof#
Every row above is backed by an executable Pester test, tests/Requires-Modules.Tests.ps1. It writes a one-line #Requires script for each case, runs it in a child PowerShell, and asserts whether the requirement resolves — using the installed Pester as the sample module, so it is independent of the exact 6.x version.
Invoke-Pester -Path ./tests/Requires-Modules.Tests.ps1
It proves, among the eight cases:
- The major lock (
ModuleVersion = 'N.0.0'; MaximumVersion = 'N.*') resolves to the installedN.x. - The wildcard ceiling is enforced — a ceiling below the floor is unsatisfiable (so
6.*genuinely blocks 7.x). - An exact
RequiredVersionthat isn't installed does not resolve (why exact pins are fragile). - A wrong GUID blocks an otherwise-matching module, while omitting the GUID still resolves (identity is optional and orthogonal to version).