Skip to content

powershell.exe still receives PSModulePath for pwsh when called indirectly #20804

Open

Description

Prerequisites

Steps to reproduce

This is a dupe of #12997 which was closed.

  1. Set up invocation of powershell.exe in some sort of non-PS tool.
  2. Example below of a bat with New-Guid (different between PS versions)
  3. Invoke the bat from pwsh.

example.bat

echo %psmodulepath%

powershell.exe "$env:PSModulePath -split ';' | Select-String 'PowerShell'; New-Guid"

Expected behavior

Powershell.exe instance does not contain `C:\Program Files\PowerShell\7`

Actual behavior

Powershell.exe still has PS7 values in PSModulePath and New-Guid throws an error. This is in a pwsh.exe window.

PS C:\Users\gsanchez\temp> .\example.bat

C:\Users\gsanchez\temp>echo C:\Users\gsanchez\Documents\PowerShell\Modules;C:\Program Files\PowerShell\Modules;c:\program files\powershell\7\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files (x86)\Windows Kits\10\Microsoft Application Virtualization\Sequencer\AppvPkgConverter;C:\Program Files (x86)\Windows Kits\10\Microsoft Application Virtualization\Sequencer\AppvSequencer;C:\Program Files (x86)\Windows Kits\10\Microsoft Application Virtualization\
C:\Users\gsanchez\Documents\PowerShell\Modules;C:\Program Files\PowerShell\Modules;c:\program files\powershell\7\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files (x86)\Windows Kits\10\Microsoft Application Virtualization\Sequencer\AppvPkgConverter;C:\Program Files (x86)\Windows Kits\10\Microsoft Application Virtualization\Sequencer\AppvSequencer;C:\Program Files (x86)\Windows Kits\10\Microsoft Application Virtualization\

C:\Users\gsanchez\temp>powershell.exe "$env:PSModulePath -split ';' | Select-String 'PowerShell'; New-Guid"

