DEV Community

Cover image for When PowerShell Classes and Functions Depend on Each Other — How PSScriptBuilder Handles It
Tim Hartling
Tim Hartling

Posted on

When PowerShell Classes and Functions Depend on Each Other — How PSScriptBuilder Handles It

When you build a PowerShell project from multiple files, the natural structure is clear: enums first, then classes, then functions. Each group has its own place, and as long as dependencies only flow in one direction, that structure works perfectly.

But sometimes a function depends on a class, and that class calls the function. There is no longer a clean boundary between the two groups — they need to be interleaved in the output. That's a cross-dependency, and handling it manually is where things get fragile.

What a Cross-Dependency Looks Like

Consider this scenario:

# New-Report.ps1
function New-Report([ReportConfig] $config) {
    # uses ReportConfig as a parameter type
}

# ReportConfig.ps1
class ReportConfig {
    [string] $Title

    [void] Generate() {
        New-Report $this  # calls New-Report
    }
}
Enter fullscreen mode Exit fullscreen mode

New-Report references ReportConfig as a parameter type — so ReportConfig must be defined before New-Report is loaded. But ReportConfig calls New-Report — so New-Report must appear before ReportConfig.

There is no single clean boundary between classes and functions anymore — they need to be interleaved in the output. That's exactly what PSScriptBuilder's Ordered Mode handles.

PSScriptBuilder Detects It Automatically

PSScriptBuilder analyzes the full dependency graph of your project and detects whether classes and functions need to be interleaved in the output. You can check this before building:

$contentCollector = New-PSScriptBuilderContentCollector |
    Add-PSScriptBuilderCollector -Type Class    -IncludePath "src/Classes"    |
    Add-PSScriptBuilderCollector -Type Function -IncludePath "src/Functions"

$analysis = Get-PSScriptBuilderDependencyAnalysis -ContentCollector $contentCollector

Write-Host "Has cross-dependencies: $($analysis.HasCrossDependencies)"
Enter fullscreen mode Exit fullscreen mode

Output:

Has cross-dependencies: True
Enter fullscreen mode Exit fullscreen mode

Free Mode, Ordered Mode, and Hybrid Mode

PSScriptBuilder selects a build mode based on the actual dependency structure of your project.

Free Mode applies when all enums, classes, and functions can be cleanly separated in the output — all enums first, then all classes in dependency order, then all functions. Each component type maps to its own placeholder in the template:

{{ENUM_DEFINITIONS}}

{{CLASS_DEFINITIONS}}

{{FUNCTION_DEFINITIONS}}
Enter fullscreen mode Exit fullscreen mode

Ordered Mode applies when cross-dependencies exist and classes and functions must be interleaved. A separate placeholder per component type is no longer sufficient — the output order cannot be determined until all dependencies are resolved globally. The template must use a single placeholder instead:

{{ORDERED_COMPONENTS}}
Enter fullscreen mode Exit fullscreen mode

PSScriptBuilder then outputs all enums, classes, and functions in a single topologically-sorted block in the correct order.

Hybrid Mode applies when the template already uses {{ORDERED_COMPONENTS}} but no cross-dependencies exist. This is an opt-in configuration — useful when you anticipate future cross-dependencies, or simply prefer a single unified component block. PSScriptBuilder handles Hybrid Mode and Ordered Mode identically.

Adapting the Template

When PSScriptBuilder detects cross-dependencies and the template still uses separate placeholders, the build fails with a clear error pointing to the required change.

The fix is straightforward — replace the separate placeholders with a single one:

# Before
{{ENUM_DEFINITIONS}}

{{CLASS_DEFINITIONS}}

{{FUNCTION_DEFINITIONS}}

# After
{{ORDERED_COMPONENTS}}
Enter fullscreen mode Exit fullscreen mode

PSScriptBuilder takes care of the rest. The output will contain all components in the correct interleaved order — automatically, on every build.

You can also check the detected mode before building:

$templateAnalysis = Get-PSScriptBuilderTemplateAnalysis `
    -ContentCollector $contentCollector `
    -TemplatePath     "build/Templates/MyScript.ps1.template"

Write-Host "Template mode: $($templateAnalysis.ValidationMode)"
Enter fullscreen mode Exit fullscreen mode

Output:

Template mode: Ordered
Enter fullscreen mode Exit fullscreen mode

No manual reordering, no fragile concatenation scripts — PSScriptBuilder resolves the interleaving and produces a correctly ordered output file on every run.

Whether your project has only a few components or over a hundred — like PSScriptBuilder itself — PSScriptBuilder figures out the correct structure and tells you immediately when the template needs to be adapted.

For the full reference, see the Templates Guide and the Dependency Analysis Guide.

Get Started

Install-Module -Name PSScriptBuilder
Enter fullscreen mode Exit fullscreen mode

New to PSScriptBuilder? Start here: Stop Manually Sorting PowerShell Class Files — PSScriptBuilder Does It For You


Have you run into cross-dependency issues in your PowerShell projects? I'd be curious to hear how you've been handling them — or whether PSScriptBuilder covers your use case.

Top comments (0)