Which version does PS actually use in this scenario?
The most recently imported version takes precedence, which the output of Get-Module
indicates in reverse order of precedence (as of PowerShell Core 7.2.0-preview.5); that is, the last version listed in Get-Module
output for a given module is the one in effect (for commands of the same name).
For a given command, you can use Get-Command
to see what module (version) it comes from.[1]
Caveat: The most recently imported version only takes precedence in the sense that it shadows commands of the same name from previously imported versions. Therefore, if a previously imported version has additional commands not defined (anymore) by the most recently imported version, they are still in effect.
Is there an easy way to ensure a specific version is being used, short of looping over all other versions and removing them?
If you want to ensure that no other versions are loaded, use Remove-Module <name>
, which removes all versions of the module with the given name from the session.
By contrast, if you wanted to unload a specific version, you'd pass a fully qualified module name to Remove-Module
's -FullyQualifiedName
parameter; e.g.:
Remove-Module -FullyQualifiedName @{ ModuleName = 'MyModule'; RequiredVersion = '1.0.28' }
Note the use of the RequiredVersion
key to specify the exact version to unload; by contrast, using key ModuleVersion
would unload the given version and all higher ones.
Also note:
As noted in Cpt.Whale's helpful answer:
- See caveats re auto-loading modules below.
- You can similarly use
-FullyQualifiedName
or -RequiredVersion
with Import-Module
for version-specific importing.
- You can choose to import selectively, i.e. a subset of a given module's exports, using the
-Cmdlet
, -Function
, -Alias
and -Variable
parameters.
- Note: Using any of these parameters means that you must then explicitly specify all exports you want to import, across the relevant parameters; e.g., if you use
-Alias @()
in order to effectively exclude exported aliases from import, you must also use the -Cmdlet
/ -Function
parameter to specify what cmdlets / functions you do want to import; however, you can use -Cmdlet *
/ -Function *
to select them all.
Caveats re auto-loading modules - i.e. those placed in one of the directories listed in $env:PSModulePath
, as is typical:
If you have removed all versions of a module with Remove-Module
but at least one version is auto-loading, using any of its exported commands later triggers its (re)import, with all its exports getting imported.
Similarly, if you have imported a specific version of a module and a (different) version of the same module is (also) auto-loading, using an exported command that is exclusive to the latter triggers the latter's auto-loading, and thereby implicitly shadows those exports that have the same name from the originally imported, specific version
The risk of that happening increases if you have used -Cmdlet
, -Function
, -Alias
and -Variable
for selective importing of the originally imported, specific version, because then use of any of the non-imported exports that are also present in the auto-loading version trigger auto-loading of the latter.
A simple example: Say you manually import version 1.0
of module Foo
in order to load the Get-Foo
cmdlet (Import-Module Foo -RequiredVersion 1.0
). However, the auto-loading version of Foo
is version 2.0
, and also has a Set-Foo
command. When you call Set-Foo
later, version 2.0
is implicitly (automatically) imported, and its Get-Foo
implementation now shadows the one from the originally imported 1.0
version of Foo
.
[1] Note that you can even get a reference to a currently shadowed command by requesting it via its specific module version using the -FullyQualifiedModule
parameter (e.g.
Get-Command Get-Foo -FullyQualifiedModule @{ ModuleName='Foo'; RequiredVersion='1.0.28' }
), which you can then invoke with &
, the call operator. However, due to the bug detailed in GitHub issue #15298, present as of PowerShell Core 7.2.0-preview.5, this only works if the targeted module version was explicitly imported first (e.g., Import-Module Foo -RequiredVersion 1.0.28
).