about_PSModulePath

简短说明

本文介绍了 $env:PSModulePath 环境变量的用途和用法。

长说明

$env:PSModulePath 环境变量包含文件夹位置列表,可以在其中搜索来查找模块和资源。 PowerShell 以递归方式搜索每个文件夹中的模块(.psd1.psm1)文件。

Install-Module 有一个 Scope 参数,用于指定是为当前用户还是为所有用户安装该模块。 有关详细信息,请参阅 Install-Module

默认情况下,分配给 $env:PSModulePath 的有效位置为:

  • 系统范围的位置:这些文件夹包含 PowerShell 附带的模块。 这些模块存储在 $PSHOME\Modules 文件夹中。

    • 在 Windows 上,安装在 AllUsers 范围内的模块存储在 $env:ProgramFiles\WindowsPowerShell\Modules 中。
    • 在非 Windows 系统上,安装在 AllUsers 范围内的模块存储在 /usr/local/share/powershell/Modules 中。
  • 用户安装的模块:在 Windows 上,安装在 CurrentUser 范围内的模块通常存储在 $HOME\Documents\WindowsPowerShell\Modules 文件夹中。 Documents 文件夹的具体位置因 Windows 版本以及使用文件夹重定向的时机而异。 此外,Microsoft OneDrive 可以更改 Documents 文件夹的位置。 你可以使用以下命令验证 Documents 文件夹的位置:[Environment]::GetFolderPath('MyDocuments')

    在非 Windows 系统上,安装在 CurrentUser 范围内的模块存储在 $HOME/.local/share/powershell/Modules 文件夹中。

  • 特定于应用程序的模块:安装程序可以将模块安装在其他目录中,例如 Windows 上的 Program Files 文件夹。 安装程序包可能会也可能不会将位置追加到 $env:PSModulePath

PowerShell PSModulePath 构造

每次 PowerShell 启动时都会构造 $env:PSModulePath 的值。 该值因 PowerShell 版本及其启动方式而异。

Windows PowerShell 启动

Windows PowerShell 使用以下逻辑在启动时构造 PSModulePath

  • 如果 PSModulePath 不存在,请合并 CurrentUser、AllUsers$PSHOME 模块路径
  • 如果 PSModulePath 存在:
    • 如果 PSModulePath 包含 $PSHOME 模块路径:
      • AllUsers 模块路径插入到 $PSHOME 模块路径之前
    • 否则:
      • 由于用户故意删除了 $PSHOME 位置,因此只需按定义使用 PSModulePath

仅当 User 范围 $env:PSModulePath 不存在时,才会为 CurrentUser 模块路径添加前缀。 否则,将按定义使用 User 范围 $env:PSModulePath

PowerShell 7 启动

在 Windows 中,对于大多数环境变量,如果存在用户范围的变量,则新进程仅使用该值,即使存在同名的计算机范围的变量。

在 PowerShell 7 中,PSModulePath 的处理方式类似于在 Windows 上处理 Path 环境变量的方式。 在 Windows 上,Path 与其他环境变量的处理方式不同。 启动进程时,Windows 会将用户范围的 Path 与计算机范围的 Path 组合在一起。

  • 检索用户范围的 PSModulePath
  • 与进程继承的 PSModulePath 环境变量进行比较
    • 如果两者相同:
      • 环境变量的Path语义之后,将 AllUsers PSModulePath 追加到末尾
      • Windows System32 路径来自计算机定义的 PSModulePath,因此无需显式添加
    • 如果不同,则视为用户显式修改了它,但不追加 AllUsers PSModulePath
  • 按该顺序以 PS7 用户、系统和 $PSHOME 路径为前缀
    • 如果 powershell.config.json 包含用户范围的 PSModulePath,请使用该路径,而不是用户的默认路径
    • 如果 powershell.config.json 包含系统范围的 PSModulePath,请使用该路径,而不是系统的默认路径

Unix 系统没有区分用户环境变量和系统环境变量。 PSModulePath 是继承的,如果尚未定义,则特定于 PS7 的路径会带有前缀。

从 PowerShell 7 启动 Windows PowerShell

对于此讨论,Windows PowerShell 意味着 powershell.exepowershell_ise.exe

$env:PSModulePath 的值复制到 WinPSModulePath,并进行以下修改:

  • 删除 PS7 用户模块路径
  • 删除 PS7 系统模块路径
  • 删除 PS7 $PSHOME 模块路径

删除 PS7 路径,使 PS7 模块不会在 Windows PowerShell 中加载。 WinPSModulePath 值在启动 Windows PowerShell 时使用。

从 Windows PowerShell 启动 PowerShell 7

PowerShell 7 启动按原样继续,添加了 Windows PowerShell 所添加的继承路径。 由于特定于 PS7 的路径带有前缀,因此不存在功能问题。

模块搜索行为

PowerShell 以递归方式搜索 PSModulePath 中的每个文件夹以查找模块(.psd1.psm1)文件。 此搜索模式允许将同一模块的多个版本安装在不同的文件夹中。 例如:

    Directory: C:\Program Files\WindowsPowerShell\Modules\PowerShellGet

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----           8/14/2020  5:56 PM                1.0.0.1
d----           9/13/2019  3:53 PM                2.1.2

默认情况下,当发现多个版本时,PowerShell 会加载模块的最高版本号。 若要加载特定版本,请将 Import-Module 与 FullyQualifiedName 参数结合使用。 有关详细信息,请参阅 Import-Module

修改 PSModulePath

对于大多数情况,你应该在默认模块位置安装模块。 但是,你可能需要更改 PSModulePath 环境变量的值。

例如,若要将当前会话的 C:\Program Files\Fabrikam\Modules 目录临时添加到 $env:PSModulePath,请键入:

$Env:PSModulePath = $Env:PSModulePath+";C:\Program Files\Fabrikam\Modules"

命令中的分号 (;) 用于分隔列表中的新路径和新路径之前的路径。 在非 Windows 平台上,由冒号 (:) 分隔环境变量中的路径位置。

在非 Windows 系统中修改 PSModulePath

若要更改非 Windows 环境中每个会话的 PSModulePath 的值,请将上一个命令添加到 PowerShell 配置文件。

在 Windows 中修改 PSModulePath

若要更改每个会话中的 PSModulePath 的值,请编辑存储 PSModulePath 值的注册表项。 PSModulePath 值作为未展开的字符串存储在注册表中。 为了避免将 PSModulePath 值永久保存为展开的字符串,请对子项使用 GetValue 方法并直接编辑该值。

以下示例将 C:\Program Files\Fabrikam\Modules 路径添加到 PSModulePath 环境变量的值,而不展开未展开的字符串。

$key = (Get-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager').OpenSubKey('Environment', $true)
$path = $key.GetValue('PSModulePath','','DoNotExpandEnvironmentNames')
$path += ';%ProgramFiles%\Fabrikam\Modules'
$key.SetValue('PSModulePath',$path,[Microsoft.Win32.RegistryValueKind]::ExpandString)

若要将路径添加到用户设置,请将注册表提供程序从 HKLM:\ 更改为 HKCU:\

$key = (Get-Item 'HKCU:\').OpenSubKey('Environment', $true)
$path = $key.GetValue('PSModulePath','','DoNotExpandEnvironmentNames')
$path += ';%ProgramFiles%\Fabrikam\Modules'
$key.SetValue('PSModulePath',$path,[Microsoft.Win32.RegistryValueKind]::ExpandString)

另请参阅