about_PSModulePath
Short description
This article describes the purpose and usage of the $env:PSModulePath
environment variable.
Long description
The $env:PSModulePath
environment variable contains a list of folder
locations. PowerShell recursively searches each folder for module (.psd1
or
.psm1
) files.
By default, the effective locations assigned to $env:PSModulePath
are:
- Modules installed in the CurrentUser scope:
- On Windows, these modules are stored in
$HOME\Documents\PowerShell\Modules
. The specific location of theDocuments
folder varies by version of Windows and when you use folder redirection. Also, Microsoft OneDrive can change the location of yourDocuments
folder. To verify the location of yourDocuments
folder, run use the following command:[Environment]::GetFolderPath('MyDocuments')
. - On non-Windows systems, these modules are stored in the
$HOME/.local/share/powershell/Modules
folder.
- On Windows, these modules are stored in
- Modules installed in the AllUsers scope:
- On Windows, these modules are stored in
$env:ProgramFiles\PowerShell\Modules
. - On non-Windows systems, these modules are stored in
/usr/local/share/powershell/Modules
.
- On Windows, these modules are stored in
- Modules that ship with PowerShell are stored in
$PSHOME\Modules
.
Note
Applications that include PowerShell modules can install modules in other
directories on Windows, such as the Program Files
folder. The installer
package might not append the location to the $env:PSModulePath
.
The default locations for Windows PowerShell 5.1 are different from PowerShell 7.
- Modules installed in the CurrentUser scope are stored in
$HOME\Documents\WindowsPowerShell\Modules
. - Modules installed in the AllUsers scope are stored in
$env:ProgramFiles\WindowsPowerShell\Modules
. - Modules that ship with Windows PowerShell stored in
$PSHOME\Modules
, which is$env:SystemRoot\System32\WindowsPowerShell\1.0\Modules
.
PowerShell PSModulePath construction
The value of $env:PSModulePath
is constructed each time PowerShell starts.
The value varies by version of PowerShell and how you launched it.
Windows PowerShell startup
Windows PowerShell uses the following logic to construct the PSModulePath
at
startup:
- If
PSModulePath
doesn't exist, combine CurrentUser, AllUsers, and the$PSHOME
modules paths - If
PSModulePath
does exist:- If
PSModulePath
contains$PSHOME
modules path:- AllUsers modules path is inserted before
$PSHOME
modules path
- AllUsers modules path is inserted before
- else:
- Just use
PSModulePath
as defined since the user deliberately removed the$PSHOME
location
- Just use
- If
The CurrentUser module path is prefixed only if the User scope
$env:PSModulePath
doesn't exist. Otherwise, the User scope
$env:PSModulePath
is used as defined.
PowerShell 7 startup
In Windows, for most environment variables, if the User-scoped variable exists, a new process uses that value only, even when a Machine-scoped variable of the same name exists. The path environment variables are treated differently.
On Windows, PSModulePath
is treated similar to how the Path
environment variable is treated. Path
is treated differently from other
environment variables. When a process is started, Windows combines the
User-scoped Path
with the Machine-scoped Path
.
- Retrieve the User-scoped
PSModulePath
- Compare to process inherited
PSModulePath
environment variable- If the same:
- Append the AllUsers
PSModulePath
to the end following the semantics of thePath
environment variable - The Windows
System32
path comes from the machine definedPSModulePath
so doesn't need to be added explicitly
- Append the AllUsers
- If different, treat as though user explicitly modified it and don't append
AllUsers
PSModulePath
- If the same:
- Prefix with PS7 User, System, and
$PSHOME
paths in that order- If
powershell.config.json
contains a user scopedPSModulePath
, use that instead of the default for the user - If
powershell.config.json
contains a system scopedPSModulePath
, use that instead of the default for the system
- If
Non-Windows systems don't have a separation of User and System environment
variables. PSModulePath
is inherited and the PS7-specific paths are prefixed
if not already defined.
Starting Windows PowerShell from PowerShell 7
For this discussion, Windows PowerShell means both powershell.exe
and
powershell_ise.exe
.
The value of $env:PSModulePath
is copied to WinPSModulePath
with the
following modifications:
- Remove PS7 the User module path
- Remove PS7 the System module path
- Remove PS7 the
$PSHOME
module path
The PS7 paths are removed so that PS7 modules don't get loaded in Windows
PowerShell. The WinPSModulePath
value is used when starting Windows
PowerShell.
Starting PowerShell 7 from Windows PowerShell
The PowerShell 7 startup continues as-is with the addition of inheriting paths that Windows PowerShell added. Since the PS7-specific paths are prefixed, there's no functional issue.
Module search behavior
PowerShell recursively searches each folder in the PSModulePath for module
(.psd1
or .psm1
) files. This search pattern allows multiple versions of the
same module to be installed in different folders. For example:
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
By default, PowerShell loads the highest version number of a module when
multiple versions are found. To load a specific version, use Import-Module
with the FullyQualifiedName parameter. For more information, see
Import-Module.
Modifying PSModulePath
For most situations, you should be installing modules in the default module
locations. However, you might need to change the value of the PSModulePath
environment variable.
For example, to temporarily add the C:\Program Files\Fabrikam\Modules
directory to $env:PSModulePath
for the current session, type:
$Env:PSModulePath = $Env:PSModulePath+";C:\Program Files\Fabrikam\Modules"
The semi-colon (;
) in the command separates the new path from the path that
precedes it in the list. On non-Windows platforms, the colon (:
) separates
the path locations in the environment variable.
Modifying PSModulePath in non-Windows
To change the value of PSModulePath
for every session in a non-Windows
environment, add the previous command to your PowerShell profile.
Modifying PSModulePath in Windows
To change the value of PSModulePath
in every session, edit the registry key
storing the PSModulePath
values. The PSModulePath
values are stored in the
registry as unexpanded strings. To avoid permanently saving the
PSModulePath
values as expanded strings, use the GetValue()
method on the
subkey and edit the value directly.
The following example adds the C:\Program Files\Fabrikam\Modules
path to the
value of the PSModulePath
environment variable without expanding the
unexpanded strings.
$key = (Get-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment')
$path = $key.GetValue('PSModulePath','','DoNotExpandEnvironmentNames')
$path += ';%ProgramFiles%\Fabrikam\Modules'
$key.SetValue('PSModulePath',$path,[Microsoft.Win32.RegistryValueKind]::ExpandString)
To add a path to the user setting, use the following code:
$key = (Get-Item 'HKCU:\Environment')
$path = $key.GetValue('PSModulePath','','DoNotExpandEnvironmentNames')
$path += ';%ProgramFiles%\Fabrikam\Modules'
$key.SetValue('PSModulePath',$path,[Microsoft.Win32.RegistryValueKind]::ExpandString)