🎓 A1Learner
🔍
0 of 47 lessons completed

PowerShell Module Versioning

Module versioning is keeping two or more versions of one module side by side, so a script can load the exact version it needs. Each version lives in its own folder, and the newest version loads when no version is named.

Two folders hold two versions

Two version folders sit under one module folder. Listing the module shows both versions, oldest first.

$root = Join-Path $PSScriptRoot "GreetTool"
$v1 = Join-Path $root "1.0.0"
$v2 = Join-Path $root "2.0.0"
$null = New-Item -ItemType Directory -Path $v1, $v2 -Force
Set-Content -Path (Join-Path $v1 "GreetTool.psm1") -Value @'
function Get-Greeting { "Hello from version 1.0.0" }
Export-ModuleMember -Function Get-Greeting
'@
Set-Content -Path (Join-Path $v1 "GreetTool.psd1") -Value @'
@{
    RootModule = 'GreetTool.psm1'
    ModuleVersion = '1.0.0'
    GUID = '11111111-1111-1111-1111-111111111111'
}
'@
Set-Content -Path (Join-Path $v2 "GreetTool.psm1") -Value @'
function Get-Greeting { "Hello from version 2.0.0" }
Export-ModuleMember -Function Get-Greeting
'@
Set-Content -Path (Join-Path $v2 "GreetTool.psd1") -Value @'
@{
    RootModule = 'GreetTool.psm1'
    ModuleVersion = '2.0.0'
    GUID = '22222222-2222-2222-2222-222222222222'
}
'@
$env:PSModulePath = $PSScriptRoot + ":" + $env:PSModulePath
Get-Module -ListAvailable -Name GreetTool | Sort-Object Version | ForEach-Object { $_.Name + " " + $_.Version }

Load one exact version

The -RequiredVersion parameter names the exact version to load. Here version 1.0.0 loads, even though a newer version exists.

$root = Join-Path $PSScriptRoot "GreetTool"
$v1 = Join-Path $root "1.0.0"
$v2 = Join-Path $root "2.0.0"
$null = New-Item -ItemType Directory -Path $v1, $v2 -Force
Set-Content -Path (Join-Path $v1 "GreetTool.psm1") -Value @'
function Get-Greeting { "Hello from version 1.0.0" }
Export-ModuleMember -Function Get-Greeting
'@
Set-Content -Path (Join-Path $v1 "GreetTool.psd1") -Value @'
@{
    RootModule = 'GreetTool.psm1'
    ModuleVersion = '1.0.0'
    GUID = '11111111-1111-1111-1111-111111111111'
}
'@
Set-Content -Path (Join-Path $v2 "GreetTool.psm1") -Value @'
function Get-Greeting { "Hello from version 2.0.0" }
Export-ModuleMember -Function Get-Greeting
'@
Set-Content -Path (Join-Path $v2 "GreetTool.psd1") -Value @'
@{
    RootModule = 'GreetTool.psm1'
    ModuleVersion = '2.0.0'
    GUID = '22222222-2222-2222-2222-222222222222'
}
'@
$env:PSModulePath = $PSScriptRoot + ":" + $env:PSModulePath
Import-Module GreetTool -RequiredVersion 1.0.0
Get-Greeting

No version means the newest

Importing by name with no version loads the newest version found. Here that is version 2.0.0.

$root = Join-Path $PSScriptRoot "GreetTool"
$v1 = Join-Path $root "1.0.0"
$v2 = Join-Path $root "2.0.0"
$null = New-Item -ItemType Directory -Path $v1, $v2 -Force
Set-Content -Path (Join-Path $v1 "GreetTool.psm1") -Value @'
function Get-Greeting { "Hello from version 1.0.0" }
Export-ModuleMember -Function Get-Greeting
'@
Set-Content -Path (Join-Path $v1 "GreetTool.psd1") -Value @'
@{
    RootModule = 'GreetTool.psm1'
    ModuleVersion = '1.0.0'
    GUID = '11111111-1111-1111-1111-111111111111'
}
'@
Set-Content -Path (Join-Path $v2 "GreetTool.psm1") -Value @'
function Get-Greeting { "Hello from version 2.0.0" }
Export-ModuleMember -Function Get-Greeting
'@
Set-Content -Path (Join-Path $v2 "GreetTool.psd1") -Value @'
@{
    RootModule = 'GreetTool.psm1'
    ModuleVersion = '2.0.0'
    GUID = '22222222-2222-2222-2222-222222222222'
}
'@
$env:PSModulePath = $PSScriptRoot + ":" + $env:PSModulePath
Import-Module GreetTool
Get-Greeting

Example

$root = Join-Path $PSScriptRoot "GreetTool"
$v1 = Join-Path $root "1.0.0"
$v2 = Join-Path $root "2.0.0"
$null = New-Item -ItemType Directory -Path $v1, $v2 -Force
Set-Content -Path (Join-Path $v1 "GreetTool.psm1") -Value @'
function Get-Greeting { "Hello from version 1.0.0" }
Export-ModuleMember -Function Get-Greeting
'@
Set-Content -Path (Join-Path $v1 "GreetTool.psd1") -Value @'
@{
    RootModule = 'GreetTool.psm1'
    ModuleVersion = '1.0.0'
    GUID = '11111111-1111-1111-1111-111111111111'
}
'@
Set-Content -Path (Join-Path $v2 "GreetTool.psm1") -Value @'
function Get-Greeting { "Hello from version 2.0.0" }
Export-ModuleMember -Function Get-Greeting
'@
Set-Content -Path (Join-Path $v2 "GreetTool.psd1") -Value @'
@{
    RootModule = 'GreetTool.psm1'
    ModuleVersion = '2.0.0'
    GUID = '22222222-2222-2222-2222-222222222222'
}
'@
$env:PSModulePath = $PSScriptRoot + ":" + $env:PSModulePath
Get-Module -ListAvailable -Name GreetTool | Sort-Object Version | ForEach-Object { $_.Name + " " + $_.Version }
Import-Module GreetTool -RequiredVersion 2.0.0
Get-Greeting
(Get-Module GreetTool).Version.ToString()

Key points

  • Version folder: a folder named with a version number, such as 1.0.0, that holds one version of a module.
  • Side by side: two version folders under one module folder let both versions live on the same machine at once.
  • Manifest: each version folder needs its own manifest file, which names the version and the module file to load.
  • RequiredVersion: use Import-Module with -RequiredVersion to load one exact version instead of the newest.
  • Default choice: importing by name with no version loads the newest version found.

In this example, the script first builds both version folders and lists them, oldest first. It then imports exactly version 2.0.0, calls the greeting function, and prints the version of the loaded module.

Note

a version folder without its manifest file is ignored when PowerShell looks for the module.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

Which command loads exactly version 1.0.0 of GreetTool?