Templates¶
A template is a plain text file that defines the structure of the generated output script.
PSScriptBuilder replaces {{Token}} placeholders with the collected and dependency-ordered
source code from configured collectors. Static text before, between, and after placeholders
is preserved as-is.
The template is what separates PSScriptBuilder from a simple file concatenation tool. It gives
you full control over the structure of the output script — module header comments, #Requires
statements, fixed boilerplate, and the order of component blocks are all defined in the
template, not in the build script.
Placeholders use double curly braces around the collector's CollectionKey:
PSScriptBuilder supports three validation modes — Free Mode, Hybrid Mode, and
Ordered Mode — which determine which placeholders are required or forbidden in the template.
Free Mode is the default. Ordered Mode is activated automatically when cross-dependencies are
detected. Hybrid Mode is activated manually by placing the ordered components placeholder
(default: {{ORDERED_COMPONENTS}}) in a template whose code has no cross-dependencies.
Walkthrough¶
1. Your First Template¶
The simplest template maps each collector type to a separate placeholder in the expected order:
{{USING_STATEMENTS}}
{{ENUM_DEFINITIONS}}
{{CLASS_DEFINITIONS}}
{{FUNCTION_DEFINITIONS}}
{{FILE_CONTENTS}}
Each placeholder is replaced with the correctly ordered source code collected by the
corresponding collector. The token names match the default CollectionKey for each collector
type — see the Collectors Guide for the full list.
2. Custom Collection Keys¶
When you register a collector with a custom -CollectionKey, the template must use that key
as the placeholder — e.g. {{DOMAIN_CLASSES}} for a collector registered with
-CollectionKey "DOMAIN_CLASSES":
$contentCollector = New-PSScriptBuilderContentCollector |
Add-PSScriptBuilderCollector -Type Class -CollectionKey "DOMAIN_CLASSES" -IncludePath "src\Domain"
Custom keys are case-insensitive at match time but preserved as written in the template output.
3. Validate Your Template¶
A mismatch between the collectors you registered and the placeholders in the template — a
missing token, a typo in a key, or a wrong ordering — will cause the build to fail with a
validation error. Test-PSScriptBuilderTemplate
catches these problems before the collection and output steps run, without requiring a full build.
Validate your template whenever you add or rename a collector, change a -CollectionKey, or
edit the template file:
$contentCollector = New-PSScriptBuilderContentCollector |
Add-PSScriptBuilderCollector -Type Class -IncludePath "src\Classes" |
Add-PSScriptBuilderCollector -Type Function -IncludePath "src\Public"
if (Test-PSScriptBuilderTemplate -ContentCollector $contentCollector -TemplatePath "template.psm1") {
Invoke-PSScriptBuilderBuild -ContentCollector $contentCollector `
-TemplatePath "template.psm1" `
-OutputPath "output.psm1"
}
Add -Verbose to see detailed validation messages.
For a full analysis result object, use
Get-PSScriptBuilderTemplateAnalysis:
$analysis = Get-PSScriptBuilderTemplateAnalysis -ContentCollector $contentCollector -TemplatePath "template.psm1"
Write-Host "Valid: $($analysis.IsValid)"
Write-Host "Mode: $($analysis.ValidationMode)"
Write-Host "Found: $($analysis.PlaceholdersFound -join ', ')"
Write-Host "Missing: $($analysis.MissingPlaceholders -join ', ')"
Write-Host "Unknown: $($analysis.UnknownPlaceholders -join ', ')"
4. Ordered Mode and Hybrid Mode¶
Ordered Mode is activated automatically when classes and functions have mutual dependencies that require them to be interleaved. In this case PSScriptBuilder cannot emit classes and functions in separate blocks — they must be interleaved in a single dependency-ordered sequence.
Hybrid Mode is activated manually, by placing the ordered components placeholder in a template whose code has no cross-dependencies yet. Use it when you want a template that remains valid regardless of whether cross-dependencies are introduced later — for example, when your project is still growing and you want to avoid restructuring the template at the moment cross-dependencies first appear.
Both modes use the same placeholder:
All Enum, Class, and Function components are emitted in a single topologically ordered block
at {{ORDERED_COMPONENTS}}. Per-type placeholders for those collector types are forbidden in
both modes. Using and File placeholders remain valid and optional, and Using must appear
before {{ORDERED_COMPONENTS}}.
Hybrid Mode is useful for mode-agnostic templates: a template using the ordered components placeholder remains valid regardless of whether cross-dependencies are introduced later, avoiding the need to restructure the template when the codebase grows.
Protect Free Mode templates from future breakage
A Free Mode template will fail validation the moment cross-dependencies are introduced — for example, when a new function references a class that also references that function. Adding the ordered components placeholder to the template now converts it to Hybrid Mode and makes it resilient to such changes without any further restructuring.
The same template before and after converting to Hybrid Mode:
{{USING_STATEMENTS}}
{{ENUM_DEFINITIONS}}
{{CLASS_DEFINITIONS}}
{{FUNCTION_DEFINITIONS}}
The placeholder name defaults to ORDERED_COMPONENTS and can be overridden with
-OrderedComponentsKey on
Invoke-PSScriptBuilderBuild and
Test-PSScriptBuilderTemplate. To keep the
template and the build call in sync, store a custom key in psscriptbuilder.config.json:
$config = Get-PSScriptBuilderConfiguration
Invoke-PSScriptBuilderBuild -ContentCollector $contentCollector `
-TemplatePath "template.psm1" `
-OutputPath "output.psm1" `
-OrderedComponentsKey $config.Build.OrderedComponentsKey
5. Combining with Release Management Tokens¶
A build template can also contain release metadata tokens — version numbers, build timestamps,
Git commit hashes — using the same {{Token}} syntax. These tokens are replaced by
Update-PSScriptBuilderBumpFiles before
the build runs:
# Version {{VERSION}} — built {{BUILD_DATE}}
{{USING_STATEMENTS}}
{{CLASS_DEFINITIONS}}
{{FUNCTION_DEFINITIONS}}
The release tokens ({{VERSION}}, {{BUILD_DATE}}) are injected by the bump step and are
gone by the time Invoke-PSScriptBuilderBuild validates the template — the build validator
only sees the collector placeholders. The corresponding bump file entry looks like this:
{
"bumpFiles": [
{
"description": "Module template — inject version and build date",
"path": "build\\Templates\\MyModule.psm1.template",
"tokens": ["VERSION", "BUILD_DATE"]
}
]
}
On subsequent releases, the {{TOKEN}} placeholders are already gone — use a regex-based
entry to update the already-substituted values. See the
Release Management Guide for the full token list, regex placeholder
syntax ({REGEX_VERSION}, {REGEX_BUILD_DATE}), and multi-entry bump file configuration.
Run bump before build
If release tokens are still present in the template when Invoke-PSScriptBuilderBuild
runs, the validator will report them as unknown placeholders and fail. Always call
Update-PSScriptBuilderBumpFiles before Invoke-PSScriptBuilderBuild.
Reference¶
Placeholder Rules¶
- Keys are case-insensitive at match time
- No whitespace inside the braces —
{{ Key }}is invalid and causes a validation error - Each placeholder may appear only once in the template
- Only keys matching a registered collector (or
{{ORDERED_COMPONENTS}}) are valid
Validation Modes¶
| Mode | When activated | Required | Forbidden |
|---|---|---|---|
| Free | No cross-dependencies and no ordered components placeholder in template | One placeholder per collector | — |
| Hybrid | No cross-dependencies, but ordered components placeholder present in template | Ordered components placeholder | Per-type placeholders for Enum, Class, Function |
| Ordered | Classes and functions have mutual dependencies (automatic) | Ordered components placeholder | Per-type placeholders for Enum, Class, Function |
In Free Mode, two ordering rules are enforced: Using placeholders must appear before all
others; Enum placeholders must appear before all Class and Function placeholders. The
position of File placeholders is unrestricted relative to Enum, Class, and Function.
In Ordered and Hybrid mode, Using placeholders must appear before the ordered components placeholder.
Validation Error Reference¶
| Error | Cause | Fix |
|---|---|---|
| Whitespace in placeholder | {{ Key }} instead of {{Key}} |
Remove whitespace inside braces |
| Missing ordered components placeholder | Ordered or Hybrid mode but placeholder absent | Add the ordered components placeholder to the template |
| Forbidden placeholder in Ordered/Hybrid mode | {{CLASS_DEFINITIONS}} etc. present when the ordered components placeholder is used |
Remove per-type placeholders; use only the ordered components placeholder |
| Collector placeholder missing | A registered collector has no matching placeholder | Add {{CollectionKey}} for each collector |
| Wrong placeholder order (Using) | A non-Using placeholder appears before {{USING_STATEMENTS}} |
Move Using placeholders before all others |
| Wrong placeholder order (Enum) | A Class or Function placeholder appears before {{ENUM_DEFINITIONS}} |
Move Enum placeholders before all Class and Function placeholders |
| Duplicate placeholder | Same {{Key}} appears more than once |
Remove the duplicate |
| Unknown placeholder | {{UNKNOWN}} has no corresponding collector |
Remove it or register a matching collector |
Analysis Result Properties¶
Get-PSScriptBuilderTemplateAnalysis returns a PSScriptBuilderTemplateAnalysisResult with:
| Property | Description |
|---|---|
IsValid |
Whether the template passed all validation rules |
ValidationErrors |
Array of error messages (empty when valid) |
ValidationMode |
Free, Hybrid, or Ordered |
OrderedComponentsKey |
The placeholder key used for the ordered components block (default: ORDERED_COMPONENTS) |
HasCrossDependencies |
Whether cross-dependencies were detected |
PlaceholdersFound |
All {{...}} tokens found in the template (sorted, unique) |
PlaceholdersExpected |
Tokens expected based on collectors and mode |
MissingPlaceholders |
Expected but not found in template |
UnknownPlaceholders |
Found in template but not matching any collector |
TemplatePath |
Resolved absolute path to the template file |
TemplateSize |
Template character count |
Tips¶
Always validate before building
Use Test-PSScriptBuilderTemplate to validate the template without running a full build.
This gives fast feedback during development and makes template mismatches explicit
before the collection and output steps run.
Use -Verbose during development
Both Test-PSScriptBuilderTemplate and Get-PSScriptBuilderTemplateAnalysis emit verbose
messages that show exactly which placeholders were found, expected, and missing.
Custom OrderedComponentsKey must match in template and build call
If you override the default ORDERED_COMPONENTS key, the placeholder in the template and
the -OrderedComponentsKey argument must use the same value. Storing it in
psscriptbuilder.config.json is the safest way to keep them in sync.
See Also¶
- Release Management Guide — version tokens and bump file configuration
- Dependency Analysis Guide — how cross-dependencies are detected