Prerequisites
Steps to reproduce
Get-Module -ListAvailable -FullyQualifiedName module resolution feels inconsistent
Overview
This issue is about discovering local modules via:
Get-Module -ListAvailable FullyQualifiedName <path>
Get-Module -ListAvailable FullyQualifiedName <module-spec>
The experience is rather suprising often and feels buggy. If the behavior is intended, then the documentation should be improved.
Description
The code base considers paths such as
~\foo.psm1
.\foo.psm1
..\foo.psm1
...to be relative rooted. Paths for which Path.IsRooted() returns true are referred to as rooted. There's no mention of fully qualified paths that I could see. Paths that are not rooted/relative-rooted sometimes are rooted at the working directory before resolution.
Mostly the ExecutionContext is used to resolve PS paths to file system paths, but this is done in seemingly inconsistent ways. When everything else fails, sometimes the code base resorts to Path.Join() or Path.Combine() together with the working directory to resolve a path, even if it doesn't exist. If the point is locating modules in the file system, resolving to non-existing paths looks like a bug.
As a consequence of the inconsistent path resolution just described, Get-Module will return PSModuleInfos for modules that don't exist, because a PS path was (wrongly) resolved to a non-existing file system path.
The case where module resolution is more consistent is when the module extension is invalid (an error occurs), but even then there's a case that behaves differently to the rest for no good reason.
The cmdlet's documentation seems inaccurate and incomplete.
A summary of behaviors follows.
| Path |
PSModuleInfo |
Actual |
Expected |
Status |
~\exists.psm1 |
yes/unexpected |
CWD\~\exists.psm1 |
$HOME\exists.psm1 |
❌ |
~\missing.psm1 |
yes/unexpected |
CWD\~\missing.psm1 |
Write-Error |
❌ |
~\invalid.xxx |
no |
Write-Error |
Write-Error |
✅ |
.\exists.psm1 |
yes |
CWD\exists.psm1 |
CWD\exists.psm1 |
✅ |
.\missing.psm1 |
yes/unexpected |
CWD\missing.psm1 |
Write-Error |
❌ |
.\invalid.xxx |
no |
Write-Error |
Write-Error |
✅ |
..\exists.psm1 |
yes |
CWD\..\exists.psm1 |
CWD\..\exists.psm1 |
✅ |
..\missing.psm1 |
yes/unexpected |
CWD\..\missing.psm1 |
Write-Error |
❌ |
..\invalid.xxx |
no |
Write-Error |
Write-Error |
✅ |
exists.psm1 |
no |
$null |
CWD\exists.psm1 |
❌ |
missing.psm1 |
no |
$null |
Write-Error |
❌ |
invalid.xxx |
no |
$null |
Write-Error |
❌ |
C:\a\b\exists.psm1 |
yes |
C:\a\b\exists.psm1 |
C:\a\b\exists.psm1 |
✅ |
C:\a\b\missing.psm1 |
yes/unexpected |
C:\a\b\missing.psm1 |
Write-Error |
❌ |
C:\a\b\invalid.xxx |
no |
Write-Error |
Write-Error |
✅ |
Inconsistent or poorly documented behaviors:
~ is never expanded to $HOME
- relative pahts as in
foo.psm1 are not resolved relative to the working directory
- module specs are returned for non-existing file system paths
- non-existing file system paths do not cause an error to be written to the pipeline
Expected changes
- Fix
Get-Module so that it behaves in less surprising ways.
- Or, improve documentation to explain seemingly inconsistent behaviors.
Expected behavior
Actual behavior
Error details
Environment data
Name Value
---- -----
PSVersion 7.6.4
PSEdition Core
GitCommitId 7.6.4
OS Microsoft Windows 10.0.26220
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.4
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
---
Also tried building from source.
Visuals
No response
Prerequisites
Steps to reproduce
Get-Module -ListAvailable -FullyQualifiedNamemodule resolution feels inconsistentOverview
This issue is about discovering local modules via:
Get-Module -ListAvailable FullyQualifiedName <path>Get-Module -ListAvailable FullyQualifiedName <module-spec>The experience is rather suprising often and feels buggy. If the behavior is intended, then the documentation should be improved.
Description
The code base considers paths such as
~\foo.psm1.\foo.psm1..\foo.psm1...to be relative rooted. Paths for which
Path.IsRooted()returnstrueare referred to asrooted. There's no mention of fully qualified paths that I could see. Paths that are not rooted/relative-rooted sometimes are rooted at the working directory before resolution.Mostly the
ExecutionContextis used to resolve PS paths to file system paths, but this is done in seemingly inconsistent ways. When everything else fails, sometimes the code base resorts toPath.Join()orPath.Combine()together with the working directory to resolve a path, even if it doesn't exist. If the point is locating modules in the file system, resolving to non-existing paths looks like a bug.As a consequence of the inconsistent path resolution just described,
Get-Modulewill returnPSModuleInfos for modules that don't exist, because a PS path was (wrongly) resolved to a non-existing file system path.The case where module resolution is more consistent is when the module extension is invalid (an error occurs), but even then there's a case that behaves differently to the rest for no good reason.
The cmdlet's documentation seems inaccurate and incomplete.
A summary of behaviors follows.
~\exists.psm1CWD\~\exists.psm1$HOME\exists.psm1~\missing.psm1CWD\~\missing.psm1Write-Error~\invalid.xxxWrite-ErrorWrite-Error.\exists.psm1CWD\exists.psm1CWD\exists.psm1.\missing.psm1CWD\missing.psm1Write-Error.\invalid.xxxWrite-ErrorWrite-Error..\exists.psm1CWD\..\exists.psm1CWD\..\exists.psm1..\missing.psm1CWD\..\missing.psm1Write-Error..\invalid.xxxWrite-ErrorWrite-Errorexists.psm1$nullCWD\exists.psm1missing.psm1$nullWrite-Errorinvalid.xxx$nullWrite-ErrorC:\a\b\exists.psm1C:\a\b\exists.psm1C:\a\b\exists.psm1C:\a\b\missing.psm1C:\a\b\missing.psm1Write-ErrorC:\a\b\invalid.xxxWrite-ErrorWrite-ErrorInconsistent or poorly documented behaviors:
~is never expanded to$HOMEfoo.psm1are not resolved relative to the working directoryExpected changes
Get-Moduleso that it behaves in less surprising ways.Expected behavior
See above.Actual behavior
See above.Error details
Environment data
Visuals
No response