🎓 A1Learner
🔍
0 of 46 lessons completed

PowerShell Module Dependencies

A module dependency is another module that a module needs in order to work. RequiredModules is the manifest entry that declares those modules, so they load before the parent does.

RequiredModules loads the needed module first

The parent manifest declares Greeter version 1.0.0. Importing the parent loads Greeter first, so the parent function can call it.

$modRoot = Join-Path $PSScriptRoot "Modules"
New-Item -ItemType Directory -Force -Path (Join-Path $modRoot "Greeter/1.0.0") | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $modRoot "Parent") | Out-Null
Set-Content -Path (Join-Path $modRoot "Greeter/1.0.0/Greeter.psm1") -Value 'function Get-Greeting { param([string]$Name) "Hello, $Name" }'
Set-Content -Path (Join-Path $modRoot "Greeter/1.0.0/Greeter.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "Greeter.psm1"; FunctionsToExport = @("Get-Greeting") }'
Set-Content -Path (Join-Path $modRoot "Parent/Parent.psm1") -Value 'function Get-ParentGreeting { param([string]$Name) Get-Greeting -Name $Name }'
Set-Content -Path (Join-Path $modRoot "Parent/Parent.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "Parent.psm1"; FunctionsToExport = @("Get-ParentGreeting"); RequiredModules = @(@{ ModuleName = "Greeter"; ModuleVersion = "1.0.0" }) }'
$env:PSModulePath = $modRoot + [IO.Path]::PathSeparator + $env:PSModulePath
Import-Module Parent
Get-ParentGreeting -Name "Ana"

ModuleVersion is a minimum, not an exact pin

Both Greeter 1.0.0 and 2.0.0 are present, and the parent declares ModuleVersion 1.0.0. The newer version loads, because 1.0.0 is only the minimum.

$modRoot = Join-Path $PSScriptRoot "Modules"
New-Item -ItemType Directory -Force -Path (Join-Path $modRoot "Greeter/1.0.0") | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $modRoot "Greeter/2.0.0") | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $modRoot "Parent") | Out-Null
Set-Content -Path (Join-Path $modRoot "Greeter/1.0.0/Greeter.psm1") -Value 'function Get-Greeting { param([string]$Name) "Hello, $Name" }'
Set-Content -Path (Join-Path $modRoot "Greeter/1.0.0/Greeter.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "Greeter.psm1"; FunctionsToExport = @("Get-Greeting") }'
Set-Content -Path (Join-Path $modRoot "Greeter/2.0.0/Greeter.psm1") -Value 'function Get-Greeting { param([string]$Name) "Hi, $Name" }'
Set-Content -Path (Join-Path $modRoot "Greeter/2.0.0/Greeter.psd1") -Value '@{ ModuleVersion = "2.0.0"; RootModule = "Greeter.psm1"; FunctionsToExport = @("Get-Greeting") }'
Set-Content -Path (Join-Path $modRoot "Parent/Parent.psm1") -Value 'function Get-ParentGreeting { param([string]$Name) Get-Greeting -Name $Name }'
Set-Content -Path (Join-Path $modRoot "Parent/Parent.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "Parent.psm1"; FunctionsToExport = @("Get-ParentGreeting"); RequiredModules = @(@{ ModuleName = "Greeter"; ModuleVersion = "1.0.0" }) }'
$env:PSModulePath = $modRoot + [IO.Path]::PathSeparator + $env:PSModulePath
Import-Module Parent
Get-ParentGreeting -Name "Ana"
(Get-Module Greeter).Version.ToString()

Both modules appear in the loaded list

After the import, the loaded list holds the parent and the needed module. The two names, sorted, prove both loaded.

$modRoot = Join-Path $PSScriptRoot "Modules"
New-Item -ItemType Directory -Force -Path (Join-Path $modRoot "Greeter/1.0.0") | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $modRoot "Parent") | Out-Null
Set-Content -Path (Join-Path $modRoot "Greeter/1.0.0/Greeter.psm1") -Value 'function Get-Greeting { param([string]$Name) "Hello, $Name" }'
Set-Content -Path (Join-Path $modRoot "Greeter/1.0.0/Greeter.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "Greeter.psm1"; FunctionsToExport = @("Get-Greeting") }'
Set-Content -Path (Join-Path $modRoot "Parent/Parent.psm1") -Value 'function Get-ParentGreeting { param([string]$Name) Get-Greeting -Name $Name }'
Set-Content -Path (Join-Path $modRoot "Parent/Parent.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "Parent.psm1"; FunctionsToExport = @("Get-ParentGreeting"); RequiredModules = @(@{ ModuleName = "Greeter"; ModuleVersion = "1.0.0" }) }'
$env:PSModulePath = $modRoot + [IO.Path]::PathSeparator + $env:PSModulePath
Import-Module Parent
(Get-Module -Name Parent, Greeter | Sort-Object Name | Select-Object -ExpandProperty Name) -join ", "

Example

$modRoot = Join-Path $PSScriptRoot "Modules"
New-Item -ItemType Directory -Force -Path (Join-Path $modRoot "Greeter/1.0.0") | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $modRoot "Greeter/2.0.0") | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $modRoot "Parent") | Out-Null
Set-Content -Path (Join-Path $modRoot "Greeter/1.0.0/Greeter.psm1") -Value 'function Get-Greeting { param([string]$Name) "Hello, $Name" }'
Set-Content -Path (Join-Path $modRoot "Greeter/1.0.0/Greeter.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "Greeter.psm1"; FunctionsToExport = @("Get-Greeting") }'
Set-Content -Path (Join-Path $modRoot "Greeter/2.0.0/Greeter.psm1") -Value 'function Get-Greeting { param([string]$Name) "Hi, $Name" }'
Set-Content -Path (Join-Path $modRoot "Greeter/2.0.0/Greeter.psd1") -Value '@{ ModuleVersion = "2.0.0"; RootModule = "Greeter.psm1"; FunctionsToExport = @("Get-Greeting") }'
Set-Content -Path (Join-Path $modRoot "Parent/Parent.psm1") -Value 'function Get-ParentGreeting { param([string]$Name) Get-Greeting -Name $Name }'
Set-Content -Path (Join-Path $modRoot "Parent/Parent.psd1") -Value '@{ ModuleVersion = "1.0.0"; RootModule = "Parent.psm1"; FunctionsToExport = @("Get-ParentGreeting"); RequiredModules = @(@{ ModuleName = "Greeter"; RequiredVersion = "1.0.0" }) }'
$env:PSModulePath = $modRoot + [IO.Path]::PathSeparator + $env:PSModulePath
Import-Module Parent
Get-ParentGreeting -Name "Ana"
(Get-Module Greeter).Version.ToString()

Key points

  • RequiredModules: the manifest entry that declares the modules a module needs.
  • ModuleVersion in RequiredModules is a minimum version, so a newer version can load instead.
  • RequiredVersion in RequiredModules pins one exact version.
  • A needed module must be findable through the module path when the parent is imported.
  • A needed module in a version folder needs its own manifest file in that folder.
  • Use Get-Module to confirm that both the parent and the needed module loaded.

In this example, the block builds both Greeter versions and a parent that pins 1.0.0 with RequiredVersion, then extends the module path and imports the parent. The greeting call proves the needed module loaded, and the version print proves the pinned version loaded, not the newer one.

Note

on this machine the module path is extended inside the block, so the local folders are found.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

A parent manifest declares Greeter 1.0.0 under RequiredModules. What happens when the parent is imported?