Skip to content

Get-PSResource does not search in user context environment variable PSModulePath #889

@o-l-a-v

Description

@o-l-a-v
Contributor

Prerequisites

  • Write a descriptive title.
    Make sure you are able to repro it on the latest released version
    Search the existing issues.

Steps to reproduce

PackageManagement, PowerShellGetv2 and PowerShellGet 3.0.18-beta (and prior versions) does not search in directorories specified in user context environmental variable PSModulePath when searching for modules. But at least v3 has a -Path parameter.

Reproduce:

  • Install Az.Accounts to %LOCALAPPDATA%\Microsoft\PowerShell\Modules by using Save-PSResource.
  • Make sure said module is not installed any other places specified in $env:PSModulePath.
    • Or rather any other default locations for PowerShell modules I guess.
  • Make sure %LOCALAPPDATA%\Microsoft\PowerShell\Modules is specified in HKCU:\Environment\PSModulePath, and that PowerShell loaded it into $env:PSModulePath at start. Should also be seen in [System.Environment]::GetEnvironmentVariable('PSModulePath','User').
  • Search for installed modules with PowerShellGet\Get-PSResource -Name 'Az.Accounts'. Result: Not found.
  • Add -Scope 'CurrentUser: Nope, still not found.
  • Add -Path ('{0}\Microsoft\PowerShell\Modules' -f $env:LOCALAPPDATA): Found.

Microsoft.PowerShell.Core\Import-Module and Get-Module works as expected.

Expected behavior

PowerShellGet\Get-PSResource should search in all PSModulePath paths, also those specified in user context environmental variable.

Actual behavior

It does not.

Error details

No response

Environment data

PowerShellGet v3.0.18
Windows PowerShell 5.1 x64 on Windows 10 22H2

Visuals

No response

Activity

modified the milestones: vNext, 3.0-Consider on Jan 18, 2023
o-l-a-v

o-l-a-v commented on Apr 1, 2024

@o-l-a-v
ContributorAuthor

Here's the responsible code as far as I can see:

// Find all potential resource paths
public static List<string> GetPathsFromEnvVarAndScope(
PSCmdlet psCmdlet,
ScopeType? scope)
{
GetStandardPlatformPaths(
psCmdlet,
out string myDocumentsPath,
out string programFilesPath);
List<string> resourcePaths = new List<string>();
if (scope is null || scope.Value is ScopeType.CurrentUser)
{
resourcePaths.Add(Path.Combine(myDocumentsPath, "Modules"));
resourcePaths.Add(Path.Combine(myDocumentsPath, "Scripts"));
}
if (scope.Value is ScopeType.AllUsers)
{
resourcePaths.Add(Path.Combine(programFilesPath, "Modules"));
resourcePaths.Add(Path.Combine(programFilesPath, "Scripts"));
}
return resourcePaths;
}

Seems doable to add PSModulePath here?

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && scope is not null) {
    Environment.GetEnvironmentVariable(
        "PSModulePath",
        scope.Value is ScopeType.CurrentUser ? EnvironmentVariableTarget.User : EnvironmentVariableTarget.Machine
    );
}

I understand it's more complex than that. One must have tests etc.

Is this one up for grabs, or do you not want environment variable PSModulePath to have any say?


Edit: Here's a PowerShellers attempt. 😁

Click to view
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && scope is not null) {
    string PSModulePath = Environment.GetEnvironmentVariable(
        "PSModulePath",
        scope.Value is ScopeType.CurrentUser ? EnvironmentVariableTarget.User : EnvironmentVariableTarget.Machine
    );
    if (string.IsNullOrEmpty(PSModulePath)) {
        psCmdlet.WriteVerbose("Found no value for PSModulePath given the scope.");
    }
    else {
        foreach (string element in PSModulePath.Split(Path.PathSeparator)) {
            if (Directory.Exists(element)) {
                if (
                    string.Equals(
                        element.Split(Path.DirectorySeparatorChar).Last(),
                        "Modules",
                        StringComparison.OrdinalIgnoreCase
                    )
                ) {
                    psCmdlet.WriteVerbose(
                        string.Format(
                            "'{0}' exists, adding it to 'resourcePaths'.",
                            element
                        )
                    );
                    resourcePaths.Add(element);
                    resourcePaths.Add(Path.Combine(Directory.GetParent(element).FullName, "Scripts"));
                }
                else {
                    psCmdlet.WriteVerbose(
                        string.Format(
                            "'{0}' exists but does not match expected pattern, not adding it to 'resourcePaths'.",
                            element
                        )
                    );
                }
            }
            else {
                psCmdlet.WriteVerbose(
                    string.Format(
                        "'{0}' does not exist, not adding it to 'resourcePaths'.",
                        element
                    )
                );
            }
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @o-l-a-v@alerickson

        Issue actions

          `Get-PSResource` does not search in user context environment variable `PSModulePath` · Issue #889 · PowerShell/PSResourceGet