The code in the question does not work for multiple reasons:
if exist "%%a:\"
just tests existence of the drive, or more precisely, the root directory of the drive of which drive letter is assigned currently to the loop variable a
.
- If the drive exists, the command DIR is executed to search the entire drive for a file with name
valheim.exe
. But the result of command DIR is not evaluated at all. DIR just outputs either all found files with name valheim.exe
with full path or the error message File Not Found
on not being able to find a file with name valheim.exe
on entire drive. There is neither the exit code of command DIR evaluated nor is the output of DIR evaluated by the used code.
- The inner command block starting with
(
, having the two command lines @set _variable=%%a
and @echo !_variable!
and ending with )
is executed for each drive letter assigned to the loop variable a
independent on IF condition being true or false for the current drive letter and independent on DIR having found a file or not. The (
marking the beginning of the command block at end of the line with the IF condition does not result in running this command block only if the IF condition is true and DIR found a file with name valheim.exe
. The syntax of the IF condition is completely wrong here to make the execution of the two commands in the command block dependent on the IF condition.
- The environment variable
_variable
is for that reason always defined with the value h
after the FOR loop finished.
- The environment variable
_variable
with value h
is discarded by the command endlocal
which results in discarding the entire environment variables list created as copy of the current environment variables list on starting the batch file by the command setlocal
with the only modification of the (re)definition of the environment variable _variable
several times within the FOR loop with having finally the string value h
. So the environment variable _variable
is not defined anymore after command endlocal
on being not defined on starting the batch file at all or is still defined with the value this environment variable had on starting the batch file.
- DIR does not support searching for file system entries with a specific path left to the file/folder name with a variable path part at the beginning. There is no Windows command supporting that. It is only possible to search for a file or folder with a specific name and look on its fully qualified name to validate if the file/folder is within a specific directory tree.
The task can be done with a batch file using following single command line:
@for /F "skip=1" %%I in ('%SystemRoot%\System32\wbem\wmic.exe LOGICALDISK GET DeviceID 2^>nul') do @for /F "delims=" %%J in ('dir %%I\valheim.exe /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /L /C:"\\common\\Valheim\\valheim.exe"') do @set "FilePath=%%~dpJ" & exit /B
@
left to a command suppresses the output of the command line after parsing it by the Windows command processor before execution. The three @
can be removed if the batch file contains more than just this line and has as first line @echo off
.
There is first executed in background one more Windows command processor with the command line:
C:\Windows\System32\cmd.exe /c C:\Windows\System32\wbem\wmic.exe LOGICALDISK GET DeviceID 2>nul
The Windows Management Instrumentation Command-line utility uses the Win32_LogicalDisk class to get information about logical drives and outputs in Unicode with the character encoding UTF-16 LE with BOM a list of drive letters with a colon and the header line DeviceID
.
The output of wmic.exe
to standard output stream of background command process is captured by the command processor which is processing the batch file. The captured lines are processed line by line by FOR after in background started cmd.exe
closed itself after wmic.exe
terminated itself.
The first line with just DeviceID
is skipped because of the usage of option skip=1
. The other lines contain only the drive letter and the colon of a drive. So the outer FOR assigns one drive letter + colon to the loop variable I
and runs the inner FOR.
The inner FOR starts again one more cmd.exe
in background with a command line like:
C:\Windows\System32\cmd.exe /c dir C:\valheim.exe /A-D /B /S 2>nul | C:\Windows\System32\findstr.exe /E /I /L /C:"\\common\\Valheim\\valheim.exe"
The internal command DIR of cmd.exe
searches
- just for files because of option
/A-D
(attribute not directory)
- with name
valheim.exe
in C:\
and all its subdirectories because of option /S
- and outputs all files with that name in bare format because of option
/B
which means with just the file name with full path because of option /S
.
The error message output by DIR on not finding any file with name valheim.exe
to the handle standard error is suppressed by redirecting it to device NUL.
The file name(s) output by DIR are redirected to standard input of FINDSTR being used as filter. It does a case-insensitive search (/I
) for the literally interpreted (/L
and /C:
) search string specified after /C:
in double quotes. The find is only positive if the searched string is found at end of a line (/E
) in which case the entire line is output by FINDSTR to standard output of the background command process.
The directory separator is \
on Windows and not /
as on Linux/Mac. That is described by the Microsoft documentation about Naming Files, Paths, and Namespaces. FINDSTR interprets a backslash as escape character even in literally interpreted strings and for that reason it is necessary to escape each backslash in search string with one more backslash.
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul
and |
. The redirection operators >
and |
must be escaped with caret character ^
on FOR command line to be interpreted as literal characters when Windows command interpreter processes this command line before executing the first command FOR.
The output by DIR filtered with FINDSTR is captured by cmd.exe
processing the batch file and is processed line by line by the inner FOR after started background command process closed itself.
There is assigned just the full path of found file name of which fully qualified file name ends case-insensitive with \common\Valheim\valheim.exe
to the environment variable FilePath
and next the two loops and the entire batch file execution is exiting by using exit /B
. If the batch file should do more with usage of FilePath
, then the command GOTO must be used with a label which has the next line in the batch file to just exit the two loops and continue batch file processing on the line below the label line.
The environment variable FilePath
can be used further in the Windows command process used to process the batch file.
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
dir /?
echo /?
exit /?
findstr /?
for /?
goto /?
set /?
wmic /?
wmic logicaldisk /?
wmic logicaldisk get /?
Read also:
- Single line with multiple commands using Windows batch file
- How to pass environment variables as parameters by reference to another batch file?
It explains very detailed what happens on each execution of the commands SETLOCAL and ENDLOCAL and why both are not used here in this batch file because of the environment variable FilePath
should still be defined with the found path after finishing processing of the batch file.
- What is the reason for "X is not recognized as an internal or external command, operable program or batch file"?
It explains in full details on the example of most important environment variable PATH
how environment variables are managed on Windows. The environment variable FilePath
exists only for cmd.exe
processing the batch file once defined by the batch file. It does not exist for other processes already running or started next by another process than cmd.exe
processing the batch file.
- Microsoft documentation about Application Registration
Many installers of applications register the executable as recommended by Microsoft. For that reason it is not necessary to search on all drives in all directories for an executable which is registered by the installer. A simple registry query is in this case enough to find out if an executable is installed at all and where it is installed. If the application registration is not done by an installer as recommended by Microsoft which is typical for games, the installers usually save the installation path either somewhere in the Windows registry or in a file in one of the common folders accessible using the predefined Windows Environment Variables output with their values on running set
in a command prompt window.