[Python] PowerShell Subprocess Launched via debugpy Doesn’t Inherit Environment Variables (but...

Discussão em 'Python' iniciado por Stack, Abril 15, 2025.

  1. Stack

    Stack Membro Participativo

    Problem


    I'm encountering an issue where launching PowerShell via Python’s subprocess.Popen() works as expected during normal execution, but in debug mode (using debugpy/cursor) key environment variables (e.g. PROGRAMFILES and LOCALAPPDATA) are empty. In contrast, when I run a CMD command (e.g. echo %PROGRAMFILES%), the environment variables are correctly inherited.

    Environment

    • Windows 22H2 build 19045.5487
    • Python 3.10.16
    What I've Tested


    I created a small test program with three functions: one for PowerShell with the -NoProfile option (print_psh), one for PowerShell without that option (print_psh_with_profile), and one for CMD (print_cmd). I also made a variant (print_psh_with_profile_inject_env) where I pass env=os.environ.copy() explicitly.

    import subprocess
    import os

    def print_psh(cmd):
    with subprocess.Popen(
    "powershell -NoProfile " + '"' +
    f"$ErrorActionPreference='silentlycontinue'; $tmp = ({cmd}); if ($tmp){{echo $tmp; Exit;}}" + '"',
    stdout=subprocess.PIPE,
    stdin=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
    shell=True,
    ) as stream:
    cmm = stream.communicate()
    stdout = cmm[0].decode()
    print(f"NoProfile: {cmd} = {stdout}")

    def print_psh_with_profile(cmd):
    with subprocess.Popen(
    "powershell " + '"' +
    f"$ErrorActionPreference='silentlycontinue'; $tmp = ({cmd}); if ($tmp){{echo $tmp; Exit;}}" + '"',
    stdout=subprocess.PIPE,
    stdin=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
    shell=True,
    ) as stream:
    cmm = stream.communicate()
    stdout = cmm[0].decode()
    print(f"WithProfile: {cmd} = {stdout}")

    def print_psh_with_profile_inject_env(cmd):
    with subprocess.Popen(
    "powershell " + '"' +
    f"$ErrorActionPreference='silentlycontinue'; $tmp = ({cmd}); if ($tmp){{echo $tmp; Exit;}}" + '"',
    stdout=subprocess.PIPE,
    stdin=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
    shell=True,
    env=os.environ.copy(),
    ) as stream:
    cmm = stream.communicate()
    stdout = cmm[0].decode()
    print(f"WithProfile(inject env): {cmd} = {stdout}")

    def print_cmd(cmd):
    with subprocess.Popen(
    cmd,
    stdout=subprocess.PIPE,
    stdin=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
    shell=True,
    ) as stream:
    cmm = stream.communicate()
    stdout = cmm[0].decode()
    print(f"CMD.EXE: {cmd} = {stdout}")

    print_psh("Write-Host $env:pROGRAMFILES")
    print_psh("Write-Host $env:LOCALAPPDATA")
    print_cmd("echo %PROGRAMFILES%")
    print_cmd("echo %LOCALAPPDATA%")
    print_psh_with_profile("Write-Host $env:pROGRAMFILES")
    print_psh_with_profile("Write-Host $env:LOCALAPPDATA")
    print_psh_with_profile_inject_env("Write-Host $env:pROGRAMFILES")
    print_psh_with_profile_inject_env("Write-Host $env:LOCALAPPDATA")

    Output

    Normal Execution (non-debug mode):


    NoProfile: Write-Host $env:pROGRAMFILES = C:\Program Files
    NoProfile: Write-Host $env:LOCALAPPDATA = C:\Users\(USERNAME)\AppData\Local
    CMD.EXE: echo %PROGRAMFILES% = C:\Program Files
    CMD.EXE: echo %LOCALAPPDATA% = C:\Users\(USERNAME)\AppData\Local
    WithProfile: Write-Host $env:pROGRAMFILES = [profile script output] ... C:\Program Files
    WithProfile: Write-Host $env:LOCALAPPDATA = [profile script output] ... C:\Users\(USERNAME)\AppData\Local
    WithProfile(inject env): Write-Host $env:pROGRAMFILES = C:\Program Files
    WithProfile(inject env): Write-Host $env:LOCALAPPDATA = C:\Users\(USERNAME)\AppData\Local

    Debug Mode (using debugpy):


    NoProfile: Write-Host $env:pROGRAMFILES =
    NoProfile: Write-Host $env:LOCALAPPDATA =
    CMD.EXE: echo %PROGRAMFILES% = C:\Program Files
    CMD.EXE: echo %LOCALAPPDATA% = C:\Users\(USERNAME)\AppData\Local
    WithProfile: Write-Host $env:pROGRAMFILES =
    WithProfile: Write-Host $env:LOCALAPPDATA =
    WithProfile(inject env): Write-Host $env:pROGRAMFILES =
    WithProfile(inject env): Write-Host $env:LOCALAPPDATA =

    What I've Tried

    • Removing -NoProfile did not change the result in debug mode.
    • Passing env=os.environ.copy() explicitly also had no effect.
    • When using CMD (via echo %PROGRAMFILES%), the environment variables are correctly inherited.
    My Question


    It appears that when running under debugpy (or the associated debug environment), the PowerShell subprocess is launched with an environment that lacks the expected variables (they are empty), while CMD subprocesses inherit the environment normally.

    Has anyone encountered this behavior with debugpy or similar debuggers?

    • Is debugpy known to override or clear the environment when launching PowerShell subprocesses?
    • Are there any workarounds or debug configuration settings (e.g., in launch.json) to ensure that the full environment is passed to PowerShell even in debug mode?

    Any insights or suggestions would be greatly appreciated.

    Background and How I Got Here


    This issue was discovered while trying to use webdriver_manager to automatically download and launch a compatible version of ChromeDriver in a script launched under debugpy. I noticed that webdriver_manager was failing to detect the installed Chrome version on my system. Upon closer inspection, I found that it internally attempts to retrieve the Chrome version using PowerShell commands (e.g., accessing registry keys or file paths that rely on environment variables like PROGRAMFILES).

    To understand why this was failing only in debug mode, I traced the call stack and found that it eventually reaches a subprocess.Popen() call that runs PowerShell. This led me to test minimal reproducible examples using Popen directly, where I discovered that under debugpy, environment variables expected by PowerShell are inexplicably missing—while the same code behaves correctly outside of debug mode or when invoking CMD instead.

    Hence, it seems that the root cause of webdriver_manager failing in debug mode stems from PowerShell being launched in an environment that lacks essential variables like PROGRAMFILES or LOCALAPPDATA.

    Enviornment (Editor)

    • Cursor 0.48.9
    • VSCode 1.96.2
    • Extensions (latest)
      • Git Graph v3
      • Git Lens
      • Language Pack
      • Pylance
      • Python
      • Python Debugger

    Continue reading...

Compartilhe esta Página