Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,42 @@ private static string AddToPath(string basePath, string pathToAdd, int insertPos
return result.ToString();
}

/// <summary>
/// The available module path scopes.
/// </summary>
public enum PSModulePathScope
{
/// <summary>The users module path.</summary>
User,

/// <summary>The Builtin module path. This is where PowerShell is installed (PSHOME).</summary>
Builtin,

/// <summary>The machine module path. This is the shared location for all users of the system.</summary>
Machine
}

/// <summary>
/// Retrieve the current PSModulePath for the specified scope.
/// </summary>
/// <param name="scope">The scope of module path to retrieve. This can be User, Builtin, or Machine.</param>
/// <returns>The string representing the requested module path type.</returns>
public static string GetPSModulePath(PSModulePathScope scope)
{
if (scope == PSModulePathScope.User)
{
return GetPersonalModulePath();
}
else if (scope == PSModulePathScope.Builtin)
{
return GetPSHomeModulePath();
}
else
{
return GetSharedModulePath();
}
}

/// <summary>
/// Checks the various PSModulePath environment string and returns PSModulePath string as appropriate.
/// </summary>
Expand Down
45 changes: 45 additions & 0 deletions test/powershell/engine/Module/ModulePath.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,48 @@ Describe "SxS Module Path Basic Tests" -tags "CI" {
$out.Split([System.IO.Path]::PathSeparator, [System.StringSplitOptions]::RemoveEmptyEntries) | Should -Not -BeLike $validation
}
}

Describe "ModuleIntrinsics.GetPSModulePath API tests" -tag @('CI', 'RequireAdminOnWindows', 'RequireSudoOnUnix') {
BeforeAll {
# create a local repostory and install a module
$localSourceName = [Guid]::NewGuid().ToString("n")
$localSourceLocation = Join-Path $PSScriptRoot assets
Register-PSRepository -Name $localSourceName -SourceLocation $localSourceLocation -InstallationPolicy Trusted -ErrorAction SilentlyContinue
Install-Module -Force -Scope AllUsers -Name PowerShell.TestPackage -Repository $localSourceName -ErrorAction SilentlyContinue
Install-Module -Force -Scope CurrentUser -Name PowerShell.TestPackage -Repository $localSourceName -ErrorAction SilentlyContinue

$testCases = @(
@{ Name = "User" ; Expected = $IsWindows ?
(Resolve-Path ([Environment]::GetFolderPath("Personal") + "\PowerShell\Modules")).Path :
(Resolve-Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory("USER_MODULES"))).Path
}
@{ Name = "Machine" ; Expected = $IsWindows ?
[Environment]::GetFolderPath("ProgramFiles") + "\PowerShell\Modules" :
(Resolve-Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory("SHARED_MODULES"))).Path
}
@{ Name = "Builtin" ; Expected = (Resolve-Path (Join-Path $PSHOME Modules)).Path }
)
# resolve the paths to ensure they are in the correct format
$currentModulePathElements = $env:PSModulePath -split [System.IO.Path]::PathSeparator | Foreach-Object { (Resolve-Path $_).Path }
}

AfterAll {
Unregister-PSRepository -Name $localSourceName -ErrorAction SilentlyContinue
}

It "The value '<Name>' should return the proper value" -testcase $testCases {
param ( $Name, $Expected )
$result = [System.Management.Automation.ModuleIntrinsics]::GetPSModulePath($name)
$result | Should -not -BeNullOrEmpty
# spot check pshome, the user and shared paths may not be present
if ( $name -eq "PSHOME") {
$result | Should -Be $Expected
}
}

It "The current module path should contain the expected paths for '<Name>'" -testcase $testCases {
param ( $Name, $Expected )
$mPath = (Resolve-Path ([System.Management.Automation.ModuleIntrinsics]::GetPSModulePath($name))).Path
$currentModulePathElements | Should -Contain $mPath
}
}
Binary file not shown.