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.
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.
shell
option.Write-Host
problem isn't affected, so I'm keeping it in V1
.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, # Is the "powershell" expression recognized as a CMD.exe command? This returns nothing, but it works without error.(see the description about *V2* code)
) 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, # Is the "powershell" expression recognized as a CMD.exe command? This returns nothing, but it works without error.(see the description about *V2* code)
) 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, # Is the "powershell" expression recognized as a CMD.exe command? This returns nothing, but it works without error.(see the description about *V2* code)
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, # use commandline commands.
) as stream:
cmm = stream.communicate()
stdout = cmm[0].decode()
print(f"CMD.EXE: {cmd} = {stdout}")
print_psh("$env:PROGRAMFILES")
print_psh("$env:LOCALAPPDATA")
print_cmd("echo %PROGRAMFILES%")
print_cmd("echo %LOCALAPPDATA%")
print_psh_with_profile("$env:PROGRAMFILES")
print_psh_with_profile("$env:LOCALAPPDATA")
print_psh_with_profile_inject_env("$env:PROGRAMFILES")
print_psh_with_profile_inject_env("$env:LOCALAPPDATA")
NoProfile: $env:PROGRAMFILES = C:\Program Files
NoProfile: $env:LOCALAPPDATA = C:\Users\(USERNAME)\AppData\Local
CMD.EXE: echo %PROGRAMFILES% = C:\Program Files
CMD.EXE: echo %LOCALAPPDATA% = C:\Users\(USERNAME)\AppData\Local
WithProfile: $env:PROGRAMFILES = [profile script output] ... C:\Program Files
WithProfile: $env:LOCALAPPDATA = [profile script output] ... C:\Users\(USERNAME)\AppData\Local
WithProfile(inject env): $env:PROGRAMFILES = C:\Program Files
WithProfile(inject env): $env:LOCALAPPDATA = C:\Users\(USERNAME)\AppData\Local
NoProfile: $env:PROGRAMFILES =
NoProfile: $env:LOCALAPPDATA =
CMD.EXE: echo %PROGRAMFILES% = C:\Program Files
CMD.EXE: echo %LOCALAPPDATA% = C:\Users\(USERNAME)\AppData\Local
WithProfile: $env:PROGRAMFILES =
WithProfile: $env:LOCALAPPDATA =
WithProfile(inject env): $env:PROGRAMFILES =
WithProfile(inject env): $env:LOCALAPPDATA =
I changed the code more precise, then I obtained a new error and clue.
shell
option.shell
option to False
in all print_psh
family because it might be secure that 'powershell'
expression is not treat as CMD.EXE command....
def print_psh...(cmd):
with subprocess.Popen(
"powershell -NoProfile " + '"' +
...
stderr=subprocess.DEVNULL,
- shell=True, # Is the "powershell" expression recognized as a CMD.exe command? This returns nothing, but it works without error.(see the description about *V2* code)
+ shell=False, # PowerShell commands are indirectlly called from a new process.
) as stream:
...
Add this code on the beginning of the code V1.
+def print_psh_test():
+ cmd = "powershell"
+ with subprocess.Popen(
+ cmd,
+ stdout=subprocess.PIPE,
+ stdin=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ shell=False, # PowerShell commands are indirectlly called from +a new process.
+ ) as stream:
+ cmm = stream.communicate()
+ print("test to run powershell.")
...
+print_psh_test()
print_psh("$env:PROGRAMFILES")
print_psh("$env:LOCALAPPDATA")
...
(Same as V1)
<Error occurs: below stacktrace>
Exception has occurred: FileNotFoundError
[WinError 2] The system cannot find the file specified.
File "C:\...\{source_file}.py", line 6, in print_psh_test
with subprocess.Popen(
File "C:\...\{source_file}.py", line 71, in <module>
print_psh_test()
FileNotFoundError: [WinError 2] The system cannot find the file specified.
python -m debugpy --listen 5678 --wait-for-client ./{source_file}.py.`
.vscode/launch.json
)...
{
"name": "Python: Attach",
"type": "python",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "."
}
],
"justMyCode": true
}
...
(Same as Normal Execution)
-NoProfile
did not change the result in debug mode.env=os.environ.copy()
explicitly also had no effect.echo %PROGRAMFILES%
), the environment variables are correctly inherited.powershell
with shell=False
option will cause the FileNotFound error, although not with shell=Ture
.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?
Any insights or suggestions would be greatly appreciated.
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
.
Apologies for the confusion and for taking up your time with this—it was my own mistake. I really appreciate your help.
After all the investigation above, I finally discovered the true culprit: a project‑root .env
file that I had added for other tooling (e.g. to set JAVA_HOME
for a Processing‑like Python library py5
). That file contained something like:
# .env at the workspace root
JAVA_HOME=C:\Some\Java\Path
PATH=$JAVA_HOME$;$PATH
.env
and appends it to the existing environment, so your real PATH
(and PROGRAMFILES
, LOCALAPPDATA
, etc.) remain intact—PowerShell and CMD subprocesses work fine..env
and override the entire process environment. As a result:
PATH
becomes exactly C:\Some\Java\Path\bin;$PATH
(no Windows system paths)powershell.exe
can’t be found (or finds no inherited variables like PROGRAMFILES
)$env:…
lookups return empty stringsRemove the PATH
varable in the .env
file.
# .env — extend the existing PATH instead of overwriting it
JAVA_HOME=C:\Some\Java\Path
PATH=%JAVA_HOME%;%PATH%
# Wrong. VARIABLES are not allowed in the .env files, only LITERALS.
It is difficult to simply do anything valid to the PATH
variable with the .env files when it is in the VS Code integrated terminal using PowerShell, lunching Python in debug mode.
While the original question has been resolved, a deeper and more specific issue remains regarding how VS Code's debugger handles the PATH
environment variable in certain cases.
I have posted a follow-up question here for further discussion and clarification:
🔗 Why does VS Code debugger reset PATH from .env, breaking subprocess behavior?