PowerShell Nested Modules
A nested module is a module that loads inside another module. The outer module brings the inner module in with it, so one import loads both.
The manifest lists the inner module
The manifest names Inner.psm1 under NestedModules. Importing the outer module then loads the inner one too.
$modDir = Join-Path $PSScriptRoot "GreetingTools"
New-Item -ItemType Directory -Force -Path $modDir | Out-Null
Set-Content -Path (Join-Path $modDir "Inner.psm1") -Value 'function Get-FullName { param([string]$First, [string]$Last) "$First $Last" }'
Set-Content -Path (Join-Path $modDir "GreetingTools.psm1") -Value 'function Get-Greeting { param([string]$First, [string]$Last) "Hello, " + (Get-FullName -First $First -Last $Last) }'
Set-Content -Path (Join-Path $modDir "GreetingTools.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "GreetingTools.psm1"; NestedModules = @("Inner.psm1"); FunctionsToExport = @("Get-Greeting", "Get-FullName") }'
Import-Module (Join-Path $modDir "GreetingTools.psd1")
Get-Greeting -First "Ana" -Last "Patel"The inner function is also available directly
The parent exports the inner function as well. The reader can call it on its own after the import.
$modDir = Join-Path $PSScriptRoot "GreetingTools"
New-Item -ItemType Directory -Force -Path $modDir | Out-Null
Set-Content -Path (Join-Path $modDir "Inner.psm1") -Value 'function Get-FullName { param([string]$First, [string]$Last) "$First $Last" }'
Set-Content -Path (Join-Path $modDir "GreetingTools.psm1") -Value 'function Get-Greeting { param([string]$First, [string]$Last) "Hello, " + (Get-FullName -First $First -Last $Last) }'
Set-Content -Path (Join-Path $modDir "GreetingTools.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "GreetingTools.psm1"; NestedModules = @("Inner.psm1"); FunctionsToExport = @("Get-Greeting", "Get-FullName") }'
Import-Module (Join-Path $modDir "GreetingTools.psd1")
Get-FullName -First "Ana" -Last "Patel"The inner module stays inside the parent
The loaded list holds the outer module, not the inner one. The inner module still works, but it is not listed on its own.
$modDir = Join-Path $PSScriptRoot "GreetingTools"
New-Item -ItemType Directory -Force -Path $modDir | Out-Null
Set-Content -Path (Join-Path $modDir "Inner.psm1") -Value 'function Get-FullName { param([string]$First, [string]$Last) "$First $Last" }'
Set-Content -Path (Join-Path $modDir "GreetingTools.psm1") -Value 'function Get-Greeting { param([string]$First, [string]$Last) "Hello, " + (Get-FullName -First $First -Last $Last) }'
Set-Content -Path (Join-Path $modDir "GreetingTools.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "GreetingTools.psm1"; NestedModules = @("Inner.psm1"); FunctionsToExport = @("Get-Greeting", "Get-FullName") }'
Import-Module (Join-Path $modDir "GreetingTools.psd1")
$names = Get-Module | Select-Object -ExpandProperty Name
($names -contains "GreetingTools")
($names -contains "Inner")Example
$modDir = Join-Path $PSScriptRoot "GreetingTools"
New-Item -ItemType Directory -Force -Path $modDir | Out-Null
Set-Content -Path (Join-Path $modDir "Inner.psm1") -Value 'function Get-FullName { param([string]$First, [string]$Last) "$First $Last" }'
Set-Content -Path (Join-Path $modDir "GreetingTools.psm1") -Value 'function Get-Greeting { param([string]$First, [string]$Last) "Hello, " + (Get-FullName -First $First -Last $Last) }'
Set-Content -Path (Join-Path $modDir "GreetingTools.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "GreetingTools.psm1"; NestedModules = @("Inner.psm1"); FunctionsToExport = @("Get-Greeting", "Get-FullName") }'
Import-Module (Join-Path $modDir "GreetingTools.psd1")
Get-Greeting -First "Ana" -Last "Patel"
Get-FullName -First "Ana" -Last "Patel"Key points
- NestedModules: the manifest entry that lists modules loaded inside the parent.
- Use NestedModules to keep a helper module together with the module that uses it.
- FunctionsToExport: the manifest entry that names the functions a module makes available.
- A nested module function can be called by the outer module function.
- A nested module function can also be called directly once the parent is imported.
- Use Get-Module to list the modules loaded in the session.
In this example, the block builds an inner module and an outer module, then imports the outer module from its manifest. The greeting call runs the outer function, which calls the inner function for the full name. The last call runs the inner function directly.
Note
a nested module does not appear as its own entry in the loaded module list.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
Which manifest entry lists a module that loads inside the parent module?