C:\Users\gsanchez\Documents\PowerShell\Modules
C:\Program Files\PowerShell\Modules
c:\program files\powershell\7\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
New-Guid : The term 'New-Guid' is not recognized as the name of a cmdlet, function, script file, or operable
program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:60
+ $env:PSModulePath -split ';' | Select-String 'PowerShell'; New-Guid
+                                                            ~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (New-Guid:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Error details

New-Guid : The term 'New-Guid' is not recognized as the name of a cmdlet, function, script file, or operable
program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:52
+ $env:Path -split ';' | Select-String 'PowerShell'; New-Guid
+                                                    ~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (New-Guid:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Environment data

Name                           Value
----                           -----
PSVersion                      7.3.10
PSEdition                      Core
GitCommitId                    7.3.10
OS                             Microsoft Windows 10.0.22631
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

No response

Activity

  1. jhoneill commented on Nov 28, 2023

    @jhoneill

    PWSH will be on the PATH.

    The title is about PSModulePath. I don't get pwsh on PSModulePath and New-Guid runs for me.

    [cmd] C:\Users\mcp> powershell.exe -noprofile "$env:PsModulePath -split ';' | Select-String 'PowerShell'; New-Guid"
    
    C:\Users\mcp\Documents\WindowsPowerShell\Modules
    C:\Program Files\WindowsPowerShell\Modules
    C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
    
    Guid : e0f08376-5e50-4a30-8f00-c517fa37abe4
    
    [cmd] C:\Users\mcp>
    
    

    It may be worth having echo %psmodulepath% in the batch file and running powershell with -noprofile to exclude a couple of possible causes.

  2. HeyItsGilbert commented on Nov 28, 2023

    @HeyItsGilbert
    Author

    You're right. I wasn't paying attention. Are you launching the example.bat from a pwsh.exe window? That's the issue. PowerShell getting invoked indirectly by subprocesses definitely happens. I have a pwsh.exe session up all the time as my daily driver, and when I kick off other tools it's when I notice. My current fix is to launch a new powershell.exe session to run known processes that have issue.

  3. jhoneill commented on Nov 28, 2023

    @jhoneill

    You're right. I wasn't paying attention. Are you launching the example.bat from a pwsh.exe window? That's the issue. PowerShell getting invoked indirectly by subprocesses definitely happens. I have a pwsh.exe session up all the time as my daily driver, and when I kick off other tools it's when I notice. My current fix is to launch a new powershell.exe session to run known processes that have issue.

    No I'm launching it from Cmd.exe

    If you run A.exe from within B.exe it will get all of B's environment variables. So if you run PowerShell.exe from pwsh, (or cmd started from pwsh) the environment variables set in pwsh will carry down into it. That's OK for pwsh starting from PowerShell.exe because it is designed to add things but PowerShell starting from pwsh can be expected to get settings that don't belong there .

  4. HeyItsGilbert commented on Nov 28, 2023

    @HeyItsGilbert
    Author

    but PowerShell starting from pwsh can be expected to get settings that don't belong there .

    I think the point of the original (and this) issue is that it's not obvious. There are multiple scenarios where unexpected things can happen. We are technical enough to understand the reasoning, but for less technical folks they may hit this issue and never discover the problem.

    In the original issue I mentioned discovering this with Chocolatey, but I've also seen other cases (e.g. config management tools). With pwsh.exe launching powershell.exe there is already some "magic" being done by modifying the environment variable. "Magic" because it happens without the user knowing, and therefore difficult to discover when issues occur.

    Possible solutions:

    • It may be reasonable to consider doing some similar "magic" for other processes. Maybe having a list of binaries that we can append to via profile.
    • Maybe update powershell.exe to always ignore pwsh module paths.
  5. rhubarb-geek-nz commented on Nov 28, 2023

    @rhubarb-geek-nz

    It is completely standard behaviour to inherit environment variables.

    • Maybe update powershell.exe to always ignore pwsh module paths.

    They are just a list of directories, there is nothing magic about them.

    What should happen is that PowerShell 5.1 should not load a module that has the following in its manifest

    	CompatiblePSEditions = @('Core')
    	PowerShellVersion = '7.2'
    

    CompatiblePSEditions should either be empty or contain 'Desktop', and if a version number appears that it is not greater than 5.1 (or what ever the current powershell is).

  6. mwallner commented on Jul 4, 2024

    @mwallner

    you might wind up in hell, but one can always hijack process creation... 😈

    In case you've got control over the initial pwsh, using PSDetour you can actively remove all $env:PSModulePath from the processes that are created from your pwsh (a.k.a. PowerShell Core / 7) session...

    <#
    https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
    
    BOOL CreateProcessW(
      [in, optional]      LPCWSTR               lpApplicationName,
      [in, out, optional] LPWSTR                lpCommandLine,
      [in, optional]      LPSECURITY_ATTRIBUTES lpProcessAttributes,
      [in, optional]      LPSECURITY_ATTRIBUTES lpThreadAttributes,
      [in]                BOOL                  bInheritHandles,
      [in]                DWORD                 dwCreationFlags,
      [in, optional]      LPVOID                lpEnvironment,
      [in, optional]      LPCWSTR               lpCurrentDirectory,
      [in]                LPSTARTUPINFOW        lpStartupInfo,
      [out]               LPPROCESS_INFORMATION lpProcessInformation
    );
    #>
    
    Import-Module PSDetour
    
    $h = New-PSDetourHook -DllName Kernel32.dll -MethodName 'CreateProcessW' -Action {
      [OutputType([bool])]
      param(
        [IntPtr]$ApplicationName,
        [IntPtr]$CommandLine,
        [IntPtr]$ProcessAttributes,
        [IntPtr]$ThreadAttributes,
        [bool]$InheritHandles,
        [int]$CreationFlags,
        [IntPtr]$Environment,
        [IntPtr]$CurrentDirectory,
        [IntPtr]$StartupInfo,
        [IntPtr]$ProcessInformation
      )
    
      $__psmodulepath = $env:PSModulePath
      $env:PSModulePath = $null
    
      $res = $this.Invoke(
        $ApplicationName,
        $CommandLine,
        $ProcessAttributes,
        $ThreadAttributes,
        $InheritHandles,
        $CreationFlags,
        $Environment,
        $CurrentDirectory,
        $StartupInfo,
        $ProcessInformation
      )
    
      $env:PSModulePath = $__psmodulepath
    
      $res
    }
    Start-PSDetour $h
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs-TriageThe issue is new and needs to be triaged by a work group.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions