Eryk Sun added the comment: As is documented for CreateProcess [1], the search path always includes the following directories: * The directory from which the application loaded. * The current directory for the parent process. * The Windows system directory. Use the GetSystemDirectory function to get the path of this directory. * The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System. * The Windows directory. Use the GetWindowsDirectory function to get the path of this directory. * The directories that are listed in the PATH environment variable. The value of PATH comes from the calling process environment, not from the environment passed in the lpEnvironment parameter. If you need to search some other list of paths, you can use shutil.which to find the fully qualified path of the target executable. Note that in Vista+ you can remove the current directory from the search list by defining the environment variable "NoDefaultCurrentDirectoryInExePath" [2]. The following examples show the minimum search path that CreateProcess uses when PATH isn't defined. >>> 'PATH' in os.environ False >>> subprocess.call('python -Sc "import sys; print(sys.prefix)"') Breakpoint 0 hit KERNELBASE!SearchPathW: 00007ff9`cf4b5860 488bc4 mov rax,rsp 0:000> du @rcx 0000006c`a7074410 "C:\Program Files\Python35;.;C:\W" 0000006c`a7074450 "indows\SYSTEM32\;C:\Windows\syst" 0000006c`a7074490 "em;C:\Windows" 0:000> g C:\Program Files\Python35 0 >>> os.environ['NoDefaultCurrentDirectoryInExePath'] = '1' >>> subprocess.call('python -Sc "import sys; print(sys.prefix)"') Breakpoint 0 hit KERNELBASE!SearchPathW: 00007ff9`cf4b5860 488bc4 mov rax,rsp 0:000> du @rcx 0000006c`a6560710 "C:\Program Files\Python35;C:\Win" 0000006c`a6560750 "dows\SYSTEM32\;C:\Windows\system" 0000006c`a6560790 ";C:\Windows" 0:000> g C:\Program Files\Python35 0 Note that in the 2nd case the current directory ('.') is no longer present between the application directory ("C:\Program Files\Python35") and the system directory ("C:\Windows\SYSTEM32\"). CreateProcess executes PE executables and batch files (run via the %ComSpec% interpreter). It automatically appends the .exe extension when searching for an executable. It does this via the lpExtension parameter of SearchPath [3]. Some .com files are PE executables (e.g. chcp.com). Otherwise it's not really usefully to loop over the PATHEXT extensions unless you're using shell=True, since most are filetypes that CreateProcess doesn't support [4]. [1]: https://msdn.microsoft.com/en-us/library/ms682425 [2]: https://msdn.microsoft.com/en-us/library/ms684269 [3]: https://msdn.microsoft.com/en-us/library/aa365527 [4]: If Microsoft's Windows team cared at all about cross-platform idioms they'd add shebang support to CreateProcess, which would make all scripts, not just batch files, directly executable without requiring ShellExecuteEx and registered filetypes. ShellExecuteEx doesn't support a lot of useful creation flags that are only available by calling CreateProcess directly, and it also doesn't check ACLs to prevent executing a file. So scripts are second class citizens in Windows, which is why Python has to embed scripts in .exe wrappers. ---------- nosy: +eryksun _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue8557> _______________________________________