导入多个版本的 Powershell 模块会加载所有版本吗?

FBr*_*t87 7 powershell powershell-7.0

导入多个版本的模块(这是PS7):

Import-Module -Name MyModule -RequiredVersion 1.0.28
Import-Module -Name MyModule -RequiredVersion 1.0.29
Run Code Online (Sandbox Code Playgroud)

将两个版本加载到您的会话中:

Get-Module -Name MyModule 
Run Code Online (Sandbox Code Playgroud)

输出:

ModuleType Version    PreRelease Name
---------- -------    ---------- ---- 
Script     1.0.28                MyModule
Script     1.0.29                MyModule
Run Code Online (Sandbox Code Playgroud)

当您尝试编写 CI/CD 脚本时,这会变得非常混乱,因为有人可能在本地加载了多个版本。就我而言,我想确保在继续之前加载特定版本。

在这种情况下,PS实际使用哪个版本?是最后加载的版本而不是最高版本吗?

有没有一种简单的方法来确保使用特定版本,而不需要循环所有其他版本并删除它们?

mkl*_*nt0 9

在这种情况下,PS实际使用哪个版本?

最近导入的版本优先,其输出以相反的优先顺序Get-Module指示(从 PowerShell Core 7.2.0-preview.5 开始);也就是说,给定模块的输出中列出的最后一个版本有效的版本(对于同名的命令)。Get-Module

对于给定的命令,您可以使用Get-Command它来查看它来自哪个模块(版本)。[1]

警告:最近导入的版本仅在它隐藏以前导入的版本中的同名命令的意义上优先。因此,如果先前导入的版本具有最近导入的版本(不再)定义的其他命令,则它们仍然有效。


有没有一种简单的方法来确保使用特定版本,而不需要循环所有其他版本并删除它们?

如果要确保不加载其他版本,请使用Remove-Module <name>,这会从会话中删除具有给定名称的模块的所有版本。

相比之下,如果您想卸载特定版本,则可以将完全限定的模块名称传递给 的Remove-Module参数-FullyQualifiedName;例如:

Remove-Module -FullyQualifiedName @{ ModuleName = 'MyModule'; RequiredVersion = '1.0.28' }
Run Code Online (Sandbox Code Playgroud)

注意使用RequiredVersionkey 来指定要卸载的确切版本;相反,使用 keyModuleVersion将卸载给定版本和所有更高版本

另请注意:

  • 正如Cpt.Whale 的有用回答所述:

    • 请参阅下面有关自动加载模块的注意事项
    • 您可以类似地使用-FullyQualifiedName-RequiredVersionwithImport-Module进行特定于版本的导入。
    • 您可以选择使用、和参数选择性导入,即给定模块导出的子集。 -Cmdlet-Function-Alias-Variable
      • 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).