From 73272905b538ce781edda438877815d83db22fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 15:59:10 +0200 Subject: [PATCH 001/117] Add `Describe` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index fddd7a12ea6..25d02bdc1db 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -280,6 +280,9 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { } } +Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { +} + Describe 'Get-Module -ListAvailable with path' -Tags "CI" { BeforeAll { $moduleName = 'Banana' From f542dbe7941d2176f72a12c4037df537e24c2184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 15:59:29 +0200 Subject: [PATCH 002/117] Add `BeforeAll` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 25d02bdc1db..b9b27dc9a68 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -281,6 +281,9 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { } Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { + BeforeAll { + $psModulePath = ($env:PSModulePath -split ';')[0] + } } Describe 'Get-Module -ListAvailable with path' -Tags "CI" { From b4f6c5c9e954684b45a03fd5bb24d3ed54ebf38f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 15:59:39 +0200 Subject: [PATCH 003/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index b9b27dc9a68..1242b0796fd 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -284,6 +284,13 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume BeforeAll { $psModulePath = ($env:PSModulePath -split ';')[0] } + + It 'wrongly returns module information instead of $null or error for missing script module' { + $path = [System.IO.Path]::GetFullPath("$pwd\missing.psm1") + Test-Path $path | Should -BeFalse + Get-Module -ListAvailable -FullyQualifiedName $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + Get-Module -ListAvailable -Name $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + } } Describe 'Get-Module -ListAvailable with path' -Tags "CI" { From a8390fe95601a7fe6440c8a8b4831bbd0925eaea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 15:59:47 +0200 Subject: [PATCH 004/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 1242b0796fd..20916d88d9f 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -291,6 +291,13 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume Get-Module -ListAvailable -FullyQualifiedName $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) Get-Module -ListAvailable -Name $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) } + + It 'wrongly returns module information instead of $null or error for missing script module under $env:PSModulePath' { + $path = [System.IO.Path]::GetFullPath("$psModulePath\missing.psm1") + Test-Path $path | Should -BeFalse + Get-Module -ListAvailable -FullyQualifiedName $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + Get-Module -ListAvailable -Name $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + } } Describe 'Get-Module -ListAvailable with path' -Tags "CI" { From 2eaf4399b1c6980e59f4a1e6d772e1f060af91de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 15:59:57 +0200 Subject: [PATCH 005/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 20916d88d9f..c9a23005b88 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -298,6 +298,13 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume Get-Module -ListAvailable -FullyQualifiedName $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) Get-Module -ListAvailable -Name $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) } + + It 'writes error for missing manifest module' { + $path = [System.IO.Path]::GetFullPath("$pwd\missing") + Test-Path $path | Should -BeFalse + { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + } } Describe 'Get-Module -ListAvailable with path' -Tags "CI" { From e946e4d1b0c68add4dd74476728ea615fe2e7ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 16:00:08 +0200 Subject: [PATCH 006/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index c9a23005b88..50ead6d9802 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -305,6 +305,13 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' } + + It 'writes error for missing manifest module under $env:PSModulePath' { + $path = [System.IO.Path]::GetFullPath("$psModulePath\missing") + Test-Path $path | Should -BeFalse + { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + } } Describe 'Get-Module -ListAvailable with path' -Tags "CI" { From 8448b34f0bdbc348f6c035b2cc16829b6f291ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 16:00:34 +0200 Subject: [PATCH 007/117] Add new `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 50ead6d9802..cf23cbb3887 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -312,6 +312,9 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' } + + Context 'Locating existing script module' { + } } Describe 'Get-Module -ListAvailable with path' -Tags "CI" { From 231af68a5c6f714024bc8d886e3882eada9eafd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 16:00:51 +0200 Subject: [PATCH 008/117] Add `BeforeAll` and `AfterAll` --- .../Get-Module.Tests.ps1 | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index cf23cbb3887..068f4b1f119 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -314,6 +314,24 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume } Context 'Locating existing script module' { + BeforeAll { + $psModulePath = ($env:PSModulePath -split ';')[0] + + # Script modules + # + # Under $env:PSModulePath. TODO: Is this a supported scenario? + $inPSModulePathLooseFilePath = Join-Path $psModulePath 'loose.psm1' + New-Item -ItemType File -Force $inPSModulePathLooseFilePath > $null + # + # Under $pwd + $inPSModulePathLooseFilePathPwd = Join-Path $pwd 'loose.psm1' + New-Item -ItemType File -Force $inPSModulePathLooseFilePathPwd > $null + } + + AfterAll { + Remove-Item $inPSModulePathLooseFilePath + Remove-Item $inPSModulePathLooseFilePathPwd + } } } From 6b75ee814cd1ec38701672d9a7b42285dd0b321c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 16:01:03 +0200 Subject: [PATCH 009/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 068f4b1f119..d69e11ddc54 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -332,6 +332,13 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume Remove-Item $inPSModulePathLooseFilePath Remove-Item $inPSModulePathLooseFilePathPwd } + + # TODO: This looks like a bug. + It 'wrongly writes error instead of returning module information for existing script module under $env:PSModulePath using basename' { + Test-Path "$psModulePath\loose.psm1" | Should -BeTrue + { Get-Module -ListAvailable -Name "$psModulePath\loose" -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + { Get-Module -ListAvailable -FullyQualifiedName "$psModulePath\loose" -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + } } } From 2b52fb6d8e9ce2f36f1f52e2e54a32cf3a3e9e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 16:01:15 +0200 Subject: [PATCH 010/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index d69e11ddc54..598db5a504b 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -339,6 +339,13 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume { Get-Module -ListAvailable -Name "$psModulePath\loose" -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' { Get-Module -ListAvailable -FullyQualifiedName "$psModulePath\loose" -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' } + + # TODO: This looks like a bug. + It 'wrongly writes error instead of returning module information for existing script module using basename' { + Test-Path "$pwd\loose.psm1" | Should -BeTrue + { Get-Module -ListAvailable -Name "$pwd\loose" -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + { Get-Module -ListAvailable -FullyQualifiedName "$pwd\loose" -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + } } } From 6258e72179508920a2f65f28c43b4a6d0b2266b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 10 Aug 2026 06:40:33 +0200 Subject: [PATCH 011/117] Review: Avoid Windows-only convention --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 598db5a504b..c5c0268af50 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -282,7 +282,7 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { BeforeAll { - $psModulePath = ($env:PSModulePath -split ';')[0] + $psModulePath = ($env:PSModulePath -split [System.IO.Path]::PathSeparator)[0] } It 'wrongly returns module information instead of $null or error for missing script module' { @@ -315,7 +315,7 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume Context 'Locating existing script module' { BeforeAll { - $psModulePath = ($env:PSModulePath -split ';')[0] + $psModulePath = ($env:PSModulePath -split [System.IO.Path]::PathSeparator)[0] # Script modules # From 95e9342c701ebbecdfaafade2b106927c4d7b0cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 10 Aug 2026 06:46:16 +0200 Subject: [PATCH 012/117] Review: Use `Join-Path` --- .../Get-Module.Tests.ps1 | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index c5c0268af50..ebb55897926 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -286,28 +286,28 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume } It 'wrongly returns module information instead of $null or error for missing script module' { - $path = [System.IO.Path]::GetFullPath("$pwd\missing.psm1") + $path = [System.IO.Path]::GetFullPath((Join-Path $pwd missing.psm1)) Test-Path $path | Should -BeFalse Get-Module -ListAvailable -FullyQualifiedName $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) Get-Module -ListAvailable -Name $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) } It 'wrongly returns module information instead of $null or error for missing script module under $env:PSModulePath' { - $path = [System.IO.Path]::GetFullPath("$psModulePath\missing.psm1") + $path = [System.IO.Path]::GetFullPath((Join-Path $psModulePath missing.psm1)) Test-Path $path | Should -BeFalse Get-Module -ListAvailable -FullyQualifiedName $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) Get-Module -ListAvailable -Name $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) } It 'writes error for missing manifest module' { - $path = [System.IO.Path]::GetFullPath("$pwd\missing") + $path = [System.IO.Path]::GetFullPath((Join-Path $pwd missing)) Test-Path $path | Should -BeFalse { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' } It 'writes error for missing manifest module under $env:PSModulePath' { - $path = [System.IO.Path]::GetFullPath("$psModulePath\missing") + $path = [System.IO.Path]::GetFullPath((Join-Path $psModulePath missing)) Test-Path $path | Should -BeFalse { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' @@ -335,16 +335,16 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume # TODO: This looks like a bug. It 'wrongly writes error instead of returning module information for existing script module under $env:PSModulePath using basename' { - Test-Path "$psModulePath\loose.psm1" | Should -BeTrue - { Get-Module -ListAvailable -Name "$psModulePath\loose" -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' - { Get-Module -ListAvailable -FullyQualifiedName "$psModulePath\loose" -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + Test-Path (Join-Path $psModulePath loose.psm1) | Should -BeTrue + { Get-Module -ListAvailable -Name (Join-Path $psModulePath loose) -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + { Get-Module -ListAvailable -FullyQualifiedName (Join-Path $psModulePath loose) -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' } # TODO: This looks like a bug. It 'wrongly writes error instead of returning module information for existing script module using basename' { - Test-Path "$pwd\loose.psm1" | Should -BeTrue - { Get-Module -ListAvailable -Name "$pwd\loose" -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' - { Get-Module -ListAvailable -FullyQualifiedName "$pwd\loose" -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + Test-Path (Join-Path $pwd loose.psm1) | Should -BeTrue + { Get-Module -ListAvailable -Name (Join-Path $pwd loose) -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + { Get-Module -ListAvailable -FullyQualifiedName (Join-Path $pwd loose) -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' } } } From 8dbc54d802b2facd1fa605fa47701601757f414b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 10 Aug 2026 07:09:11 +0200 Subject: [PATCH 013/117] Review: Fix `Should -Throw` tests --- .../Get-Module.Tests.ps1 | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index ebb55897926..a4a823554b5 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -302,15 +302,23 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume It 'writes error for missing manifest module' { $path = [System.IO.Path]::GetFullPath((Join-Path $pwd missing)) Test-Path $path | Should -BeFalse - { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' - { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + + $err = { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' + + $err = { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' } It 'writes error for missing manifest module under $env:PSModulePath' { $path = [System.IO.Path]::GetFullPath((Join-Path $psModulePath missing)) Test-Path $path | Should -BeFalse - { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' - { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + + $err = { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' + + $err = { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' } Context 'Locating existing script module' { @@ -336,15 +344,23 @@ Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argume # TODO: This looks like a bug. It 'wrongly writes error instead of returning module information for existing script module under $env:PSModulePath using basename' { Test-Path (Join-Path $psModulePath loose.psm1) | Should -BeTrue - { Get-Module -ListAvailable -Name (Join-Path $psModulePath loose) -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' - { Get-Module -ListAvailable -FullyQualifiedName (Join-Path $psModulePath loose) -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + + $err = { Get-Module -ListAvailable -Name (Join-Path $psModulePath loose) -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' + + $err = { Get-Module -ListAvailable -FullyQualifiedName (Join-Path $psModulePath loose) -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' } # TODO: This looks like a bug. It 'wrongly writes error instead of returning module information for existing script module using basename' { Test-Path (Join-Path $pwd loose.psm1) | Should -BeTrue - { Get-Module -ListAvailable -Name (Join-Path $pwd loose) -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' - { Get-Module -ListAvailable -FullyQualifiedName (Join-Path $pwd loose) -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + + $err = { Get-Module -ListAvailable -Name (Join-Path $pwd loose) -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' + + $err = { Get-Module -ListAvailable -FullyQualifiedName (Join-Path $pwd loose) -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' } } } From bb7d1db6d305e4b5c76adc2e8922d6ac08f867ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 10 Aug 2026 07:10:23 +0200 Subject: [PATCH 014/117] Review: Typo --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index a4a823554b5..5211077b96b 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -280,7 +280,7 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { } } -Describe 'Get-Module -ListAvaiable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { +Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { BeforeAll { $psModulePath = ($env:PSModulePath -split [System.IO.Path]::PathSeparator)[0] } From 0b6503e61fef5d604bc6e0acb547c62438941c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 10 Aug 2026 07:15:09 +0200 Subject: [PATCH 015/117] Review: Use dedicated $env:PSModulePath for tests --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 5211077b96b..05c0b615702 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -282,7 +282,13 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { BeforeAll { - $psModulePath = ($env:PSModulePath -split [System.IO.Path]::PathSeparator)[0] + $oldPSModulePath = $env:PSModulePath + $psModulePath = New-Item -ItemType Directory (Join-Path $TestDrive modules) + $env:PSModulePath = $psModulePath + } + + AfterAll { + $env:PSModulePath = $oldPSModulePath } It 'wrongly returns module information instead of $null or error for missing script module' { From c6d6a31faf4ce0814ddf64d71f8bd29318dedf4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 10 Aug 2026 07:18:33 +0200 Subject: [PATCH 016/117] Refactor --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 05c0b615702..2017872ba16 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -329,7 +329,7 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Context 'Locating existing script module' { BeforeAll { - $psModulePath = ($env:PSModulePath -split [System.IO.Path]::PathSeparator)[0] + $psModulePath = $env:PSModulePath # Script modules # From 45075a96eb1496d6af5401fb57e06f7777a24a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 10 Aug 2026 21:58:49 +0200 Subject: [PATCH 017/117] Fix name --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 2017872ba16..5ff8e078008 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -338,13 +338,13 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum New-Item -ItemType File -Force $inPSModulePathLooseFilePath > $null # # Under $pwd - $inPSModulePathLooseFilePathPwd = Join-Path $pwd 'loose.psm1' - New-Item -ItemType File -Force $inPSModulePathLooseFilePathPwd > $null + $inCwdLooseFilePath = Join-Path $pwd 'loose.psm1' + New-Item -ItemType File -Force $inCwdLooseFilePath > $null } AfterAll { Remove-Item $inPSModulePathLooseFilePath - Remove-Item $inPSModulePathLooseFilePathPwd + Remove-Item $inCwdLooseFilePath } # TODO: This looks like a bug. From 0f4e5fbeefabb75e04240c5981b8637802e99f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:05:59 +0200 Subject: [PATCH 018/117] Refactor: Use single variable for the same data --- .../Get-Module.Tests.ps1 | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 5ff8e078008..18aea8ccc16 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -283,8 +283,7 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { BeforeAll { $oldPSModulePath = $env:PSModulePath - $psModulePath = New-Item -ItemType Directory (Join-Path $TestDrive modules) - $env:PSModulePath = $psModulePath + $env:PSModulePath = New-Item -ItemType Directory (Join-Path $TestDrive modules) } AfterAll { @@ -299,7 +298,7 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } It 'wrongly returns module information instead of $null or error for missing script module under $env:PSModulePath' { - $path = [System.IO.Path]::GetFullPath((Join-Path $psModulePath missing.psm1)) + $path = [System.IO.Path]::GetFullPath((Join-Path $env:PSModulePath missing.psm1)) Test-Path $path | Should -BeFalse Get-Module -ListAvailable -FullyQualifiedName $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) Get-Module -ListAvailable -Name $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) @@ -317,7 +316,7 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } It 'writes error for missing manifest module under $env:PSModulePath' { - $path = [System.IO.Path]::GetFullPath((Join-Path $psModulePath missing)) + $path = [System.IO.Path]::GetFullPath((Join-Path $env:PSModulePath missing)) Test-Path $path | Should -BeFalse $err = { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -PassThru @@ -329,12 +328,12 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Context 'Locating existing script module' { BeforeAll { - $psModulePath = $env:PSModulePath + $env:PSModulePath = $env:PSModulePath # Script modules # # Under $env:PSModulePath. TODO: Is this a supported scenario? - $inPSModulePathLooseFilePath = Join-Path $psModulePath 'loose.psm1' + $inPSModulePathLooseFilePath = Join-Path $env:PSModulePath 'loose.psm1' New-Item -ItemType File -Force $inPSModulePathLooseFilePath > $null # # Under $pwd @@ -349,12 +348,12 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum # TODO: This looks like a bug. It 'wrongly writes error instead of returning module information for existing script module under $env:PSModulePath using basename' { - Test-Path (Join-Path $psModulePath loose.psm1) | Should -BeTrue + Test-Path (Join-Path $env:PSModulePath loose.psm1) | Should -BeTrue - $err = { Get-Module -ListAvailable -Name (Join-Path $psModulePath loose) -ErrorAction Stop } | Should -Throw -PassThru + $err = { Get-Module -ListAvailable -Name (Join-Path $env:PSModulePath loose) -ErrorAction Stop } | Should -Throw -PassThru $err.Exception.Message | Should -BeLike '*Update the Name parameter*' - $err = { Get-Module -ListAvailable -FullyQualifiedName (Join-Path $psModulePath loose) -ErrorAction Stop } | Should -Throw -PassThru + $err = { Get-Module -ListAvailable -FullyQualifiedName (Join-Path $env:PSModulePath loose) -ErrorAction Stop } | Should -Throw -PassThru $err.Exception.Message | Should -BeLike '*Update the Name parameter*' } From c56d882160b3819cbb704da71bef9b65798e9c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:06:24 +0200 Subject: [PATCH 019/117] Consistent formatting --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 18aea8ccc16..0e519f43d64 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -293,6 +293,7 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum It 'wrongly returns module information instead of $null or error for missing script module' { $path = [System.IO.Path]::GetFullPath((Join-Path $pwd missing.psm1)) Test-Path $path | Should -BeFalse + Get-Module -ListAvailable -FullyQualifiedName $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) Get-Module -ListAvailable -Name $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) } @@ -300,6 +301,7 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum It 'wrongly returns module information instead of $null or error for missing script module under $env:PSModulePath' { $path = [System.IO.Path]::GetFullPath((Join-Path $env:PSModulePath missing.psm1)) Test-Path $path | Should -BeFalse + Get-Module -ListAvailable -FullyQualifiedName $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) Get-Module -ListAvailable -Name $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) } From 8a0a003db3c3eda8e20a0cd1d227267e09b2d510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:09:07 +0200 Subject: [PATCH 020/117] Refactor: Consolidate variables --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 0e519f43d64..23947810929 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -351,22 +351,24 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum # TODO: This looks like a bug. It 'wrongly writes error instead of returning module information for existing script module under $env:PSModulePath using basename' { Test-Path (Join-Path $env:PSModulePath loose.psm1) | Should -BeTrue + $path = Join-Path $env:PSModulePath loose - $err = { Get-Module -ListAvailable -Name (Join-Path $env:PSModulePath loose) -ErrorAction Stop } | Should -Throw -PassThru + $err = { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -PassThru $err.Exception.Message | Should -BeLike '*Update the Name parameter*' - $err = { Get-Module -ListAvailable -FullyQualifiedName (Join-Path $env:PSModulePath loose) -ErrorAction Stop } | Should -Throw -PassThru + $err = { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -PassThru $err.Exception.Message | Should -BeLike '*Update the Name parameter*' } # TODO: This looks like a bug. It 'wrongly writes error instead of returning module information for existing script module using basename' { Test-Path (Join-Path $pwd loose.psm1) | Should -BeTrue + $path = Join-Path $pwd loose - $err = { Get-Module -ListAvailable -Name (Join-Path $pwd loose) -ErrorAction Stop } | Should -Throw -PassThru + $err = { Get-Module -ListAvailable -Name $path -ErrorAction Stop } | Should -Throw -PassThru $err.Exception.Message | Should -BeLike '*Update the Name parameter*' - $err = { Get-Module -ListAvailable -FullyQualifiedName (Join-Path $pwd loose) -ErrorAction Stop } | Should -Throw -PassThru + $err = { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -PassThru $err.Exception.Message | Should -BeLike '*Update the Name parameter*' } } From c2bf6cff4d382e8b50fcf2e6a07e8100e4587020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:40:58 +0200 Subject: [PATCH 021/117] Cleanup --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 23947810929..17bc6e2526a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -330,8 +330,6 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Context 'Locating existing script module' { BeforeAll { - $env:PSModulePath = $env:PSModulePath - # Script modules # # Under $env:PSModulePath. TODO: Is this a supported scenario? From 7dd54977b4a0fa611d17260b3b8142a99ba2a98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:42:39 +0200 Subject: [PATCH 022/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 17bc6e2526a..9f4daa703fd 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -369,6 +369,19 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $err = { Get-Module -ListAvailable -FullyQualifiedName $path -ErrorAction Stop } | Should -Throw -PassThru $err.Exception.Message | Should -BeLike '*Update the Name parameter*' } + + It 'returns module information for existing script module using file name' { + $path = Join-Path $pwd loose.psm1 + Test-Path $path | Should -BeTrue + + $actual = Get-Module -ListAvailable -Name $path + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly $path + + $actual = Get-Module -ListAvailable -FullyQualifiedName $path + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly $path + } } } From 92c622fd5f0816b46d51ba05bb1c3ca4ee66fda5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:43:09 +0200 Subject: [PATCH 023/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 9f4daa703fd..ee2566e287a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -382,6 +382,19 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual | Should -HaveCount 1 $actual[0].Path | Should -BeExactly $path } + + It 'returns module information for existing script module under $env:PSModulePath using file name' { + $path = Join-Path $env:PSModulePath loose.psm1 + Test-Path $path | Should -BeTrue + + $actual = Get-Module -ListAvailable -Name $path + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly $path + + $actual = Get-Module -ListAvailable -FullyQualifiedName $path + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly $path + } } } From 4087b48801de1bf9b4350ecd2e9d34f4ce8a8bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:43:26 +0200 Subject: [PATCH 024/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index ee2566e287a..535ef997cea 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -396,6 +396,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual[0].Path | Should -BeExactly $path } } + + Context 'When argument contains wildcards' { + } } Describe 'Get-Module -ListAvailable with path' -Tags "CI" { From 3dbf91e4a324f036a17e9675e64c5cdfd3e631d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:43:43 +0200 Subject: [PATCH 025/117] Add `BeforeAll` and `AfterAll` --- .../Get-Module.Tests.ps1 | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 535ef997cea..7e637e01f3f 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -398,6 +398,61 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'When argument contains wildcards' { + BeforeAll { + # Manifest modules under $env:PSModulePath + # + # Versioned, manifest + $inPSModulePathWithManifestFileName = 'existing' + $inPSModulePatWithManifestDirectory = Join-Path $env:PSModulePath $inPSModulePathWithManifestFileName '0.0.1' + $inPSModulePathWithManifestFilePath = Join-Path $inPSModulePatWithManifestDirectory "$inPSModulePathWithManifestFileName.psm1" + New-Item -ItemType File -Force $inPSModulePathWithManifestFilePath > $null + New-ModuleManifest -Path (Join-Path $inPSModulePatWithManifestDirectory "$inPSModulePathWithManifestFileName.psd1") + # + # Versioned, manifest + $inPSModulePathWithManifestFileName2 = 'existing2' + $inPSModulePatWithManifestDirectory2 = Join-Path $env:PSModulePath $inPSModulePathWithManifestFileName2 '0.0.1' + $inPSModulePathWithManifestFilePath2 = Join-Path $inPSModulePatWithManifestDirectory2 "$inPSModulePathWithManifestFileName2.psm1" + New-Item -ItemType File -Force $inPSModulePathWithManifestFilePath2 > $null + New-ModuleManifest -Path (Join-Path $inPSModulePatWithManifestDirectory2 "$inPSModulePathWithManifestFileName2.psd1") + + # Manifest modules under $pwd + # + # Versioned, manifest + $inCwdhWithManifestFileName = 'existing' + $inCwdWithManifestDirectory = Join-Path $pwd $inCwdhWithManifestFileName '0.0.1' + $inCwdWithManifestFilePath = Join-Path $inCwdWithManifestDirectory "$inCwdhWithManifestFileName.psm1" + New-Item -ItemType File -Force $inCwdWithManifestFilePath > $null + New-ModuleManifest -Path (Join-Path $inCwdWithManifestDirectory "$inCwdhWithManifestFileName.psd1") + # + # Versioned, manifest + $inCwdWithManifestFileName2 = 'existing2' + $inCwdWithManifestDirectory2 = Join-Path $pwd $inCwdWithManifestFileName2 '0.0.1' + $inCwdWithManifestFilePath2 = Join-Path $inCwdWithManifestDirectory2 "$inCwdWithManifestFileName2.psm1" + New-Item -ItemType File -Force $inCwdWithManifestFilePath2 > $null + New-ModuleManifest -Path (Join-Path $inCwdWithManifestDirectory2 "$inCwdWithManifestFileName2.psd1") + + # Script modules + # + # Under $env:PSModulePath. TODO: Is this a supported scenario? + $inPSModulePathLooseFilePath = Join-Path $env:PSModulePath 'loose.psm1' + New-Item -ItemType File -Force $inPSModulePathLooseFilePath > $null + # + # + # Under $pwd + $inCwdFilePath = Join-Path $pwd 'loose.psm1' + New-Item -ItemType File -Force $inCwdFilePath > $null + } + + AfterAll { + Remove-Item -Force -Recurse $inPSModulePatWithManifestDirectory + Remove-Item -Force -Recurse $inPSModulePatWithManifestDirectory2 + + Remove-Item -Force -Recurse $inCwdWithManifestDirectory + Remove-Item -Force -Recurse $inCwdWithManifestDirectory2 + + Remove-Item $inPSModulePathLooseFilePath + Remove-Item $inCwdFilePath + } } } From dbf05874b590a66837817808a7d52500a0e8cc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:43:49 +0200 Subject: [PATCH 026/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 7e637e01f3f..9f2fe400f39 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -453,6 +453,18 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Remove-Item $inPSModulePathLooseFilePath Remove-Item $inCwdFilePath } + + It 'returns existing manifest modules under $env:PSModulePath when using the -Name parameter' { + $moduleManifestPath1 = Join-Path $env:PSModulePath existing 0.0.1,existing.psd1 + $moduleManifestPath2 = Join-Path $env:PSModulePath existing2 0.0.1,existing2.psd1 + Test-Path $moduleManifestPath1 | Should -BeTrue + Test-Path $moduleManifestPath2 | Should -BeTrue + + $actual = Get-Module -ListAvailable -Name (Join-Path $env:PSModulePath 'existing*') + $actual | Should -HaveCount 2 + $actual[0].Path | Should -BeExactly $moduleManifestPath1 + $actual[1].Path | Should -BeExactly $moduleManifestPath2 + } } } From 592a4a116c76815bac687837662b8b3735d3e891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:43:56 +0200 Subject: [PATCH 027/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 9f2fe400f39..c7046e2c4e2 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -465,6 +465,12 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual[0].Path | Should -BeExactly $moduleManifestPath1 $actual[1].Path | Should -BeExactly $moduleManifestPath2 } + + # TODO: This looks like a bug. + It 'wrongly returns $null for existing manifest modules under $env:PSModulePath when using the -FullyQualifiedName parameter' { + $actual = Get-Module -ListAvailable -FullyQualifiedName (Join-Path $env:PSModulePath 'existing*') + $actual | Should -Be $null + } } } From 11edc827f8428f8b184de74df7f0dfaf4fea70f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:44:01 +0200 Subject: [PATCH 028/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index c7046e2c4e2..9256b428c5d 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -471,6 +471,18 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual = Get-Module -ListAvailable -FullyQualifiedName (Join-Path $env:PSModulePath 'existing*') $actual | Should -Be $null } + + It 'returns existing manifest modules when using the -Name parameter' { + $moduleManifestPath1 = Join-Path $pwd existing 0.0.1,existing.psd1 + $moduleManifestPath2 = Join-Path $pwd existing2 0.0.1,existing2.psd1 + Test-Path $moduleManifestPath1 | Should -BeTrue + Test-Path $moduleManifestPath2 | Should -BeTrue + + $actual = Get-Module -ListAvailable -Name (Join-Path $pwd 'existing*') + $actual | Should -HaveCount 2 + $actual[0].Path | Should -BeExactly $moduleManifestPath1 + $actual[1].Path | Should -BeExactly $moduleManifestPath2 + } } } From 8e822c668d833665cd17fd620ff36c72b331a051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:44:08 +0200 Subject: [PATCH 029/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 9256b428c5d..010ab76e0a5 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -483,6 +483,12 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual[0].Path | Should -BeExactly $moduleManifestPath1 $actual[1].Path | Should -BeExactly $moduleManifestPath2 } + + # TODO: This looks like a bug. + It 'wrongly returns $null for existing manifest modules when using the -FullyQualifiedName parameter' { + $actual = Get-Module -ListAvailable -FullyQualifiedName (Join-Path $pwd 'existing*') + $actual | Should -Be $null + } } } From f385bcddc0b988819085c7af01da539ece39bc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:44:13 +0200 Subject: [PATCH 030/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 010ab76e0a5..fb3be7ed048 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -489,6 +489,12 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual = Get-Module -ListAvailable -FullyQualifiedName (Join-Path $pwd 'existing*') $actual | Should -Be $null } + + It 'returns module information for existing script module under $env:PSModulePath' { + $actual = Get-Module -ListAvailable -Name (Join-Path $env:PSModulePath 'loose*') + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly (Join-Path $env:PSModulePath loose.psm1) + } } } From 5154898d2372d771e6147591adfb7738e9d30404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 07:44:18 +0200 Subject: [PATCH 031/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index fb3be7ed048..72e5dd45812 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -495,6 +495,19 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual | Should -HaveCount 1 $actual[0].Path | Should -BeExactly (Join-Path $env:PSModulePath loose.psm1) } + + It 'returns module information for existing script module using file name' { + $path = Join-Path $pwd loose.psm1 + Test-Path $path | Should -BeTrue + + $actual = Get-Module -ListAvailable -Name $path + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly $path + + $actual = Get-Module -ListAvailable -FullyQualifiedName $path + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly $path + } } } From 8afb65f9403dcb574ec2959f903d1b0c9dc49c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 17:22:23 +0200 Subject: [PATCH 032/117] Add `Describe` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 72e5dd45812..ad47a283c70 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -280,6 +280,9 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { } } +Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is relative-rooted' -Tags "CI" { +} + Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { BeforeAll { $oldPSModulePath = $env:PSModulePath From 0d362fe0b60059049e427432b9dfe8c047676494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 17:22:34 +0200 Subject: [PATCH 033/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index ad47a283c70..9bce7ba983e 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -281,6 +281,17 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is relative-rooted' -Tags "CI" { + It 'wrongly returns module information instead of $null or error for missing script module' { + $path1 = Join-Path . missing.psm1 + $path2 = Join-Path .. missing.psm1 + Test-Path $path1 | Should -BeFalse + Test-Path $path2 | Should -BeFalse + + Get-Module -ListAvailable -Name $path1 | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + Get-Module -ListAvailable -Name $path2 | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + Get-Module -ListAvailable -FullyQualifiedName $path1 | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + Get-Module -ListAvailable -FullyQualifiedName $path2 | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { From 5d8168cc78ac0ec79c138249c6dfa29bc5ce5372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 17:22:44 +0200 Subject: [PATCH 034/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 9bce7ba983e..0edab2a6891 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -292,6 +292,18 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Get-Module -ListAvailable -FullyQualifiedName $path1 | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) Get-Module -ListAvailable -FullyQualifiedName $path2 | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) } + + It 'writes error for missing manifest module' { + $path1 = Join-Path . missing + $path2 = Join-Path .. missing + Test-Path $path1 | Should -BeFalse + Test-Path $path2 | Should -BeFalse + + { Get-Module -ListAvailable -Name $path1 -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + { Get-Module -ListAvailable -Name $path2 -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + { Get-Module -ListAvailable -FullyQualifiedName $path1 -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + { Get-Module -ListAvailable -FullyQualifiedName $path2 -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { From 52ec5a068d2f94d77cf8d24991a78bdd059f193c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 17:23:10 +0200 Subject: [PATCH 035/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 0edab2a6891..d3a8e5845b4 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -304,6 +304,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum { Get-Module -ListAvailable -FullyQualifiedName $path1 -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' { Get-Module -ListAvailable -FullyQualifiedName $path2 -ErrorAction Stop } | Should -Throw -Because '*Update the Name parameter*' } + + Context 'Locating existing script module' { + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { From f28cb52e623a7f0c6d614b7ce982b97f35e47224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 17:23:22 +0200 Subject: [PATCH 036/117] Add `BeforeAll` and `AfterAll` --- .../Get-Module.Tests.ps1 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index d3a8e5845b4..08389490311 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -306,6 +306,22 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'Locating existing script module' { + BeforeAll { + # Script modules + # + # Under $env:PSModulePath. TODO: Is this a supported scenario? + $inPSModulePathLooseFilePath = Join-Path . loose.psm1 + New-Item -ItemType File -Force $inPSModulePathLooseFilePath > $null + # + # Under $pwd + $inPSModulePathLooseFilePathParent = Join-Path .. loose.psm1 + New-Item -ItemType File -Force $inPSModulePathLooseFilePathParent > $null + } + + AfterAll { + Remove-Item $inPSModulePathLooseFilePath + Remove-Item $inPSModulePathLooseFilePathParent + } } } From ff1c480019292b5af500ca180a798923474bc7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 17:23:29 +0200 Subject: [PATCH 037/117] Add test --- .../Get-Module.Tests.ps1 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 08389490311..90e528363e8 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -322,6 +322,23 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Remove-Item $inPSModulePathLooseFilePath Remove-Item $inPSModulePathLooseFilePathParent } + + # TODO: This looks like a bug. + It 'wrongly writes error instead of returning module information for existing script module using basename' { + $path1 = Join-Path . loose.psm1 + $path2 = Join-Path .. loose.psm1 + Test-Path $path1 | Should -BeTrue + Test-Path $path2 | Should -BeTrue + + $name1 = Join-Path . loose + $name2 = Join-Path .. loose + + $err = { Get-Module -ListAvailable -Name $name1 -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' + + $err = { Get-Module -ListAvailable -Name $name2 -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' + } } } From 9620dac3deb55089e8b67dde924717962e9fd322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 17:23:37 +0200 Subject: [PATCH 038/117] Add test --- .../Get-Module.Tests.ps1 | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 90e528363e8..fba9c99d0d6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -339,6 +339,29 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $err = { Get-Module -ListAvailable -Name $name2 -ErrorAction Stop } | Should -Throw -PassThru $err.Exception.Message | Should -BeLike '*Update the Name parameter*' } + + It 'returns module information for existing script module using file name' { + $name1 = Join-Path . loose.psm1 + $name2 = Join-Path .. loose.psm1 + Test-Path $name1 | Should -BeTrue + Test-Path $name2 | Should -BeTrue + + $actual = Get-Module -ListAvailable -Name $name1 + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly ([System.IO.Path]::GetFullPath($name1)) + + $actual = Get-Module -ListAvailable -Name $name2 + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly ([System.IO.Path]::GetFullPath($name2)) + + $actual = Get-Module -ListAvailable -FullyQualifiedName $name1 + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly ([System.IO.Path]::GetFullPath($name1)) + + $actual = Get-Module -ListAvailable -FullyQualifiedName $name2 + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly ([System.IO.Path]::GetFullPath($name2)) + } } } From 3a3837bdbce49e12838c05a4996965041794deec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 20:27:47 +0200 Subject: [PATCH 039/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index fba9c99d0d6..1e864900a9e 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -363,6 +363,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual[0].Path | Should -BeExactly ([System.IO.Path]::GetFullPath($name2)) } } + + Context 'When argument contains wildcards' { + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is absolute path' -Tags "CI" { From f06e705166d5b5fb9471e532adb79e31bc9698de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 17:29:33 +0200 Subject: [PATCH 040/117] Add `BeforeAll` and `AfterAll` --- .../Get-Module.Tests.ps1 | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 1e864900a9e..e82143c2554 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -365,6 +365,59 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'When argument contains wildcards' { + BeforeAll { + # Manifest modules under '.' + # + # Versioned, manifest + $inCwdWithManifestFileName = 'existing' + $inCwdWithManifestDirectory = Join-Path '.' $inCwdWithManifestFileName '0.0.1' + $inCwdWithManifestFilePath = Join-Path $inCwdWithManifestDirectory "$inCwdWithManifestFileName.psm1" + New-Item -ItemType File -Force $inCwdWithManifestFilePath > $null + New-ModuleManifest -Path (Join-Path $inCwdWithManifestDirectory "$inCwdWithManifestFileName.psd1") + # + # Versioned, manifest + $inCwdWithManifestFileName2 = 'existing2' + $inCwdWithManifestDirectory2 = Join-Path '.' $inCwdWithManifestFileName2 '0.0.1' + $inCwdWithManifestFilePath2 = Join-Path $inCwdWithManifestDirectory2 "$inCwdWithManifestFileName2.psm1" + New-Item -ItemType File -Force $inCwdWithManifestFilePath2 > $null + New-ModuleManifest -Path (Join-Path $inCwdWithManifestDirectory2 "$inCwdWithManifestFileName2.psd1") + + # Manifest modules under '..' + # + # Versioned, manifest + $inParentWithManifestFileName = 'existing' + $inParentWithManifestDirectory = Join-Path '..' $inParentWithManifestFileName '0.0.1' + $inParentWithManifestFilePath = Join-Path $inParentWithManifestDirectory "$inParentWithManifestFileName.psm1" + New-Item -ItemType File -Force $inParentWithManifestFilePath > $null + New-ModuleManifest -Path (Join-Path $inParentWithManifestDirectory "$inParentWithManifestFileName.psd1") + # + # Versioned, manifest + $inParentWithManifestFileName2 = 'existing2' + $inParentWithManifestDirectory2 = Join-Path '..' $inParentWithManifestFileName2 '0.0.1' + $inParentWithManifestFilePath2 = Join-Path $inParentWithManifestDirectory2 "$inParentWithManifestFileName2.psm1" + New-Item -ItemType File -Force $inParentWithManifestFilePath2 > $null + New-ModuleManifest -Path (Join-Path $inParentWithManifestDirectory2 "$inParentWithManifestFileName2.psd1") + + # Script modules under '.' and '..' + # + # Under '.' + $inCwdLooseFilePath = Join-Path '.' 'loose.psm1' + New-Item -ItemType File -Force $inCwdLooseFilePath > $null + # + # Under '..' + $inParentLooseFilePath = Join-Path '..' 'loose.psm1' + New-Item -ItemType File -Force $inParentLooseFilePath > $null + } + + AfterAll { + Remove-Item -Force -Recurse $inCwdWithManifestDirectory + Remove-Item -Force -Recurse $inCwdWithManifestDirectory2 + + Remove-Item -Force -Recurse $inParentWithManifestDirectory + Remove-Item -Force -Recurse $inParentWithManifestDirectory2 + + Remove-Item $inCwdLooseFilePath + } } } From 6d932612adaa8b723aed6121e7917986767339ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 17:29:39 +0200 Subject: [PATCH 041/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index e82143c2554..b51a94abb5a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -418,6 +418,18 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Remove-Item $inCwdLooseFilePath } + + It 'returns existing manifest modules when using the -Name parameter' { + $actual = Get-Module -ListAvailable -Name '.\existing*' + $actual | Should -HaveCount 2 + $actual[0].Path | Should -BeExactly ([System.IO.Path]::GetFullPath('.\existing\0.0.1\existing.psd1')) + $actual[1].Path | Should -BeExactly ([System.IO.Path]::GetFullPath('.\existing2\0.0.1\existing2.psd1')) + + $actual = Get-Module -ListAvailable -Name '..\existing*' + $actual | Should -HaveCount 2 + $actual[0].Path | Should -BeExactly ([System.IO.Path]::GetFullPath('..\existing\0.0.1\existing.psd1')) + $actual[1].Path | Should -BeExactly ([System.IO.Path]::GetFullPath('..\existing2\0.0.1\existing2.psd1')) + } } } From c8356e6a467fb35e493590f36689beae24e7df73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 17:29:45 +0200 Subject: [PATCH 042/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index b51a94abb5a..7b99bc4af47 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -430,6 +430,15 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual[0].Path | Should -BeExactly ([System.IO.Path]::GetFullPath('..\existing\0.0.1\existing.psd1')) $actual[1].Path | Should -BeExactly ([System.IO.Path]::GetFullPath('..\existing2\0.0.1\existing2.psd1')) } + + # TODO: This looks like a bug. + It 'wrongly returns $null for existing manifest modules when using the -FullyQualifiedName parameter' { + $actual = Get-Module -ListAvailable -FullyQualifiedName '.\existing*' + $actual | Should -Be $null + + $actual = Get-Module -ListAvailable -FullyQualifiedName '..\existing*' + $actual | Should -Be $null + } } } From aa7e56d3325df3932bca79e2912f89c699ea6b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 17:29:52 +0200 Subject: [PATCH 043/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 7b99bc4af47..9fc62c435dc 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -439,6 +439,16 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual = Get-Module -ListAvailable -FullyQualifiedName '..\existing*' $actual | Should -Be $null } + + It 'returns module information for existing script module' { + $actual = Get-Module -ListAvailable -Name '.\loose*' + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly ([System.IO.Path]::GetFullPath('.\loose.psm1')) + + $actual = Get-Module -ListAvailable -FullyQualifiedName '..\loose*' + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly ([System.IO.Path]::GetFullPath('..\loose.psm1')) + } } } From d0f5508ad7efacb1147b020a8117c7de0e340dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:32:55 +0200 Subject: [PATCH 044/117] Add `Describe` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 9fc62c435dc..d394f493c44 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -280,6 +280,9 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { } } +Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is home-rooted' -Tags "CI" { +} + Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is relative-rooted' -Tags "CI" { It 'wrongly returns module information instead of $null or error for missing script module' { $path1 = Join-Path . missing.psm1 From 19c392ac89d3536ab4354328cb1258e4b3f77223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:33:10 +0200 Subject: [PATCH 045/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index d394f493c44..119a6a3cb7c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -281,6 +281,14 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is home-rooted' -Tags "CI" { + It 'wrongly does not expand ''~'' to $HOME' { + $path = Join-Path ~ missing.psm1 + Test-Path $path | Should -BeFalse + + Get-Module -ListAvailable -Name $path | ForEach-Object Path | Should -BeExactly (Join-Path $HOME missing.psm1) + # TODO: This is a bug. + Get-Module -ListAvailable -FullyQualifiedName $path | ForEach-Object Path | Should -BeExactly (Join-Path $pwd $path) + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is relative-rooted' -Tags "CI" { From b75d60e517472d2cf306cbe6bbf88d7cfd9f6ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:33:20 +0200 Subject: [PATCH 046/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 119a6a3cb7c..0f3102a6b31 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -289,6 +289,14 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum # TODO: This is a bug. Get-Module -ListAvailable -FullyQualifiedName $path | ForEach-Object Path | Should -BeExactly (Join-Path $pwd $path) } + + It 'wrongly returns module information instead of $null or error for missing script module' { + $path = Join-Path ~ missing.psm1 + Test-Path $path | Should -BeFalse + + Get-Module -ListAvailable -Name $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + Get-Module -ListAvailable -FullyQualifiedName $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is relative-rooted' -Tags "CI" { From 1c653629c17a93300c0c209d0f5779fc6a3f5d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:33:31 +0200 Subject: [PATCH 047/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 0f3102a6b31..b35d5a4dbeb 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -297,6 +297,19 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Get-Module -ListAvailable -Name $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) Get-Module -ListAvailable -FullyQualifiedName $path | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) } + + It 'writes error for missing manifest module' { + $path = Join-Path ~ missing.psm1 + Test-Path $path | Should -BeFalse + + $name = Join-Path ~ missing + + $err = { Get-Module -ListAvailable -Name $name -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' + + $err = { Get-Module -ListAvailable -FullyQualifiedName $name -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is relative-rooted' -Tags "CI" { From f4ea1ea38fd8cac1c43f4d5213c3e75dbda67577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:33:47 +0200 Subject: [PATCH 048/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index b35d5a4dbeb..74bbf9b9f7a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -310,6 +310,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $err = { Get-Module -ListAvailable -FullyQualifiedName $name -ErrorAction Stop } | Should -Throw -PassThru $err.Exception.Message | Should -BeLike '*Update the Name parameter*' } + + Context 'Locating existing script module' { + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is relative-rooted' -Tags "CI" { From 2fcbc0ce017ac33cee1369ebf270ef035af4e7fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:34:08 +0200 Subject: [PATCH 049/117] Add `BeforeAll` and `AfterAll` --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 74bbf9b9f7a..09b71cfe329 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -312,6 +312,16 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'Locating existing script module' { + BeforeAll { + # Script modules + # + $inHomeLooseFilePath = Join-Path $HOME loose.psm1 + New-Item -ItemType File -Force $inHomeLooseFilePath > $null + } + + AfterAll { + Remove-Item $inHomeLooseFilePath + } } } From eb36cb1249c9c854b02de2cd5bf174dce3835084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:34:15 +0200 Subject: [PATCH 050/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 09b71cfe329..1dff9ff729c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -322,6 +322,20 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum AfterAll { Remove-Item $inHomeLooseFilePath } + + # TODO: This looks like a bug. + It 'wrongly writes error instead of returning module information for existing script module using basename' { + $path = Join-Path ~ loose.psm1 + Test-Path $path | Should -BeTrue + + $name = Join-Path ~ loose + + $err = { Get-Module -ListAvailable -Name $name -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' + + $err = { Get-Module -ListAvailable -FullyQualifiedName $name -ErrorAction Stop } | Should -Throw -PassThru + $err.Exception.Message | Should -BeLike '*Update the Name parameter*' + } } } From cfe48552ec798020eabd30e9301fc0c948ba66dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:34:24 +0200 Subject: [PATCH 051/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 1dff9ff729c..d1d9d430bf5 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -336,6 +336,20 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $err = { Get-Module -ListAvailable -FullyQualifiedName $name -ErrorAction Stop } | Should -Throw -PassThru $err.Exception.Message | Should -BeLike '*Update the Name parameter*' } + + It 'returns module information for existing script module using file name' { + $path = Join-Path ~ loose.psm1 + Test-Path $path | Should -BeTrue + + $actual = Get-Module -ListAvailable -Name $path + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly (Join-Path $HOME loose.psm1) + + # TODO: This is a bug. + $actual = Get-Module -ListAvailable -FullyQualifiedName $path + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly (Join-Path $pwd $path) + } } } From 0deccbeb7c3c1b5fef93b73db1a4f06c0c972045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:34:36 +0200 Subject: [PATCH 052/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index d1d9d430bf5..8aba55bed72 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -351,6 +351,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual[0].Path | Should -BeExactly (Join-Path $pwd $path) } } + + Context 'When argument contains wildcards' { + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is relative-rooted' -Tags "CI" { From 2fec8f5de48260206c21e3dd0d6bf4b38925ede9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:34:51 +0200 Subject: [PATCH 053/117] Add `BeforeAll` and `AfterAll` --- .../Get-Module.Tests.ps1 | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 8aba55bed72..93f88ac15c2 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -353,6 +353,35 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'When argument contains wildcards' { + BeforeAll { + # Manifest modules under '~' + # + # Versioned, manifest + $inHomeWithManifestFileName = 'existing' + $inHomeWithManifestDirectory = Join-Path '~' $inHomeWithManifestFileName '0.0.1' + $inHomeWithManifestFilePath = Join-Path $inHomeWithManifestDirectory "$inHomeWithManifestFileName.psm1" + New-Item -ItemType File -Force $inHomeWithManifestFilePath > $null + New-ModuleManifest -Path (Join-Path $inHomeWithManifestDirectory "$inHomeWithManifestFileName.psd1") + # + # Versioned, manifest + $inHomeWithManifestFileName2 = 'existing2' + $inHomeWithManifestDirectory2 = Join-Path '~' $inHomeWithManifestFileName2 '0.0.1' + $inHomeWithManifestFilePath2 = Join-Path $inHomeWithManifestDirectory2 "$inHomeWithManifestFileName2.psm1" + New-Item -ItemType File -Force $inHomeWithManifestFilePath2 > $null + New-ModuleManifest -Path (Join-Path $inHomeWithManifestDirectory2 "$inHomeWithManifestFileName2.psd1") + + # Script modules under '~' + # + $inHomeLooseFilePath = Join-Path '~' 'loose.psm1' + New-Item -ItemType File -Force $inHomeLooseFilePath > $null + } + + AfterAll { + Remove-Item -Force -Recurse $inHomeWithManifestDirectory + Remove-Item -Force -Recurse $inHomeWithManifestDirectory2 + + Remove-Item $inHomeLooseFilePath + } } } From 2c5886498deb975b598b08f626b9c65418438bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:34:58 +0200 Subject: [PATCH 054/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 93f88ac15c2..162cd8d96a3 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -382,6 +382,15 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Remove-Item $inHomeLooseFilePath } + + It 'returns existing manifest modules when using the -Name parameter' { + $name = Join-Path ~ existing* + + $actual = Get-Module -ListAvailable -Name $name + $actual | Should -HaveCount 2 + $actual[0].Path | Should -BeExactly (Join-Path $HOME existing 0.0.1, existing.psd1) + $actual[1].Path | Should -BeExactly (Join-Path $HOME existing2 0.0.1, existing2.psd1) + } } } From e4e16964098bd25fbc1f13c0d8bcf8ff1db14918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:35:06 +0200 Subject: [PATCH 055/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 162cd8d96a3..a3cc17e2ea0 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -391,6 +391,12 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual[0].Path | Should -BeExactly (Join-Path $HOME existing 0.0.1, existing.psd1) $actual[1].Path | Should -BeExactly (Join-Path $HOME existing2 0.0.1, existing2.psd1) } + + # TODO: This looks like a bug. + It 'wrongly returns $null for existing manifest modules when using the -FullyQualifiedName parameter' { + $actual = Get-Module -ListAvailable -FullyQualifiedName (Join-Path ~ existing*) + $actual | Should -Be $null + } } } From 0bb5dda192135d96cae4e88d46734a05ca031731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:35:10 +0200 Subject: [PATCH 056/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index a3cc17e2ea0..d979099dc47 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -397,6 +397,12 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual = Get-Module -ListAvailable -FullyQualifiedName (Join-Path ~ existing*) $actual | Should -Be $null } + + It 'returns module information for existing script module' { + $actual = Get-Module -ListAvailable -Name (Join-Path ~ loose*) + $actual | Should -HaveCount 1 + $actual[0].Path | Should -BeExactly (Join-Path $HOME loose.psm1) + } } } From c6bdcf8e92910873c26aeda3335e4a199de59c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:42:39 +0200 Subject: [PATCH 057/117] Add `Describe` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index d979099dc47..40462d6a00a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -280,6 +280,9 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { } } +Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is module name or filename-like' -Tags "CI" { +} + Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is home-rooted' -Tags "CI" { It 'wrongly does not expand ''~'' to $HOME' { $path = Join-Path ~ missing.psm1 From 056942776f8a98da9c7d676b703330267a319683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:43:07 +0200 Subject: [PATCH 058/117] Add test --- .../Get-Module.Tests.ps1 | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 40462d6a00a..3653b285bcc 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -281,6 +281,88 @@ Describe "Get-Module -ListAvailable" -Tags "CI" { } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is module name or filename-like' -Tags "CI" { + BeforeAll { + $oldPSModulePath = $env:PSModulePath + $env:PSModulePath = New-Item -ItemType Directory (Join-Path $TestDrive modules) + + # Manifest modules under $env:PSModulePath + # + # Versioned, manifest + $inPSModulePathWithManifestFileName = 'existing' + $inPSModulePatWithManifestDirectory = Join-Path $env:PSModulePath $inPSModulePathWithManifestFileName '0.0.1' + $inPSModulePathWithManifestFilePath = Join-Path $inPSModulePatWithManifestDirectory "$inPSModulePathWithManifestFileName.psm1" + New-Item -ItemType File -Force $inPSModulePathWithManifestFilePath > $null + New-ModuleManifest -Path (Join-Path $inPSModulePatWithManifestDirectory "$inPSModulePathWithManifestFileName.psd1") + # + # Versioned, manifest + $inPSModulePathWithManifestFileName2 = 'existing2' + $inPSModulePatWithManifestDirectory2 = Join-Path $env:PSModulePath $inPSModulePathWithManifestFileName2 '0.0.1' + $inPSModulePathWithManifestFilePath2 = Join-Path $inPSModulePatWithManifestDirectory2 "$inPSModulePathWithManifestFileName2.psm1" + New-Item -ItemType File -Force $inPSModulePathWithManifestFilePath2 > $null + New-ModuleManifest -Path (Join-Path $inPSModulePatWithManifestDirectory2 "$inPSModulePathWithManifestFileName2.psd1") + # + # Versioned, manifest, multiple components in name + $inPSModulePathWithManifestWithPathLikeNameFileName = 'existing.xxx' + $inPsModulePathWithManifestWithPathLikeNameDirectory = Join-Path $env:PSModulePath $inPSModulePathWithManifestWithPathLikeNameFileName '0.0.1' + $inPsModulePathWithManifestWithPathLikeNameFilePath = Join-Path $inPsModulePathWithManifestWithPathLikeNameDirectory "$inPSModulePathWithManifestWithPathLikeNameFileName.psm1" + New-Item -ItemType File -Force $inPsModulePathWithManifestWithPathLikeNameFilePath > $null + New-ModuleManifest -Path (Join-Path $inPsModulePathWithManifestWithPathLikeNameDirectory "$inPSModulePathWithManifestWithPathLikeNameFileName.psd1") + # + # Versioned, manifest, multiple components in name, name ending with PS module extension + $inPSModulePathWithManifestWithPathLikeNameAsPSExtensionFileName = 'existing.psm1' + $inPSModulePathWithManifestWithPathLikeNameAsPSExtensionDirectory = Join-Path $env:PSModulePath $inPSModulePathWithManifestWithPathLikeNameAsPSExtensionFileName '0.0.1' + $inPSModulePathWithManifestWithPathLikeNameAsPSExtensionFilePath = Join-Path $inPSModulePathWithManifestWithPathLikeNameAsPSExtensionDirectory "$inPSModulePathWithManifestWithPathLikeNameAsPSExtensionFileName.psm1" + New-Item -ItemType File -Force $inPSModulePathWithManifestWithPathLikeNameAsPSExtensionFilePath > $null + New-ModuleManifest -Path (Join-Path $inPSModulePathWithManifestWithPathLikeNameAsPSExtensionDirectory "$inPSModulePathWithManifestWithPathLikeNameAsPSExtensionFileName.psd1") + + # Script modules + # + # Under $env:PSModulePath. TODO: Is this a supported scenario? + $inPSModulePathLooseFilePath = Join-Path $env:PSModulePath 'existing-loose.psm1' + New-Item -ItemType File -Force $inPSModulePathLooseFilePath > $null + # + # Under $env:PSModulePath, multiple components in name. TODO: Is this a supported scenario? + $inPSModulePathLooseWithPathLikeFilePath = Join-Path $env:PSModulePath "existing-loose.xxx.psm1" + New-Item -ItemType File -Force $inPSModulePathLooseWithPathLikeFilePath > $null + # + # Under $env:PSModulePath, multiple components in name, name ending with PS module extension. TODO: Is this a supported scenario? + $inPSModulePathLooseWithPathLikeNameAsPSExtensionFilePath = Join-Path $env:PSModulePath "existing.psm1.psm1" + New-Item -ItemType File -Force $inPSModulePathLooseWithPathLikeNameAsPSExtensionFilePath > $null + # + # In working directory + $inWorkingDirectoryLooseFilePath = Join-Path . existing.psm1 + New-Item -ItemType File -Force $inWorkingDirectoryLooseFilePath > $null + # + # In parent directory + $inParentDirectoryLooseFilePath = Join-Path .. existing.psm1 + New-Item -ItemType File -Force $inParentDirectoryLooseFilePath > $null + # + # In working directory, ignored + 'function foo { "_" }' > (Join-Path $pwd ignore.psm1) + 'function foo { "_" }' > (Join-Path $pwd ignore.psm1.psm1) + } + + AfterAll { + $env:PSModulePath = $oldPSModulePath + + Remove-Item -ErrorAction Stop -Force -Recurse $inPSModulePatWithManifestDirectory + Remove-Item -ErrorAction Stop -Force -Recurse $inPSModulePatWithManifestDirectory2 + Remove-Item -ErrorAction Stop -Force -Recurse $inPsModulePathWithManifestWithPathLikeNameDirectory + Remove-Item -ErrorAction Stop -Force -Recurse $inPSModulePathWithManifestWithPathLikeNameAsPSExtensionDirectory + + Remove-Item -ErrorAction Stop $inPSModulePathLooseFilePath + Remove-Item -ErrorAction Stop $inPSModulePathLooseWithPathLikeFilePath + Remove-Item -ErrorAction Stop $inPSModulePathLooseWithPathLikeNameAsPSExtensionFilePath + Remove-Item -ErrorAction Stop $inWorkingDirectoryLooseFilePath + Remove-Item -ErrorAction Stop $inParentDirectoryLooseFilePath + Remove-Item -ErrorAction Stop ignore.psm1 + Remove-Item -ErrorAction Stop ignore.psm1.psm1 + } + + It 'returns module information for manifest module' { + Get-Module -ListAvailable -FullyQualifiedName existing | ForEach-Object Path | Should -BeExactly (Join-Path $env:PSModulePath existing '0.0.1','existing.psd1') + Get-Module -ListAvailable -Name existing | ForEach-Object Path | Should -BeExactly (Join-Path $env:PSModulePath existing '0.0.1','existing.psd1') + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is home-rooted' -Tags "CI" { From 7bbd2b62d00227e69d20165758131de94687b8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:43:12 +0200 Subject: [PATCH 059/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 3653b285bcc..27b3946fa68 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -363,6 +363,11 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Get-Module -ListAvailable -FullyQualifiedName existing | ForEach-Object Path | Should -BeExactly (Join-Path $env:PSModulePath existing '0.0.1','existing.psd1') Get-Module -ListAvailable -Name existing | ForEach-Object Path | Should -BeExactly (Join-Path $env:PSModulePath existing '0.0.1','existing.psd1') } + + It 'ignores module at current directory' { + Get-Module -ListAvailable -FullyQualifiedName ignore | Should -Be $null + Get-Module -ListAvailable -Name ignore | Should -Be $null + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is home-rooted' -Tags "CI" { From f2f491e6bf53ad9530f5fb3d79257d8a1cde9573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:43:30 +0200 Subject: [PATCH 060/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 27b3946fa68..cccc0544636 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -368,6 +368,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Get-Module -ListAvailable -FullyQualifiedName ignore | Should -Be $null Get-Module -ListAvailable -Name ignore | Should -Be $null } + + Context 'When path value has PS module extension, such as ''name.psm1''' { + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is home-rooted' -Tags "CI" { From 63e403d351e9adcde1a63875fd1f30c38eca424f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sun, 9 Aug 2026 21:43:36 +0200 Subject: [PATCH 061/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index cccc0544636..89acf0ac366 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -370,6 +370,11 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'When path value has PS module extension, such as ''name.psm1''' { + # Because non-rooted/non-relative-rooted paths MUST be resolved to modules under $env:PSModulePath. + It 'ignores module at current directory' { + Get-Module -ListAvailable -FullyQualifiedName ignore.psm1 | Should -Be $null + Get-Module -ListAvailable -Name ignore.psm1 | Should -Be $null + } } } From 9bff3f0c9a0a896feef248f5231733e283ab9c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:33:53 +0200 Subject: [PATCH 062/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 89acf0ac366..c340998f517 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -375,6 +375,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Get-Module -ListAvailable -FullyQualifiedName ignore.psm1 | Should -Be $null Get-Module -ListAvailable -Name ignore.psm1 | Should -Be $null } + + Context 'Resolves to module under $env:PSModulePath' { + } } } From bdd49cc1526a398a8bc37c64794c617fd8b4d840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:34:02 +0200 Subject: [PATCH 063/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index c340998f517..7a5e0c3ce90 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -377,6 +377,13 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'Resolves to module under $env:PSModulePath' { + # Unclear whether this is correct behavior. Are loose modules allowed under $env:PSModulePath? + # Could resolve to: + # - 'existing-loose.psm1' loose module + It 'wrongly/correctly returns $null instead of module information for loose module' { + Get-Module -ListAvailable -FullyQualifiedName existing-loose.psm1 | Should -Be $null + Get-Module -ListAvailable -Name existing-loose.psm1 | Should -Be $null + } } } } From a48815cf8270e4770bb42a91118338526d97ccdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:34:10 +0200 Subject: [PATCH 064/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 7a5e0c3ce90..8205f6c0037 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -384,6 +384,14 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Get-Module -ListAvailable -FullyQualifiedName existing-loose.psm1 | Should -Be $null Get-Module -ListAvailable -Name existing-loose.psm1 | Should -Be $null } + + # Unclear whether this is correct behavior. Are loose modules allowed under $env:PSModulePath?. + # Could resolve to: + # - 'existing2' manifest module + It 'wrongly/correctly returns $null instead of module information for versioned module' { + Get-Module -ListAvailable -FullyQualifiedName existing2.psm1 | Should -Be $null + Get-Module -ListAvailable -Name existing2.psm1 | Should -Be $null + } } } } From ebe1ecbf84e51cef8ad014c854414c7507bad7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:34:19 +0200 Subject: [PATCH 065/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 8205f6c0037..770a29b67e4 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -392,6 +392,12 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Get-Module -ListAvailable -FullyQualifiedName existing2.psm1 | Should -Be $null Get-Module -ListAvailable -Name existing2.psm1 | Should -Be $null } + + # Finds manifest module 'existing.psm1.psm1'. TODO: Is that correct? + It 'wrongly/correctly returns module information for versioned module ending with PS extension' { + Get-Module -ListAvailable -FullyQualifiedName existing.psm1 | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + Get-Module -ListAvailable -Name existing.psm1 | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + } } } } From e37c3225ba98b388d88f5d7d623892e801999684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:34:34 +0200 Subject: [PATCH 066/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 770a29b67e4..b26af8a93f5 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -399,6 +399,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Get-Module -ListAvailable -Name existing.psm1 | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) } } + + Context 'Resolves to non-existing loose or versioned module under $env:PSModulePath' { + } } } From d9daa5377b739956e0374fd563461f9d16b29108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:34:41 +0200 Subject: [PATCH 067/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index b26af8a93f5..068ec07a267 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -401,6 +401,15 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'Resolves to non-existing loose or versioned module under $env:PSModulePath' { + It 'wrongly returns $null instead of error' { + $path1 = Join-Path $env:PSModulePath missing.psm1 + $path2 = Join-Path $env:PSModulePath missing.psm1 *, missing.psm1 + Test-Path $path1 | Should -BeFalse + Test-Path $path2 | Should -BeFalse + + Get-Module -ListAvailable -FullyQualifiedName missing.psm1 | Should -Be $null + Get-Module -ListAvailable -Name missing.psm1 | Should -Be $null + } } } } From 963c04dda1caef74ebaf04a43be2d610e3da48ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:34:56 +0200 Subject: [PATCH 068/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 068ec07a267..370efce84d1 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -412,6 +412,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } } } + + Context 'When path value has unknown extension, such as ''name.xxx''' { + } } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is home-rooted' -Tags "CI" { From 8fe048632c8711dc0e7cbfdadd5a6e7b561c9cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:35:14 +0200 Subject: [PATCH 069/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 370efce84d1..54fc1428648 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -414,6 +414,8 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'When path value has unknown extension, such as ''name.xxx''' { + Context 'Resolves to non-existing loose or versioned module under $env:PSModulePath' { + } } } From 47a6d46b5ff1d0422536877102f634731b8d9e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:35:20 +0200 Subject: [PATCH 070/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 54fc1428648..8bd582cf347 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -415,6 +415,15 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Context 'When path value has unknown extension, such as ''name.xxx''' { Context 'Resolves to non-existing loose or versioned module under $env:PSModulePath' { + It 'wrongly returns $null instead of error' { + $path1 = Join-Path $env:PSModulePath missing.xxx.psm1 + $path2 = Join-Path $env:PSModulePath missing *, missing.xxx.psm1 + Test-Path $path1 | Should -BeFalse + Test-Path $path2 | Should -BeFalse + + Get-Module -ListAvailable -FullyQualifiedName missing.xxx | Should -Be $null + Get-Module -ListAvailable -Name missing.xxx | Should -Be $null + } } } } From 47e4bad50bfadfdbd76564f8e587847cb72ea504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:35:28 +0200 Subject: [PATCH 071/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 8bd582cf347..d68d99354e1 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -425,6 +425,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Get-Module -ListAvailable -Name missing.xxx | Should -Be $null } } + + Context 'Resolves to loose module under $env:PSModule' { + } } } From 8f1beaaeaf275f1a84052c5a12a4151a3fd80f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:35:35 +0200 Subject: [PATCH 072/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index d68d99354e1..609707e9e14 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -427,6 +427,13 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'Resolves to loose module under $env:PSModule' { + # Unclear whether only manifest modules are discovered under $env:PSModulePath. + It 'wrongly/correctly returns $null instead of module information' { + $path = Join-Path $env:PSModulePath existing-loose.xxx.psm1 + Test-Path $path | Should -BeTrue + + Get-Module -ListAvailable -FullyQualifiedName existing-loose.xxx | Should -Be $null + } } } } From 3d826dd9522082658875b77a523e20396c8b7018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:35:45 +0200 Subject: [PATCH 073/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 609707e9e14..6206cde8c87 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -435,6 +435,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Get-Module -ListAvailable -FullyQualifiedName existing-loose.xxx | Should -Be $null } } + + Context 'Resolves to manifest module under $env:PSModule' { + } } } From ce944e9f4995d7c117cb4136fe2c72ee7a8393a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 21:35:52 +0200 Subject: [PATCH 074/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 6206cde8c87..bbcccd36c41 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -437,6 +437,14 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'Resolves to manifest module under $env:PSModule' { + # Unclear whether only manifest modules are discovered under $env:PSModulePath. + It 'returns module information' { + $path = Join-Path $env:PSModulePath existing.xxx 0.0.1, existing.xxx.psm1 + Test-Path $path | Should -BeTrue + + Get-Module -ListAvailable -FullyQualifiedName existing.xxx | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + Get-Module -ListAvailable -Name existing.xxx | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) + } } } } From a2062ec5293db27ea79c94e3ef5efd52bcddc028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 22:37:15 +0200 Subject: [PATCH 075/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index bbcccd36c41..43ba11344a6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -446,6 +446,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum Get-Module -ListAvailable -Name existing.xxx | Should -BeOfType ([System.Management.Automation.PSModuleInfo]) } } + + Context 'When argument has wildcards' { + } } } From 56c561d92c6421c2ce76da2899f34012e03b19e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 22:37:24 +0200 Subject: [PATCH 076/117] Add test --- .../Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 43ba11344a6..b849c306e95 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -448,6 +448,15 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'When argument has wildcards' { + It 'ignores existing script modules in working directory' { + Join-Path $pwd ignore.psm1 | Should -BeTrue + + $actual = Get-Module -ListAvailable -Name ignore* + $actual | Should -Be $null + + $actual = Get-Module -ListAvailable -FullyQualifiedName ignore* + $actual | Should -Be $null + } } } } From d099bf62b4e66cb3aea562212c54d70854147a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 22:37:37 +0200 Subject: [PATCH 077/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index b849c306e95..f3a17e73808 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -457,6 +457,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual = Get-Module -ListAvailable -FullyQualifiedName ignore* $actual | Should -Be $null } + + Context 'Resolves to existing script modules' { + } } } } From 10754158821211f349433b4b1251bd1ffd818071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 22:37:44 +0200 Subject: [PATCH 078/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index f3a17e73808..7ce9e17442a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -459,6 +459,13 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'Resolves to existing script modules' { + It 'wrongly/correctly returns $null' { + $actual = Get-Module -ListAvailable -Name existing-loose* + $actual | Should -Be $null + + $actual = Get-Module -ListAvailable -FullyQualifiedName existing-loose* + $actual | Should -Be $null + } } } } From b7b3126892fe874fe50525123db9d667e522e44d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 22:37:55 +0200 Subject: [PATCH 079/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 7ce9e17442a..9a2a18d97a6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -467,6 +467,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual | Should -Be $null } } + + Context 'Resolves to existing manifest modules' { + } } } } From 2b27c51a8af2260e9e8fccbffe3f0817be7e27cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 22:38:02 +0200 Subject: [PATCH 080/117] Add test --- .../Get-Module.Tests.ps1 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 9a2a18d97a6..79ca9426077 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -469,6 +469,21 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'Resolves to existing manifest modules' { + It 'returns modules' { + $actual = Get-Module -ListAvailable -Name existing* + $actual | Should -HaveCount 4 + $actual[0].Name | Should -BeExactly existing + $actual[1].Name | Should -BeExactly existing.psm1 + $actual[2].Name | Should -BeExactly existing.xxx + $actual[3].Name | Should -BeExactly existing2 + + $actual = Get-Module -ListAvailable -FullyQualifiedName existing* + $actual | Should -HaveCount 4 + $actual[0].Name | Should -BeExactly existing + $actual[1].Name | Should -BeExactly existing.psm1 + $actual[2].Name | Should -BeExactly existing.xxx + $actual[3].Name | Should -BeExactly existing2 + } } } } From 26957357b13290cb9468ffe0128ba28c406aac4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 22:38:16 +0200 Subject: [PATCH 081/117] Add `Context` --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index 79ca9426077..e79e8579d69 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -485,6 +485,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual[3].Name | Should -BeExactly existing2 } } + + Context 'Resolves to non-existing modules' { + } } } } From c8d50419e7a6f5b35c3595c98b6b322b362c07e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 11 Aug 2026 22:38:23 +0200 Subject: [PATCH 082/117] Add test --- .../Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index e79e8579d69..e4855255df3 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -487,6 +487,13 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Context 'Resolves to non-existing modules' { + It 'wrongly/correctly returns $null' { + $actual = Get-Module -ListAvailable -Name missing* + $actual | Should -Be $null + + $actual = Get-Module -ListAvailable -FullyQualifiedName missing* + $actual | Should -Be $null + } } } } From 33c6948cb2fea41bf7703cf7f4fd3204e0f8a6ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:06:34 +0200 Subject: [PATCH 083/117] Clarify intent --- .../engine/Modules/ModuleSpecification.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs index 3c06ee856f3..01bdec513be 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs @@ -105,7 +105,8 @@ internal static Exception ModuleSpecificationInitHelper(ModuleSpecification modu else if (field.Equals("MaximumVersion", StringComparison.OrdinalIgnoreCase)) { moduleSpecification.MaximumVersion = LanguagePrimitives.ConvertTo(entry.Value); - ModuleCmdletBase.GetMaximumVersion(moduleSpecification.MaximumVersion); + // Ensure max version is correctly formatted. + _ = ModuleCmdletBase.GetMaximumVersion(moduleSpecification.MaximumVersion); } else if (field.Equals("GUID", StringComparison.OrdinalIgnoreCase)) { From 4c0f3dd26641abaea67b71b15f9842eed0d7a9e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:07:04 +0200 Subject: [PATCH 084/117] Use existing API The API belongs to a different PowerShell module but is accessible. --- .../engine/Modules/ModuleSpecification.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs index 01bdec513be..758cf5b0f4a 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs @@ -90,25 +90,25 @@ internal static Exception ModuleSpecificationInitHelper(ModuleSpecification modu { string field = entry.Key.ToString(); - if (field.Equals("ModuleName", StringComparison.OrdinalIgnoreCase)) + if (field.EqualsOrdinalIgnoreCase("ModuleName")) { moduleSpecification.Name = LanguagePrimitives.ConvertTo(entry.Value); } - else if (field.Equals("ModuleVersion", StringComparison.OrdinalIgnoreCase)) + else if (field.EqualsOrdinalIgnoreCase("ModuleVersion")) { moduleSpecification.Version = LanguagePrimitives.ConvertTo(entry.Value); } - else if (field.Equals("RequiredVersion", StringComparison.OrdinalIgnoreCase)) + else if (field.EqualsOrdinalIgnoreCase("RequiredVersion")) { moduleSpecification.RequiredVersion = LanguagePrimitives.ConvertTo(entry.Value); } - else if (field.Equals("MaximumVersion", StringComparison.OrdinalIgnoreCase)) + else if (field.EqualsOrdinalIgnoreCase("MaximumVersion")) { moduleSpecification.MaximumVersion = LanguagePrimitives.ConvertTo(entry.Value); // Ensure max version is correctly formatted. _ = ModuleCmdletBase.GetMaximumVersion(moduleSpecification.MaximumVersion); } - else if (field.Equals("GUID", StringComparison.OrdinalIgnoreCase)) + else if (field.EqualsOrdinalIgnoreCase("GUID")) { moduleSpecification.Guid = LanguagePrimitives.ConvertTo(entry.Value); } From 1454a6afe364b3897cc26fcdce44a6347876195d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:07:16 +0200 Subject: [PATCH 085/117] Edit --- .../engine/Modules/ModuleSpecification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs index 758cf5b0f4a..d264215383e 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs @@ -340,7 +340,7 @@ internal ModuleSpecification WithNormalizedName(ExecutionContext context, string } /// - /// Compares two ModuleSpecification objects for equality. + /// Compares two objects for structural equality. /// internal class ModuleSpecificationComparer : IEqualityComparer { From dab0c4ecc5b197e607ccde6a299f132ab9fdfad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:07:45 +0200 Subject: [PATCH 086/117] More explicit comparison --- .../engine/Modules/ModuleSpecification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs index d264215383e..be48b08e9af 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs @@ -352,7 +352,7 @@ internal class ModuleSpecificationComparer : IEqualityComparerTrue if the specifications are equal, false otherwise. public bool Equals(ModuleSpecification x, ModuleSpecification y) { - if (x == y) + if (ReferenceEquals(x, y)) { return true; } From 9471ebb5e4f9c30c551ff69622d8a0cfbe9953ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:09:32 +0200 Subject: [PATCH 087/117] Consistency The values are expected to be numbers, though. --- .../engine/Modules/ModuleSpecification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs index be48b08e9af..4a9d6a2cab1 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleSpecification.cs @@ -362,7 +362,7 @@ public bool Equals(ModuleSpecification x, ModuleSpecification y) && Guid.Equals(x.Guid, y.Guid) && Version.Equals(x.RequiredVersion, y.RequiredVersion) && Version.Equals(x.Version, y.Version) - && string.Equals(x.MaximumVersion, y.MaximumVersion); + && string.Equals(x.MaximumVersion, y.MaximumVersion, StringComparison.OrdinalIgnoreCase); } /// From 3233cef7b68359162b870222f84136346bd475f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:41:29 +0200 Subject: [PATCH 088/117] Rename parameter No call sites using parameter name. --- .../engine/Modules/ModuleIntrinsics.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 538c4775f0a..13048623bc2 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -728,7 +728,7 @@ internal static bool MatchesModulePath(string modulePath, string requiredPath) /// and either returns it as a simple name (if it was a simple name) /// or a fully qualified, PowerShell-resolved path. /// - /// The name or path of the module from the specification. + /// The name or path of the module from the specification. /// The path to base relative paths off. /// The current execution context. /// @@ -743,37 +743,37 @@ internal static bool MatchesModulePath(string modulePath, string requiredPath) /// Hopefully we can find a standard path resolution API to settle on. /// internal static string NormalizeModuleName( - string moduleName, + string moduleNameOrPath, string basePath, ExecutionContext executionContext) { - if (moduleName == null) + if (moduleNameOrPath == null) { return null; } // Check whether the module is a path -- if not, it is a simple name and we just return it. - if (!IsModuleNamePath(moduleName)) + if (!IsModuleNamePath(moduleNameOrPath)) { - return moduleName; + return moduleNameOrPath; } // Standardize directory separators -- Path.IsPathRooted() will return false for "\path\here" on *nix and for "/path/there" on Windows - moduleName = moduleName.Replace(StringLiterals.AlternatePathSeparator, StringLiterals.DefaultPathSeparator); + moduleNameOrPath = moduleNameOrPath.Replace(StringLiterals.AlternatePathSeparator, StringLiterals.DefaultPathSeparator); // Note: Path.IsFullyQualified("\default\root") is false on Windows, but Path.IsPathRooted returns true - if (!Path.IsPathRooted(moduleName)) + if (!Path.IsPathRooted(moduleNameOrPath)) { - moduleName = Path.Join(basePath, moduleName); + moduleNameOrPath = Path.Join(basePath, moduleNameOrPath); } // Use the PowerShell filesystem provider to fully resolve the path // If there is a problem, null could be returned -- so default back to the pre-normalized path - string normalizedPath = ModuleCmdletBase.GetResolvedPath(moduleName, executionContext)?.TrimEnd(StringLiterals.DefaultPathSeparator); + string normalizedPath = ModuleCmdletBase.GetResolvedPath(moduleNameOrPath, executionContext)?.TrimEnd(StringLiterals.DefaultPathSeparator); // ModuleCmdletBase.GetResolvePath will return null in the unlikely event that it failed. // If it does, we return the fully qualified path generated before. - return normalizedPath ?? Path.GetFullPath(moduleName); + return normalizedPath ?? Path.GetFullPath(moduleNameOrPath); } /// From aa29c6c41c4ff9eb1b0ae2cc4d1f5dd7957c34b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:43:53 +0200 Subject: [PATCH 089/117] Rename parameter No call sites using parameter name. Same parameter name as `System.IO.Path.GetRelativePath()`. --- .../engine/Modules/ModuleIntrinsics.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 13048623bc2..fc1a11e4787 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -729,7 +729,7 @@ internal static bool MatchesModulePath(string modulePath, string requiredPath) /// or a fully qualified, PowerShell-resolved path. /// /// The name or path of the module from the specification. - /// The path to base relative paths off. + /// The path to base relative paths off. /// The current execution context. /// /// The simple module name if the given one was simple, @@ -744,7 +744,7 @@ internal static bool MatchesModulePath(string modulePath, string requiredPath) /// internal static string NormalizeModuleName( string moduleNameOrPath, - string basePath, + string relativeTo, ExecutionContext executionContext) { if (moduleNameOrPath == null) @@ -764,7 +764,7 @@ internal static string NormalizeModuleName( // Note: Path.IsFullyQualified("\default\root") is false on Windows, but Path.IsPathRooted returns true if (!Path.IsPathRooted(moduleNameOrPath)) { - moduleNameOrPath = Path.Join(basePath, moduleNameOrPath); + moduleNameOrPath = Path.Join(relativeTo, moduleNameOrPath); } // Use the PowerShell filesystem provider to fully resolve the path From 033f72ba5e4edaaeb71178f37ffcc82a44018dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:45:22 +0200 Subject: [PATCH 090/117] Edit --- .../engine/Modules/ModuleIntrinsics.cs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index fc1a11e4787..d111c4d9e17 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -724,16 +724,28 @@ internal static bool MatchesModulePath(string modulePath, string requiredPath) } /// - /// Takes the name of a module as used in a module specification - /// and either returns it as a simple name (if it was a simple name) - /// or a fully qualified, PowerShell-resolved path. + /// Takes a module name from a module specification and returns a + /// normalized module name. /// + /// + /// + /// A normalized module name is either: + /// + /// A simple module name if was a simple name. + /// A fully qualified, PowerShell-resolved path. + /// + /// A fully qualified path by combination of and + /// if PowerShell could not resolve the path. + /// + /// + /// + /// /// The name or path of the module from the specification. /// The path to base relative paths off. /// The current execution context. /// - /// The simple module name if the given one was simple, - /// otherwise a fully resolved, absolute path to the module. + /// A simple module name if was a simple module + /// name, otherwise a fully qualified path to the module. /// /// /// 2018-11-09 rjmholt: From 9aba90a95d4b48256d3ee7e6073ab2c6d2b06196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:48:42 +0200 Subject: [PATCH 091/117] Add parameter precondition The argument for `moduleNameOrPath` cannot be null at the current call sites. --- .../engine/Modules/ModuleIntrinsics.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index d111c4d9e17..fbb8ccacc23 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -759,10 +759,7 @@ internal static string NormalizeModuleName( string relativeTo, ExecutionContext executionContext) { - if (moduleNameOrPath == null) - { - return null; - } + ArgumentNullException.ThrowIfNull(moduleNameOrPath); // Check whether the module is a path -- if not, it is a simple name and we just return it. if (!IsModuleNamePath(moduleNameOrPath)) From 3abdc8499ef84b66a2fe9b953eedaf6208ffcff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:51:21 +0200 Subject: [PATCH 092/117] Add parameter precondition The point is to return a fully qualified path, which cannot be the case if `relativeTo` is `null` and we need to use it. --- .../engine/Modules/ModuleIntrinsics.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index fbb8ccacc23..0a7b0626c0c 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -760,6 +760,7 @@ internal static string NormalizeModuleName( ExecutionContext executionContext) { ArgumentNullException.ThrowIfNull(moduleNameOrPath); + ArgumentNullException.ThrowIfNull(relativeTo); // Check whether the module is a path -- if not, it is a simple name and we just return it. if (!IsModuleNamePath(moduleNameOrPath)) From 3f7e3c8d0fc7ab7e8798d496a704b133453e51e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:51:55 +0200 Subject: [PATCH 093/117] Remove redundant comment --- .../engine/Modules/ModuleIntrinsics.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 0a7b0626c0c..95090c3321b 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -762,7 +762,6 @@ internal static string NormalizeModuleName( ArgumentNullException.ThrowIfNull(moduleNameOrPath); ArgumentNullException.ThrowIfNull(relativeTo); - // Check whether the module is a path -- if not, it is a simple name and we just return it. if (!IsModuleNamePath(moduleNameOrPath)) { return moduleNameOrPath; From 4a3ccdd6e53e607c5467ca5ed5190ee5c4616a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:52:08 +0200 Subject: [PATCH 094/117] Edit documentation The comment may not apply to newer versions of .NET. --- .../engine/Modules/ModuleIntrinsics.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 95090c3321b..6b5c4f2a422 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -767,7 +767,9 @@ internal static string NormalizeModuleName( return moduleNameOrPath; } - // Standardize directory separators -- Path.IsPathRooted() will return false for "\path\here" on *nix and for "/path/there" on Windows + // Ensure OS default directory separators because + // - Path.IsPathRooted("\some\path") returns false on *nix, and + // - Path.IsPathRooted("/some/path") return false on Windows. moduleNameOrPath = moduleNameOrPath.Replace(StringLiterals.AlternatePathSeparator, StringLiterals.DefaultPathSeparator); // Note: Path.IsFullyQualified("\default\root") is false on Windows, but Path.IsPathRooted returns true From 7ca24b8957926bb12120380ee10b04b2bae2cd92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:52:17 +0200 Subject: [PATCH 095/117] Edit documentation --- .../engine/Modules/ModuleIntrinsics.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 6b5c4f2a422..4077850dc52 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -772,7 +772,9 @@ internal static string NormalizeModuleName( // - Path.IsPathRooted("/some/path") return false on Windows. moduleNameOrPath = moduleNameOrPath.Replace(StringLiterals.AlternatePathSeparator, StringLiterals.DefaultPathSeparator); - // Note: Path.IsFullyQualified("\default\root") is false on Windows, but Path.IsPathRooted returns true + // On Windows: + // - Path.IsFullyQualified("\default\root") returns false, but + // - Path.IsPathRooted("\default\root") returns true. if (!Path.IsPathRooted(moduleNameOrPath)) { moduleNameOrPath = Path.Join(relativeTo, moduleNameOrPath); From 29fcdf5901f8ee84f9b85925d5d9510467e9b38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:52:34 +0200 Subject: [PATCH 096/117] Edit documentation --- .../engine/Modules/ModuleIntrinsics.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 4077850dc52..132fbd1b1e6 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -780,12 +780,10 @@ internal static string NormalizeModuleName( moduleNameOrPath = Path.Join(relativeTo, moduleNameOrPath); } - // Use the PowerShell filesystem provider to fully resolve the path - // If there is a problem, null could be returned -- so default back to the pre-normalized path + // Resolving the path using ModuleCmdletBase.GetResolvedPath() may rarely return null. string normalizedPath = ModuleCmdletBase.GetResolvedPath(moduleNameOrPath, executionContext)?.TrimEnd(StringLiterals.DefaultPathSeparator); - // ModuleCmdletBase.GetResolvePath will return null in the unlikely event that it failed. - // If it does, we return the fully qualified path generated before. + // If the resolved path is null, just return the fully qualified path generated before. return normalizedPath ?? Path.GetFullPath(moduleNameOrPath); } From d85fea0f2590eb10a801712fc44d556e773a29f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 19:58:13 +0200 Subject: [PATCH 097/117] Format Relatively short signature and no more than three parameters. --- .../engine/Modules/ModuleIntrinsics.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 132fbd1b1e6..ce3160afc06 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -754,10 +754,7 @@ internal static bool MatchesModulePath(string modulePath, string requiredPath) /// they all make some assumptions about their caller I wrote this method. /// Hopefully we can find a standard path resolution API to settle on. /// - internal static string NormalizeModuleName( - string moduleNameOrPath, - string relativeTo, - ExecutionContext executionContext) + internal static string NormalizeModuleName(string moduleNameOrPath, string relativeTo, ExecutionContext executionContext) { ArgumentNullException.ThrowIfNull(moduleNameOrPath); ArgumentNullException.ThrowIfNull(relativeTo); From f10393f400ba79e630969f2b5c4dd25dc482947b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 20:01:34 +0200 Subject: [PATCH 098/117] Make old remark visible again --- .../engine/Modules/ModuleIntrinsics.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index ce3160afc06..6523679f573 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -739,6 +739,12 @@ internal static bool MatchesModulePath(string modulePath, string requiredPath) /// /// /// + /// + /// 2018-11-09 rjmholt: + /// There are several, possibly inconsistent, path handling mechanisms in the module cmdlets. + /// After looking through all of them and seeing they all make some assumptions about their caller + /// I wrote this method. Hopefully we can find a standard path resolution API to settle on. + /// /// /// The name or path of the module from the specification. /// The path to base relative paths off. @@ -747,13 +753,6 @@ internal static bool MatchesModulePath(string modulePath, string requiredPath) /// A simple module name if was a simple module /// name, otherwise a fully qualified path to the module. /// - /// - /// 2018-11-09 rjmholt: - /// There are several, possibly inconsistent, path handling mechanisms - /// in the module cmdlets. After looking through all of them and seeing - /// they all make some assumptions about their caller I wrote this method. - /// Hopefully we can find a standard path resolution API to settle on. - /// internal static string NormalizeModuleName(string moduleNameOrPath, string relativeTo, ExecutionContext executionContext) { ArgumentNullException.ThrowIfNull(moduleNameOrPath); From 85bc7959f9f4c83863df902e9133c572a6acbb48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Sat, 18 Jul 2026 20:02:56 +0200 Subject: [PATCH 099/117] Hide old remark from Intellisense --- .../engine/Modules/ModuleIntrinsics.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 6523679f573..71ac49e9701 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -739,12 +739,12 @@ internal static bool MatchesModulePath(string modulePath, string requiredPath) /// /// /// - /// + /// /// /// The name or path of the module from the specification. /// The path to base relative paths off. From a3651a1c325e808fc2393b5d3b79767e658d28d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 20 Jul 2026 23:00:04 +0200 Subject: [PATCH 100/117] Add new path resolution API --- .../engine/Modules/ModuleCmdletBase.cs | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 0a1d0bfc04f..e3fceb459d2 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4891,6 +4891,88 @@ internal static Collection GetResolvedPathCollection(string filePath, Ex return filePaths; } + /// + /// Resolves using the file system provider, without error handling. + /// + /// + /// + /// This method does not normalize 's directory separators. + /// + /// + /// The path to resolve. + /// The execution context. + /// Whether non-existing paths should be resolved. + /// + /// + /// if the file system provider isn't available. + /// All resolved paths if resolution of succeeded. + /// + /// + /// Thrown if path resolution is not performed by the file system provider. + internal static Collection ResolveToFileSystemPathsThrowing(string path, ExecutionContext context, bool allowNonExistingPaths = false) + { + if (context?.EngineSessionState?.IsProviderLoaded(context.ProviderNames.FileSystem) != true) + { + // We're only interested in resolving file system paths. + return null; + } + + // TODO: Can path resolution succeed and return null? + Collection resolvedPaths = context.SessionState.Path.GetResolvedProviderPathFromPSPath(path, + allowNonExistingPaths, + out ProviderInfo provider); + + // Ported from legacy code to preserve behavior. + if (!provider.NameEquals(context.ProviderNames.FileSystem)) + { + throw InterpreterError.NewInterpreterException( + path, + typeof(RuntimeException), + errorPosition: null, + "FileOpenError", + ParserStrings.FileOpenError, + provider.FullName); + } + + return resolvedPaths; + } + + /// + /// Resolves using the file system provider. + /// + /// + /// + /// This method does not normalize 's directory separators. + /// This method does not throw. + /// + /// + /// The path to resolve. + /// Execution context. + /// Whether non-existing paths should be resolved. + /// All resolved file system paths if the return value is , otherwise . + /// + /// if path resolution through the file system provider succeeded, otherwise . + /// + internal static bool TryResolveToFileSystemPaths( + string path, + ExecutionContext context, + out Collection resolvedPaths, + bool allowNonExistingPaths = false) + { + resolvedPaths = null; + + try + { + resolvedPaths = ResolveToFileSystemPathsThrowing(path, context, allowNonExistingPaths); + } + catch (Exception) + { + // Ignore. + } + + return resolvedPaths != null; + } + internal static PSSession GetWindowsPowerShellCompatRemotingSession() { PSSession result = null; From 1f28de5e926418809572d68448ddb8a5bd3feb97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 20 Jul 2026 23:08:49 +0200 Subject: [PATCH 101/117] Refactor to use new path resolution API --- .../engine/Modules/ModuleCmdletBase.cs | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index e3fceb459d2..98a2665c4d1 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4819,34 +4819,18 @@ internal static string ResolveRootedFilePath(string filePath, ExecutionContext c internal static string GetResolvedPath(string filePath, ExecutionContext context) { - ProviderInfo provider = null; - - Collection filePaths; + Collection filePaths = null; - if (context != null && context.EngineSessionState != null && context.EngineSessionState.IsProviderLoaded(context.ProviderNames.FileSystem)) + if (!TryResolveToFileSystemPaths(filePath, context, out filePaths, allowNonExistingPaths: true)) { - try - { - filePaths = context.SessionState.Path.GetResolvedProviderPathFromPSPath(filePath, true /* allowNonExistentPaths */, out provider); - } - catch (Exception) - { - return null; - } - // Make sure that the path is in the file system - that's all we can handle currently... - if ((provider == null) || !provider.NameEquals(context.ProviderNames.FileSystem)) + // Ported from legacy code to preserve behavior. + if (context?.EngineSessionState?.IsProviderLoaded(context.ProviderNames.FileSystem) != true) { - return null; + filePaths = [filePath]; } } - else - { - filePaths = new Collection(); - filePaths.Add(filePath); - } - // Make sure at least one file was found... - if (filePaths == null || filePaths.Count < 1 || filePaths.Count > 1) + if (filePaths?.Count != 1) { return null; } From 17049280a1e1cbfa5075329ab3babf6d2116d59d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 20 Jul 2026 23:10:08 +0200 Subject: [PATCH 102/117] Rename method --- .../engine/Modules/ModuleCmdletBase.cs | 4 ++-- .../engine/Modules/ModuleIntrinsics.cs | 2 +- .../engine/Modules/PSModuleInfo.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 98a2665c4d1..57c44619525 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4817,7 +4817,7 @@ internal static string ResolveRootedFilePath(string filePath, ExecutionContext c return filePaths[0]; } - internal static string GetResolvedPath(string filePath, ExecutionContext context) + internal static string ResolveToSingleFileSystemPath(string filePath, ExecutionContext context) { Collection filePaths = null; @@ -5505,7 +5505,7 @@ internal PSModuleInfo LoadUsingExtensions(PSModuleInfo parentModule, string fileName = fileBaseName + ext; // Get the resolved file name - fileName = GetResolvedPath(fileName, Context); + fileName = ResolveToSingleFileSystemPath(fileName, Context); if (fileName == null) continue; diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 71ac49e9701..126db0abc98 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -777,7 +777,7 @@ internal static string NormalizeModuleName(string moduleNameOrPath, string relat } // Resolving the path using ModuleCmdletBase.GetResolvedPath() may rarely return null. - string normalizedPath = ModuleCmdletBase.GetResolvedPath(moduleNameOrPath, executionContext)?.TrimEnd(StringLiterals.DefaultPathSeparator); + string normalizedPath = ModuleCmdletBase.ResolveToSingleFileSystemPath(moduleNameOrPath, executionContext)?.TrimEnd(StringLiterals.DefaultPathSeparator); // If the resolved path is null, just return the fully qualified path generated before. return normalizedPath ?? Path.GetFullPath(moduleNameOrPath); diff --git a/src/System.Management.Automation/engine/Modules/PSModuleInfo.cs b/src/System.Management.Automation/engine/Modules/PSModuleInfo.cs index 4315f8bcb2b..e68ac4a8054 100644 --- a/src/System.Management.Automation/engine/Modules/PSModuleInfo.cs +++ b/src/System.Management.Automation/engine/Modules/PSModuleInfo.cs @@ -78,7 +78,7 @@ internal PSModuleInfo(string name, string path, ExecutionContext context, Sessio { if (path != null) { - string resolvedPath = ModuleCmdletBase.GetResolvedPath(path, context); + string resolvedPath = ModuleCmdletBase.ResolveToSingleFileSystemPath(path, context); // The resolved path might be null if we're building a dynamic module and the path // is just a GUID, not an actual path that can be resolved. Path = resolvedPath ?? path; From ff483fd0439200ec70449112f8cd69ab4b7f6ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 20 Jul 2026 23:17:02 +0200 Subject: [PATCH 103/117] Refactor to use new path resolution API --- .../engine/Modules/ModuleCmdletBase.cs | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 57c44619525..3d4096968f7 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4840,33 +4840,21 @@ internal static string ResolveToSingleFileSystemPath(string filePath, ExecutionC internal static Collection GetResolvedPathCollection(string filePath, ExecutionContext context) { - ProviderInfo provider = null; - Collection filePaths; - if (context != null && context.EngineSessionState != null && context.EngineSessionState.IsProviderLoaded(context.ProviderNames.FileSystem)) + if (!TryResolveToFileSystemPaths(filePath, context, out filePaths, allowNonExistingPaths: true)) { - try - { - filePaths = context.SessionState.Path.GetResolvedProviderPathFromPSPath(filePath, true /* allowNonExistentPaths */, out provider); - } - catch (Exception) + // Ported from legacy code to preserve behavior. + if (context?.EngineSessionState?.IsProviderLoaded(context.ProviderNames.FileSystem) == false) { - return null; + filePaths = [filePath]; } - // Make sure that the path is in the file system - that's all we can handle currently... - if ((provider == null) || !provider.NameEquals(context.ProviderNames.FileSystem)) + else { return null; } } - else - { - filePaths = new Collection(); - filePaths.Add(filePath); - } - // Make sure at least one file was found... if (filePaths == null || filePaths.Count < 1) { return null; From e6a1880b71d74072063cb824a00c51765f29de59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 20 Jul 2026 23:18:26 +0200 Subject: [PATCH 104/117] Rename --- .../engine/Modules/ModuleCmdletBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 3d4096968f7..0655882cb21 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -1034,7 +1034,7 @@ private IEnumerable GetModuleForRootedPaths(List modulePat } // Now we resolve the possible paths in case it is relative path/path contains wildcards - var modulePathCollection = GetResolvedPathCollection(modulePath, this.Context); + var modulePathCollection = ResolveToFileSystemPaths(modulePath, this.Context); if (modulePathCollection != null) { @@ -4838,7 +4838,7 @@ internal static string ResolveToSingleFileSystemPath(string filePath, ExecutionC return filePaths[0]; } - internal static Collection GetResolvedPathCollection(string filePath, ExecutionContext context) + internal static Collection ResolveToFileSystemPaths(string filePath, ExecutionContext context) { Collection filePaths; From abf37731885b6626b875d80453426b5fda5a1e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 20 Jul 2026 23:23:55 +0200 Subject: [PATCH 105/117] Refactor to use new path resolution API --- .../engine/Modules/ModuleCmdletBase.cs | 42 +++++-------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 0655882cb21..069697a036e 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4767,45 +4767,23 @@ internal static string ResolveRootedFilePath(string filePath, ExecutionContext c return null; } - ProviderInfo provider = null; - Collection filePaths = null; - if (context.EngineSessionState.IsProviderLoaded(context.ProviderNames.FileSystem)) + try { - try - { - filePaths = - context.SessionState.Path.GetResolvedProviderPathFromPSPath(filePath, out provider); - } - catch (ItemNotFoundException) - { - return null; - } - - // Make sure that the path is in the file system - that's all we can handle currently... - if (!provider.NameEquals(context.ProviderNames.FileSystem)) - { - // "The current provider ({0}) cannot open a file" - throw InterpreterError.NewInterpreterException( - filePath, - typeof(RuntimeException), - errorPosition: null, - "FileOpenError", - ParserStrings.FileOpenError, - provider.FullName); - } + filePaths = ResolveToFileSystemPathsThrowing(filePath, context, allowNonExistingPaths: false); + } + catch (ItemNotFoundException) + { + // Ignore. } - // Make sure at least one file was found... if (filePaths == null || filePaths.Count < 1) { return null; } - - if (filePaths.Count > 1) + else if (filePaths.Count > 1) { - // "The path resolved to more than one file; can only process one file at a time." throw InterpreterError.NewInterpreterException( filePaths, typeof(RuntimeException), @@ -4813,8 +4791,10 @@ internal static string ResolveRootedFilePath(string filePath, ExecutionContext c "AmbiguousPath", ParserStrings.AmbiguousPath); } - - return filePaths[0]; + else + { + return filePaths[0]; + } } internal static string ResolveToSingleFileSystemPath(string filePath, ExecutionContext context) From ae506ee460b4f4de1f23912a0c1ab7a3ef459c03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 20 Jul 2026 23:25:45 +0200 Subject: [PATCH 106/117] Rename --- .../commands/utility/Update-TypeData.cs | 8 ++++---- .../engine/InitialSessionState.cs | 4 ++-- .../engine/Modules/ImportModuleCommand.cs | 4 ++-- .../engine/Modules/ModuleCmdletBase.cs | 12 ++++++------ src/System.Management.Automation/utils/PathUtils.cs | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-TypeData.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-TypeData.cs index b73d8570040..559e5561354 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-TypeData.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-TypeData.cs @@ -788,7 +788,7 @@ private void ProcessTypeFiles() for (int i = prependPathTotal.Count - 1; i >= 0; i--) { string formattedTarget = string.Format(CultureInfo.InvariantCulture, target, prependPathTotal[i]); - string resolvedPath = ModuleCmdletBase.ResolveRootedFilePath(prependPathTotal[i], Context) ?? prependPathTotal[i]; + string resolvedPath = ModuleCmdletBase.ResolveToFileSystemPathIfRooted(prependPathTotal[i], Context) ?? prependPathTotal[i]; if (ShouldProcess(formattedTarget, action)) { @@ -804,7 +804,7 @@ private void ProcessTypeFiles() { if (entry.FileName != null) { - string resolvedPath = ModuleCmdletBase.ResolveRootedFilePath(entry.FileName, Context) ?? entry.FileName; + string resolvedPath = ModuleCmdletBase.ResolveToFileSystemPathIfRooted(entry.FileName, Context) ?? entry.FileName; if (fullFileNameHash.Add(resolvedPath)) { newTypes.Add(entry); @@ -819,7 +819,7 @@ private void ProcessTypeFiles() foreach (string appendPathTotalItem in appendPathTotal) { string formattedTarget = string.Format(CultureInfo.InvariantCulture, target, appendPathTotalItem); - string resolvedPath = ModuleCmdletBase.ResolveRootedFilePath(appendPathTotalItem, Context) ?? appendPathTotalItem; + string resolvedPath = ModuleCmdletBase.ResolveToFileSystemPathIfRooted(appendPathTotalItem, Context) ?? appendPathTotalItem; if (ShouldProcess(formattedTarget, action)) { @@ -1135,7 +1135,7 @@ protected override void ProcessRecord() // Resolving the file path because the path to the types file in module manifest is now specified as // ..\..\types.ps1xml which expands to C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Core\..\..\types.ps1xml - fileName = ModuleCmdletBase.ResolveRootedFilePath(fileName, Context) ?? fileName; + fileName = ModuleCmdletBase.ResolveToFileSystemPathIfRooted(fileName, Context) ?? fileName; ConstructFileToIndexMap(fileName, index, fileToIndexMap); } } diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index a6d50f47443..a0f20a26ebe 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -3494,7 +3494,7 @@ internal static void RemoveTypesAndFormats(ExecutionContext context, IList resolvedTypeFilesToRemove = new List(); foreach (var typeFile in typeFilesToRemove) { - resolvedTypeFilesToRemove.Add(ModuleCmdletBase.ResolveRootedFilePath(typeFile, context) ?? typeFile); + resolvedTypeFilesToRemove.Add(ModuleCmdletBase.ResolveToFileSystemPathIfRooted(typeFile, context) ?? typeFile); } foreach (SessionStateTypeEntry entry in context.InitialSessionState.Types) @@ -3508,7 +3508,7 @@ internal static void RemoveTypesAndFormats(ExecutionContext context, IListThe filename to resolve. /// Execution context. /// The resolved filename. - internal static string ResolveRootedFilePath(string filePath, ExecutionContext context) + internal static string ResolveToFileSystemPathIfRooted(string filePath, ExecutionContext context) { // If the path is not fully qualified or relative rooted, then // we need to do path-based resolution... diff --git a/src/System.Management.Automation/utils/PathUtils.cs b/src/System.Management.Automation/utils/PathUtils.cs index 3afea30a962..5016751501b 100644 --- a/src/System.Management.Automation/utils/PathUtils.cs +++ b/src/System.Management.Automation/utils/PathUtils.cs @@ -618,7 +618,7 @@ internal static DirectoryInfo CreateModuleDirectory(PSCmdlet cmdlet, string modu { // Even if 'moduleNameOrPath' is a rooted path, 'ResolveRootedFilePath' may return null when the path doesn't exist yet, // or when it contains wildcards but cannot be resolved to a single path. - string rootedPath = ModuleCmdletBase.ResolveRootedFilePath(moduleNameOrPath, cmdlet.Context); + string rootedPath = ModuleCmdletBase.ResolveToFileSystemPathIfRooted(moduleNameOrPath, cmdlet.Context); if (string.IsNullOrEmpty(rootedPath) && moduleNameOrPath.StartsWith('.')) { PathInfo currentPath = cmdlet.CurrentProviderLocation(cmdlet.Context.ProviderNames.FileSystem); From 7f75d1b64706dd40049c3e8870726b114f18d895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 20 Jul 2026 23:32:42 +0200 Subject: [PATCH 107/117] Add class --- .../engine/Modules/PathHandling.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/System.Management.Automation/engine/Modules/PathHandling.cs diff --git a/src/System.Management.Automation/engine/Modules/PathHandling.cs b/src/System.Management.Automation/engine/Modules/PathHandling.cs new file mode 100644 index 00000000000..25cfe3159b1 --- /dev/null +++ b/src/System.Management.Automation/engine/Modules/PathHandling.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace System.Management.Automation.Internal +{ + internal static class PathHandling + { + public static string NormalizeDirectorySeparators(string path) + { + return path.Replace(StringLiterals.AlternatePathSeparator, StringLiterals.DefaultPathSeparator); + } + } +} From 415d6bf0a49fff495f2971b87f9849bf377cd54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 20 Jul 2026 23:35:54 +0200 Subject: [PATCH 108/117] Refactor to use new API --- .../engine/Modules/ModuleIntrinsics.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 126db0abc98..1afcbcf7c18 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -766,7 +766,7 @@ internal static string NormalizeModuleName(string moduleNameOrPath, string relat // Ensure OS default directory separators because // - Path.IsPathRooted("\some\path") returns false on *nix, and // - Path.IsPathRooted("/some/path") return false on Windows. - moduleNameOrPath = moduleNameOrPath.Replace(StringLiterals.AlternatePathSeparator, StringLiterals.DefaultPathSeparator); + moduleNameOrPath = PathHandling.NormalizeDirectorySeparators(moduleNameOrPath); // On Windows: // - Path.IsFullyQualified("\default\root") returns false, but From cf604b4f8e83a12df6afadb842e020f602450c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 21 Jul 2026 23:07:43 +0200 Subject: [PATCH 109/117] Document --- .../engine/Modules/ModuleCmdletBase.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 45917d1bd37..ef0b4a9cb2e 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4797,6 +4797,18 @@ internal static string ResolveToFileSystemPathIfRooted(string filePath, Executio } } + /// + /// Resolves to a single file system path using the file system provider. + /// + /// + /// + /// Path resolution is considered successful if resolves to exactly + /// one file system path. + /// + /// + /// The file path to resolve. + /// The execution context. + /// The resolved, fully qualified file system path if resolution succeeded; otherwise . internal static string ResolveToSingleFileSystemPath(string filePath, ExecutionContext context) { Collection filePaths = null; From 3060a4b8cb68f2c1f466ece45866de20c6937b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 21 Jul 2026 23:08:27 +0200 Subject: [PATCH 110/117] Rename --- .../engine/Modules/ModuleCmdletBase.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index ef0b4a9cb2e..b97849b18d7 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4798,7 +4798,7 @@ internal static string ResolveToFileSystemPathIfRooted(string filePath, Executio } /// - /// Resolves to a single file system path using the file system provider. + /// Resolves to a single file system path using the file system provider. /// /// /// @@ -4806,19 +4806,19 @@ internal static string ResolveToFileSystemPathIfRooted(string filePath, Executio /// one file system path. /// /// - /// The file path to resolve. + /// The file path to resolve. /// The execution context. /// The resolved, fully qualified file system path if resolution succeeded; otherwise . - internal static string ResolveToSingleFileSystemPath(string filePath, ExecutionContext context) + internal static string ResolveToSingleFileSystemPath(string path, ExecutionContext context) { Collection filePaths = null; - if (!TryResolveToFileSystemPaths(filePath, context, out filePaths, allowNonExistingPaths: true)) + if (!TryResolveToFileSystemPaths(path, context, out filePaths, allowNonExistingPaths: true)) { // Ported from legacy code to preserve behavior. if (context?.EngineSessionState?.IsProviderLoaded(context.ProviderNames.FileSystem) != true) { - filePaths = [filePath]; + filePaths = [path]; } } From ebfec897020fd4b3ec0e9a4b309234fd658eb212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 21 Jul 2026 23:09:46 +0200 Subject: [PATCH 111/117] Rename --- .../engine/Modules/ModuleCmdletBase.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index b97849b18d7..947a7884114 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4811,23 +4811,23 @@ internal static string ResolveToFileSystemPathIfRooted(string filePath, Executio /// The resolved, fully qualified file system path if resolution succeeded; otherwise . internal static string ResolveToSingleFileSystemPath(string path, ExecutionContext context) { - Collection filePaths = null; + Collection paths = null; - if (!TryResolveToFileSystemPaths(path, context, out filePaths, allowNonExistingPaths: true)) + if (!TryResolveToFileSystemPaths(path, context, out paths, allowNonExistingPaths: true)) { // Ported from legacy code to preserve behavior. if (context?.EngineSessionState?.IsProviderLoaded(context.ProviderNames.FileSystem) != true) { - filePaths = [path]; + paths = [path]; } } - if (filePaths?.Count != 1) + if (paths?.Count != 1) { return null; } - return filePaths[0]; + return paths[0]; } internal static Collection ResolveToFileSystemPaths(string filePath, ExecutionContext context) From 9b3a71b22a712b8fb3217dc0a2baedebf1cc7aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 21 Jul 2026 23:25:46 +0200 Subject: [PATCH 112/117] Remove comment --- .../engine/Modules/ModuleIntrinsics.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 1afcbcf7c18..251e830c5ff 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -776,7 +776,6 @@ internal static string NormalizeModuleName(string moduleNameOrPath, string relat moduleNameOrPath = Path.Join(relativeTo, moduleNameOrPath); } - // Resolving the path using ModuleCmdletBase.GetResolvedPath() may rarely return null. string normalizedPath = ModuleCmdletBase.ResolveToSingleFileSystemPath(moduleNameOrPath, executionContext)?.TrimEnd(StringLiterals.DefaultPathSeparator); // If the resolved path is null, just return the fully qualified path generated before. From c15876cbb61df7bcd5eec97750bbdd00da580eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 21 Jul 2026 23:37:27 +0200 Subject: [PATCH 113/117] Document --- .../engine/Modules/ModuleCmdletBase.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 947a7884114..e184d50ae6d 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4830,6 +4830,18 @@ internal static string ResolveToSingleFileSystemPath(string path, ExecutionConte return paths[0]; } + /// + /// Resolves to file system paths using the file system provider. + /// + /// + /// + /// Path resolution is considered successful if resolves to + /// at least one file system path. + /// + /// + /// The path to resolve. + /// The execution context. + /// The resolved file system paths if path resolution succeeded; otherwise . internal static Collection ResolveToFileSystemPaths(string filePath, ExecutionContext context) { Collection filePaths; From 8f5a78cdcd7c8d8ccdb10d8335804dd684d01ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 21 Jul 2026 23:37:53 +0200 Subject: [PATCH 114/117] Rename --- .../engine/Modules/ModuleCmdletBase.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index e184d50ae6d..6b0c36561b0 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4831,7 +4831,7 @@ internal static string ResolveToSingleFileSystemPath(string path, ExecutionConte } /// - /// Resolves to file system paths using the file system provider. + /// Resolves to file system paths using the file system provider. /// /// /// @@ -4839,19 +4839,19 @@ internal static string ResolveToSingleFileSystemPath(string path, ExecutionConte /// at least one file system path. /// /// - /// The path to resolve. + /// The path to resolve. /// The execution context. /// The resolved file system paths if path resolution succeeded; otherwise . - internal static Collection ResolveToFileSystemPaths(string filePath, ExecutionContext context) + internal static Collection ResolveToFileSystemPaths(string path, ExecutionContext context) { Collection filePaths; - if (!TryResolveToFileSystemPaths(filePath, context, out filePaths, allowNonExistingPaths: true)) + if (!TryResolveToFileSystemPaths(path, context, out filePaths, allowNonExistingPaths: true)) { // Ported from legacy code to preserve behavior. if (context?.EngineSessionState?.IsProviderLoaded(context.ProviderNames.FileSystem) == false) { - filePaths = [filePath]; + filePaths = [path]; } else { From 9b2667b4ab91d098857df2bb92f9ef8a2459d9d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 21 Jul 2026 23:38:09 +0200 Subject: [PATCH 115/117] Rename --- .../engine/Modules/ModuleCmdletBase.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 6b0c36561b0..2806d8277ac 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4844,14 +4844,14 @@ internal static string ResolveToSingleFileSystemPath(string path, ExecutionConte /// The resolved file system paths if path resolution succeeded; otherwise . internal static Collection ResolveToFileSystemPaths(string path, ExecutionContext context) { - Collection filePaths; + Collection paths; - if (!TryResolveToFileSystemPaths(path, context, out filePaths, allowNonExistingPaths: true)) + if (!TryResolveToFileSystemPaths(path, context, out paths, allowNonExistingPaths: true)) { // Ported from legacy code to preserve behavior. if (context?.EngineSessionState?.IsProviderLoaded(context.ProviderNames.FileSystem) == false) { - filePaths = [path]; + paths = [path]; } else { @@ -4859,12 +4859,12 @@ internal static Collection ResolveToFileSystemPaths(string path, Executi } } - if (filePaths == null || filePaths.Count < 1) + if (paths == null || paths.Count < 1) { return null; } - return filePaths; + return paths; } /// From df8f8aff1a7d6e7c63c8fe44e91f8a9b89409d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Tue, 21 Jul 2026 23:39:54 +0200 Subject: [PATCH 116/117] Edit --- .../engine/Modules/ModuleCmdletBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 2806d8277ac..c78d06780e8 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4841,7 +4841,7 @@ internal static string ResolveToSingleFileSystemPath(string path, ExecutionConte /// /// The path to resolve. /// The execution context. - /// The resolved file system paths if path resolution succeeded; otherwise . + /// The resolved, fully qualified file system paths if path resolution succeeded; otherwise . internal static Collection ResolveToFileSystemPaths(string path, ExecutionContext context) { Collection paths; From d203872e236eac9516fa460049abf37e838b958b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Thu, 23 Jul 2026 07:15:49 +0200 Subject: [PATCH 117/117] BREAKING: Correctly resolve relative- and home-rooted paths Relative-rooted paths such as: .\foo.psm1 ..\foo.psm1 and home-rooted paths such as: ~\foo.psm1 are now fully resolved via $executionContext.SessionState.Path.GetResolvedProviderPathFromPSPath() instead of joining them with the working directory first, because GetResolvedProviderPathFromPSPath() already joins relative paths with the working directory as needed. Before this commit, ~\foo.psm1 was resolved to $pwd\~\foo.psm1. After this commit, ~\foo.psm1 correctly resolves to $HOME\foo.psm1. A path like .\~\foo.psm1 still resolves to $pwd\~\foo.psm1. --- .../engine/Modules/ModuleIntrinsics.cs | 22 ++++++++++--------- .../Get-Module.Tests.ps1 | 8 +++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 251e830c5ff..cec9b9a2de5 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -768,18 +768,20 @@ internal static string NormalizeModuleName(string moduleNameOrPath, string relat // - Path.IsPathRooted("/some/path") return false on Windows. moduleNameOrPath = PathHandling.NormalizeDirectorySeparators(moduleNameOrPath); - // On Windows: - // - Path.IsFullyQualified("\default\root") returns false, but - // - Path.IsPathRooted("\default\root") returns true. - if (!Path.IsPathRooted(moduleNameOrPath)) - { - moduleNameOrPath = Path.Join(relativeTo, moduleNameOrPath); - } - string normalizedPath = ModuleCmdletBase.ResolveToSingleFileSystemPath(moduleNameOrPath, executionContext)?.TrimEnd(StringLiterals.DefaultPathSeparator); - // If the resolved path is null, just return the fully qualified path generated before. - return normalizedPath ?? Path.GetFullPath(moduleNameOrPath); + if (normalizedPath != null) + { + return normalizedPath; + } + else if (Path.IsPathRooted(moduleNameOrPath)) + { + return Path.GetFullPath(moduleNameOrPath); + } + else + { + return Path.GetFullPath(Path.Join(relativeTo, moduleNameOrPath)); + } } /// diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 index e4855255df3..f73eddc4949 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Module.Tests.ps1 @@ -500,13 +500,12 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum } Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argument is home-rooted' -Tags "CI" { - It 'wrongly does not expand ''~'' to $HOME' { + It 'expands ''~'' to $HOME' { $path = Join-Path ~ missing.psm1 Test-Path $path | Should -BeFalse Get-Module -ListAvailable -Name $path | ForEach-Object Path | Should -BeExactly (Join-Path $HOME missing.psm1) - # TODO: This is a bug. - Get-Module -ListAvailable -FullyQualifiedName $path | ForEach-Object Path | Should -BeExactly (Join-Path $pwd $path) + Get-Module -ListAvailable -FullyQualifiedName $path | ForEach-Object Path | Should -BeExactly (Join-Path $HOME missing.psm1) } It 'wrongly returns module information instead of $null or error for missing script module' { @@ -564,10 +563,9 @@ Describe 'Get-Module -ListAvailable -(FullyQualifiedName|Name) when argum $actual | Should -HaveCount 1 $actual[0].Path | Should -BeExactly (Join-Path $HOME loose.psm1) - # TODO: This is a bug. $actual = Get-Module -ListAvailable -FullyQualifiedName $path $actual | Should -HaveCount 1 - $actual[0].Path | Should -BeExactly (Join-Path $pwd $path) + $actual[0].Path | Should -BeExactly (Join-Path $HOME loose.psm1) } }