InvokeSystems: the grimoire, not the spells
InvokeSystems: Import Once, Use Everything
(or: why meta-modules are actually useful)
Every module collection eventually hits the same UX problem. You build four related modules. Each does something useful. Each is independently installable. Users need three of them at once.
Now they’re typing three separate Import-Module commands at the start of every script. Or worse, they’re copying the imports between scripts and occasionally forgetting one, leading to cryptic “command not found” errors halfway through execution.
The traditional answer is “create a manifest module that declares nested modules.” That works, but it couples everything together at installation time. You can’t install just one sub-module without pulling in the others. That’s fine for tightly-coupled suites, less fine for loosely-related tools.
The better pattern, borrowed from Microsoft.Graph and similar large module collections, is a meta-module. It’s an optional convenience module that imports all the sub-modules programmatically at load time. Sub-modules can still be used independently. The meta-module just makes “import everything” a one-liner.
InvokeSystems is that meta-module. Import it, get the whole suite. Import individual sub-modules if you only need specific functionality. Both work.
What It Actually Does
When you run Import-Module InvokeSystems, the module looks for its sibling directories, finds each InvokeSystems sub-module, and imports them into the global scope.
That’s the entire implementation. No magic, no complex dependency resolution. It’s a glorified foreach loop with error handling.
The module itself exports no functions. It exists purely as a loader. All the functionality comes from the sub-modules it imports: InvokeSystems.Common, InvokeSystems.Generator, InvokeSystems.RestrictedTask, and InvokeSystems.UpdateRepair.
Once loaded, all functions from all sub-modules are available in your session. New-InvPassword from Generator, New-RestrictedTask from RestrictedTask, Invoke-InvUpdateRepair from UpdateRepair. They all just work, as if you’d imported each module individually.
Why This Pattern Works
The key is that sub-modules remain independent. You can still do:
Import-Module InvokeSystems.RestrictedTask
That works without InvokeSystems. The meta-module is optional convenience, not required infrastructure.
This matters for a few reasons. Modules can have different update cadences. RestrictedTask might get a security patch while Generator is stable. Users can update just what they need without pulling in everything else.
Scripts can declare minimal dependencies. If a script only uses Generator, it should only import Generator. That makes dependencies explicit and prevents unnecessary coupling.
Testing and development stay isolated. You can work on one sub-module without loading the entire suite. That speeds up feedback loops and reduces unintended interactions.
The meta-module exists for interactive use and for scripts that genuinely need multiple sub-modules. It’s a shortcut, not a requirement.
How It Finds Sub-Modules
The loader walks the parent directory looking for sibling folders with matching manifest files. For each sub-module in the hardcoded list (Common, Generator, RestrictedTask, UpdateRepair), it constructs the expected path and imports the manifest if it exists.
If a sub-module is missing, import fails cleanly with a clear error. No silent fallbacks, no partial imports that leave you wondering which functions are available.
This approach relies on directory structure convention. All InvokeSystems modules live in sibling directories under a common parent. That structure is consistent across development environments, module installs from PSGallery, and manual deployments.
If the modules are installed in different locations (which shouldn’t happen with normal PowerShell module installation), the loader falls back to Import-Module by name, letting PowerShell’s module resolution handle it.
What This Isn’t
InvokeSystems doesn’t provide a unified configuration system. Each sub-module manages its own parameters, logging, and state. The meta-module doesn’t abstract that away.
It doesn’t version-lock sub-modules. You can have InvokeSystems 1.0.0 with RestrictedTask 1.2.0 and Generator 1.1.0. The meta-module doesn’t enforce matching versions. That’s deliberate: sub-modules are loosely coupled, and strict version alignment would create unnecessary dependency hell.
It doesn’t provide cross-module functionality. There’s no shared state, no inter-module communication layer, no orchestration. That’s intentional. Each sub-module is self-contained. If you need coordination between them, that happens in your scripts, not in the meta-module.
Why Not Just Use Nested Modules
PowerShell supports NestedModules in manifest files, which automatically imports specified modules when the parent loads. That’s simpler and doesn’t require custom loader code.
The problem is installation. With NestedModules, installing the parent module typically requires all nested modules to be present and resolvable at install time. That makes independent sub-module installation awkward.
The programmatic loader approach lets each sub-module be independently installable and updatable while still providing a convenient “import everything” option.
It’s a tradeoff. More code in the meta-module, more flexibility at installation and usage time.
The Design Philosophy
InvokeSystems as a suite isn’t trying to be a framework. Each sub-module solves a specific problem: shared utilities, random value generation, restricted task management, update remediation.
The meta-module reflects that philosophy. It doesn’t impose structure or create abstractions. It’s a convenience mechanism for users who want all the tools loaded at once.
The real functionality lives in the sub-modules. The meta-module is just the bookshelf.
Where This Fits
Use InvokeSystems when you’re working interactively and want quick access to the full toolkit. One import, everything available, no repeated typing.
Use individual sub-modules in production scripts where you want explicit, minimal dependencies. If a script only calls New-InvPassword, import only InvokeSystems.Generator.
Use the meta-module in your PowerShell profile if you frequently use multiple sub-modules and want them available in every session.
The pattern scales to larger collections. If the InvokeSystems suite grows to ten or fifteen sub-modules, the meta-module remains useful. The loader logic doesn’t get more complex, just the list of modules to import.
The Real Point
InvokeSystems doesn’t do anything technically interesting. It’s a loader. Loaders are boring.
But boring infrastructure that eliminates repetitive tasks has value. Not having to remember which sub-modules you need, not having to type multiple import statements, not having to copy-paste imports between scripts: those small frictions add up.
The meta-module removes that friction. That’s the entire justification for its existence.
Import once. Use everything. Move on to actual work.