Page 1 of 1

Exclude current directory from PATH search

Posted: 02 Sep 2017 12:02
by dbenham
In a StachOverflow comment I saw the following fascinating bit of info:
erykson on StackOverflow wrote:Starting with Windows Vista, you can remove the current directory from the implicit search path in CMD and CreateProcess by defining the environment variable NoDefaultCurrentDirectoryInExePath.


I tested on my Win 10 machine, and it indeed works :!:

I created a "junk.bat" hello world script in a "c:\test" folder that is not in my PATH. I set my current directory to "c:\test", defined NoDefaultCurrentDirectoryInExePath=1, and then junk.bat could not be found. 8)


Dave Benham

Re: Exclude current directory from PATH search

Posted: 02 Sep 2017 12:22
by aGerman
Thanks for sharing, Dave! I read the reference of the NeedCurrentDirectoryForExePath API (that describes the NoDefaultCurrentDirectoryInExePath variable) several times but I never tried what happens if I define this variable manually :oops:

Steffen

Re: Exclude current directory from PATH search

Posted: 02 Sep 2017 12:37
by SIMMS7400
Interesting - what is a good use case for this though?

Re: Exclude current directory from PATH search

Posted: 02 Sep 2017 13:07
by aGerman
Most likely you won't use it because it's a wanted behavior to search in the current directory first. E.g. if you want to use a 3rd party tool you can simply put it in the same directory along with your batch script where you want to use it.

But to provide an example:
Batch scripts fail if they have the same name as a utility they need to call (or if there is any other executable file with the same name in the working directory).
Save this code as "find.bat"

Code: Select all

@echo off
echo Hello World|find "Hello"
pause

Executing it produces maybe a thousand cmd.exe processes. You might not even be able to close the window. The reason why this happens is that you call find in your script. Instead of calling C:\Windows\System32\find.exe the script calls itself recursively because it searches for an executable file with name find in the current directory first.
If you define NoDefaultCurrentDirectoryInExePath it works as you might have expected.

Code: Select all

@echo off
set NoDefaultCurrentDirectoryInExePath=1
echo Hello World|find "Hello"
pause

Steffen

Re: Exclude current directory from PATH search

Posted: 02 Sep 2017 13:57
by thefeduke
A couple of years ago I was experimenting with poorly chosen names in the CD interfering with the system search.

This would open up the possibility of adding the CD behind the path and disabling searching the CD first.

John A.

Re: Exclude current directory from PATH search

Posted: 02 Sep 2017 14:22
by dbenham
Yep, a perfect usage - an extension of what Steffen was talking about.

Somewhere on this site there is a thread that discusses speeding up CALLs to internal commands (like CALL ECHO %%VAR%%). One of the things that slows these CALLs is the search of the current directory and the PATH for an external command of that name. Performance was enhanced by undefining PATH and setting PATHEXT to a bogus value like a single dot. (I'm not sure about the details - this is from memory)

I believe the NoDefaultCurrentDirectoryInExePath variable would allow the CALL performance boost by simply undefining PATH, without the need to modify PATHEXT.


Dave Benham

Re: Exclude current directory from PATH search

Posted: 03 Sep 2017 07:13
by SIMMS7400
Ah - that makes perfect sense!

Thank you for the followup, gentlemen!

Re: Exclude current directory from PATH search

Posted: 04 Sep 2017 10:57
by jfl
Thanks Dave for sharing this useful information!

I've updated my which program to test for this when displaying the pathname of the program that will run.
It now skips the instance in the current directory (if any) if NoDefaultCurrentDirectoryInExePath is defined.

After a bit of hesitation, I decided to keep displaying the instance in the current directory anyway when using the which -a option.
The rationale being that when using which -a, you want to enumerate all alternative versions that could be run.

Code: Select all

C:\JFL\Temp>which wm
wm.bat

C:\JFL\Temp>set NoDefaultCurrentDirectoryInExePath=1

C:\JFL\Temp>which wm
C:\JFL\Tools\wm.bat

C:\JFL\Temp>which -a wm
wm.bat
C:\JFL\Tools\wm.bat

C:\JFL\Temp>

The source is available there: which.c
A build is available there: which.exe
Eventually it'll be in the next release of my tools library: SysTools.zip
(Which (no pun intended :D ) unfortunately I last released this morning, before knowing about all this!)

PS. I also made a quick test in PowerShell. Whether NoDefaultCurrentDirectoryInExePath is defined of not, the current directory is never searched, even when running batch files.
So the output of my which.exe did not need to change when invoked within PowerShell. It already skipped the current directory in all cases.