How to check for a certain pattern in Windows batch - windows

I want to run something like this
C:\> mybatch.bat somefile.gz
or like this
C:\> mybatch.bat somefile.mps.gz
Inside the batch I want to check wether the argument ended with .gz or with .mps.gz.
This doesn't work
if findstr ".mps.gz" %1 (
echo ".mps.gz file"
) else (
echo ".gz file"
)
What is the right way to do this?
EDIT 1 (from https://stackoverflow.com/users/2128947/magoo):
set ZIP="C:\Program Files\7-Zip\7zFM.exe"
echo %1|findstr /i /L /e /C:".mps.gz">nul&if errorlevel 1 (
echo ".gz only %1"
%ZIP% %1
) else (
echo ".mps.gz %1"
call freempsgz2lpt.bat %1
)
pause -1
doesn't recognize the .mps.gz extension if I associate the batch file with extension .gz and double click in Windows Explorer. From commandline it works well.
EDIT 2:
I changed the proposal to
echo %1|findstr /i /L /e /C:".mps.gz""">nul&if errorlevel 1 ( ...
Now it works with file association in Windows Explorer but not on commandline. This is ok for me.

echo %~1|findstr /i /L /e /C:".mps.gz">nul&if errorlevel 1 (echo does not end .mps.gz) else (echo ends mps.gz)
findstr is a utility that sets errorlevel = 1 if the string is not matched and 0 if matched.
Documentation : findstr /? from the prompt or This tome or many examples.
In brief, /I means case-insensitive, /L is literal-match (as distinct from default /R - partial-regex) /E match at end of line, /C:"stringtomatch"

Related

Workaround for failing DEL not setting errorlevel [duplicate]

The batch has to remove files and directories from specific locations and output success or stdout/stderr messages to a new .txt file. I have created the most of the script and it performs exactly as it should, except when the deletion is successful it moves forward to the next line rather than echo a 'successful' message on the log.
echo Basic Deletion Batch Script > results.txt
#echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b
:filelog
call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:\NoSuchDirectory
GOTO :EOF
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 0 echo succesful
GOTO :EOF
:remove
echo deleting directory %1
rmdir /q /s %1
GOTO :EOF
For some reason I can't find the syntax for if del succeeds echo 'successful'. In the above example if I remove the line
if errorlevel 0 echo successful
Everything works fine, but no success message. With this line left in it echoes success for every line.
del and ErrorLevel?
The del command does not set the ErrorLevel as long as the given arguments are valid, it even resets the ErrorLevel to 0 in such cases (at least for Windows 7).
del modifies the ErrorLevel only in case an invalid switch is provided (del /X sets ErrorLevel to 1), no arguments are specified at all (del sets ErrorLevel to 1 too), or an incorrect file path is given (del : sets ErrorLevel to 123), at least for Windows 7.
Possible Work-Around
A possible work-around is to capture the STDERR output of del, because in case of deletion errors, the related messages (Could Not Find [...], Access is denied., The process cannot access the file because it is being used by another process.) are written there. Such might look like:
for /F "tokens=*" %%# in ('del /F /Q "\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)
To use the code in command prompt directly rather than in a batch file, write %# instead of %%#.
If you do not want to delete read-only files, remove /F from the del command line;
if you do want prompts (in case wildcards ? and/or * are present in the file path), remove /Q.
Explanation of Code
This executes the command line del /F /Q "\path\to\the\file_s.txt". By the part 2>&1 1> nul, the command output at STDOUT will be dismissed, and its STDERR output will be redirected so that for /F receives it.
If the deletion was successful, del does not generate a STDERR output, hence the for /F loop does not iterate, because there is nothing to parse. Notice that ErrorLevel will not be reset in that case, its value remains unchanged.
If for /F recieves any STDERR output from the del command line, the command in the loop body is executed, which is set =; this is an invalid syntax, therefore set sets the ErrorLevel to 1. The 2> nul portion avoids the message The syntax of the command is incorrect. to be displayed.
To set the ErrorLevel explicitly you could also use cmd /C exit /B 1. Perhaps this line is more legible. For sure it is more flexible because you can state any (signed 32-bit) number, including 0 to clear it (omitting the number clears it as well). It might be a bit worse in terms of performance though.
Application Example
The following batch file demonstrates how the above described work-around could be applied:
:DELETE
echo Deleting "%~1"...
rem this line resets ErrorLevel initially:
cmd /C exit /B
rem this line constitutes the work-around:
for /F "tokens=*" %%# in ('del /F /Q "C:\Users\newuser\Desktop\%~1" 2^>^&1 1^> nul') do (2> nul set =)
rem this is the corrected ErrorLevel query:
if not ErrorLevel 1 echo Deleted "%~1" succesfully.
goto :EOF
Presetting ErrorLevel
Besides the above mentioned command cmd /C exit /B, you can also use > nul ver to reset the ErrorLevel. This can be combined with the for /F loop work-around like this:
> nul ver & for /F "tokens=*" %%# in ('del /F /Q "\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)
Alternative Method Without for /F
Instead of using for /F to capture the STDERR output of del, the find command could also be used like find /V "", which returns an ErrorLevel of 1 if an empty string comes in and 0 otherwise:
del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1
However, this would return an ErrorLevel of 1 in case the deletion has been successful and 0 if not. To reverse that behaviour, an if/else clause could be appended like this:
del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1 & if ErrorLevel 1 (1> nul ver) else (2> nul set =)
Different Approach: Checking File for Existence After del
A completely different approach is to check the file for existence after having tried to delete it (thanks to user Sasha for the hint!), like this, for example:
del /F /Q "\path\to\the\file_s.txt" 1> nul 2>&1
if exist "\path\to\the\file_s.txt" (2> nul set =) else (1> nul ver)
When using this syntax, instead of this
if errorlevel 0 echo successful
you can use this - because errorlevel 0 is always true.
if not errorlevel 1 echo successful
Just use rm from UnxUtils (or gow or cygwin). It sets the errorlevel correctly in case of a nonexistent file, or any errors deleting the file.
This was added as an edit by the original asker, I have converted it to a community wiki answer because it should be an answer, not an edit.
I found out how to do it... one way anyway.
echo Startup > results.txt
#echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b
:filelog
call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:\NoSuchDirectory
GOTO :EOF
:delete
echo deleting %1
dir c:\users\newuser\Desktop\%1 >NUL 2>&1
SET existed=%ERRORLEVEL%
del /f /q c:\Users\newuser\Desktop\%1
dir c:\users\newuser\Desktop\%1 2>NUL >NUL
if %existed% == 0 (if %ERRORLEVEL% == 1 echo "successful" )
GOTO :EOF
:remove
echo deleting directory %1
rmdir /q /s %1
GOTO :EOF
IF ERRORLEVEL 0 [cmd] will execute every time because IF ERRORLEVEL # checks to see if the value of ERRORLEVEL is greater than or equal to #. Therefore, every error code will cause execution of [cmd].
A great reference for this is: http://www.robvanderwoude.com/errorlevel.php
>IF /?
Performs conditional processing in batch programs.
IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command
NOT Specifies that Windows should carry out
the command only if the condition is false.
ERRORLEVEL number Specifies a true condition if the last program run
returned an exit code equal to or greater than the number
specified.
I would recommend modifying your code to something like the following:
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 1 (
rem This block executes if ERRORLEVEL is a non-zero
echo failed
) else (
echo succesful
)
GOTO :EOF
If you need something that processes more than one ERRORLEVEL, you could do something like this:
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 3 echo Cannot find path& GOTO :delete_errorcheck_done
if errorlevel 2 echo Cannot find file& GOTO :delete_errorcheck_done
if errorlevel 1 echo Unknown error& GOTO :delete_errorcheck_done
echo succesful
:delete_errorcheck_done
GOTO :EOF
OR
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
goto :delete_error%ERRORLEVEL% || goto :delete_errorOTHER
:delete_errorOTHER
echo Unknown error: %ERRORLEVEL%
GOTO :delete_errorcheck_done
:delete_error3
echo Cannot find path
GOTO :delete_errorcheck_done
:delete_error2
echo Cannot find file
GOTO :delete_errorcheck_done
:delete_error0
echo succesful
:delete_errorcheck_done
GOTO :EOF
The answer of aschipfl is great (thanks, helped me a lot!) using the code under Presetting ErrorLevel you get a nice standard function:
Take care to use %~1 instead of %1 in the del statement, or you will get errors if you use a quoted filename.
::######################################################################
::call :DELETE "file.txt"
::call :DELETE "file.txt" "error message"
:DELETE
>nul ver && for /F "tokens=*" %%# in ('del /F /Q "%~1" 2^>^&1 1^> nul') do (2>nul set =) || (
if NOT .%2==. echo %~2
)
goto :EOF
BTW 1: You can give a nifty error message as a second parameter
BTW 2: Using :: instead of REM for comments makes the code even more readable.
Code:
Error Code: (What you did)
if errorlevel 0 echo succesful
The problem here is that you aren't calling errorlevel as a variable and plus you didn't add in the operator to the statement as well.
Correct Code: (Here is what it should actually be.)
if %ERRORLEVEL% EQU 0 echo succesful
Definitions:
EQU: The EQU stands for Equal. This kind of operator is also called a relational operator. Here is the documentation link to operators if you wanna know more, there are other ones but this helped me.
ERRORLEVEL: is declared as a variable and usually get the error level of the last command run usually. Variables are usually called when they are between percent signs like this
%foo%
For some more help on variables, go to cmd (Which you can go to by searching it on windows 10) and type in "set /?", without the quotes. the set command is the command you use to set variables

FINDSTR: help understanding results. Returns nothing, but no error when there is one expected?

I am writing a batch file. part of the program will compare the list of files in a 'source' folder. With the contents of a list in a text file.
I loop through each file in the folder, and search for its filename in the text file using FINDSTR
Everything works until there is a filename in the source folder that doesnt exist in the text file.
the findstr code:
for /f %%o in ('findstr %name% old.txt') do (
echo o=%%o >> result.txt
if %%o==%name% (
echo %name% exists
) ELSE (
echo %name% does not exists
)
)
Again, the problem occurs when FINDSTR searches for a filename that is not in the text file.
when it reaches that point it outputs the variable %%o as being '%o' and echos nothing. So it sends nothing to the results.txt.
This doesnt trigger an ERRORLEVEL change but also will not echo anything. I have tried outputing the errorlevels but they are also empty. I just dont understand what FINDSTR is doing in this instance.
the FULL batch file: (its my first one. forgive any mistakes)
::return the raw (/b) list of files
FORFILES /p %~dp0source\ /s /m "*.cr2" /C "cmd /c echo #path" > new.txt
::pull file path for each file and send to subroutine
for /f %%n in ('FORFILES /p %~dp0source\ /s /m "*.cr2" /C "cmd /c echo #path"') do (
call :dequote %%n
)
::subroutine for removing quotes
::and returning the filename, extension, and path
:dequote
set fullPath=%~f1
set fileName=%~n1
set fileExt=%~x1
set filePath=%~dp1
set name=%fileName%& set npath=%filePath%& set ext=%fileExt%& set fpath=%fullPath%
echo %fpath%
echo %npath%
echo %name%
echo %ext%
for /f %%o in ('findstr %name% old.txt') do (
echo o=%%o >> result.txt
if %%o==%name% (
echo %name% exists
) ELSE (
echo %name% does not exists
)
)
This only happens on the last filename sent to findstr. Any suggestions or direction would be very appreciated. Ive tried and read everything I can get my hands on.
Thank You for your time.
UPDATE: 9-9-15
Here is the working final batch file i created using the help on this page. It creates a hotfolder that will edit any new files added to it until you stop the script from running:
:start
:: return the raw (/b) list of files and full path to source text
FORFILES /p %~dp0source\ /s /m "*.cr2" /C "cmd /c echo #path" > source.txt
IF %ERRORLEVEL% EQU 1 goto :start
::join new and old data, return only what is shared in common (/g)
findstr /I /L /G:"source.txt" "output.txt" > found.txt
IF %ERRORLEVEL% EQU 1 copy /y source.txt notFound.txt
::join found file names and source filenames, return those that do not have a match
findstr /I /L /V /G:"found.txt" "source.txt" >> notFound.txt
IF %ERRORLEVEL% EQU 2 echo error no match
::for each line of notFound.txt, dequote and break apart
for /f %%n in (notFound.txt) do (
echo n=%%n
call :dequote %%n
)
:dequote
set fullPath=%~f1
set fileName=%~n1
set fileExt=%~x1
set filePath=%~dp1
set name=%fileName%& set npath=%filePath%& set ext=%fileExt%& set fpath=%fullPath%
echo %fpath%
echo %npath%
echo %name%
echo %ext%
cd %nPath%
if NOT [%1]==[] (
echo converted %name%
convert -negate -density 600 -colorspace gray flatField.cr2 %name%%ext% -compose Divide -composite %name%.tif
move %name%.tif %~dp0output
cd %~dp0
del notFound.txt
copy /y source.txt output.txt
) ELSE (
echo end of batch else
cd %~dp0
)
Loop variables must be referenced with %% in a batch file because percent sign has a special meaning and must be therefore escaped with another percent sign in a batch file to specify it literally. This is the reason why on running the batch file with echo on in a command prompt window results in getting %%o in the batch file displayed as %o on execution.
Command FOR as used in
for /f %%o in ('findstr %name% old.txt') do
processes the output written to stdout by the called command findstr. But findstr does not write anything to standard output when it searched for one or more strings in a file and could not find any matching string in any line of the file.
So command for can't process anything and therefore none of the commands after do are processed at all in this case.
Assuming the list file contains only file names without path, the following commented batch file can be used to get with 1 execution of command dir and just 1 or 2 executions of console application findstr the two lists containing the file names in folder being found and being not found in the list file. The batch file is written for not producing empty files.
#echo off
setlocal
set "ListFile=C:\Temp\List.txt"
if not exist "%ListFile%" goto NoListFile
set "SourceFolder=C:\Temp\Test"
if not exist "%SourceFolder%\*" goto NoSourceFolder
set "AllFileNames=%TEMP%\AllFileNames.txt"
set "FoundFileNames=%TEMP%\FoundFileNames.txt"
set "NotFoundFileNames=%TEMP%\NotFoundFileNames.txt"
rem Get alphabetic list of files in source folder without path.
dir /A /B /ON "%SourceFolder%" >"%AllFileNames%"
rem Find all file names in list file with a case-insensitive
rem search matching completely a file name in list file and
rem output the found file names to another list file.
%SystemRoot%\system32\findstr.exe /I /L /X "/G:%AllFileNames%" "%ListFile%" >"%FoundFileNames%"
if errorlevel 1 goto NoFileNameFound
rem Find all file names with a case-insensitive search found
rem before in all file names list and output the lines not
rem containing one of the file names to one more list file.
%SystemRoot%\system32\findstr.exe /I /L /V "/G:%FoundFileNames%" "%AllFileNames%" >"%NotFoundFileNames%"
if errorlevel 1 goto AllFileNamesFound
rem Some file names are found in list file and others not.
del "%AllFileNames%"
goto :EndBatch
:NoFileNameFound
move /Y "%AllFileNames%" "%NotFoundFileNames%"
del "%FoundFileNames%"
goto EndBatch
:AllFileNamesFound
del "%AllFileNames%"
del "%NotFoundFileNames%"
goto EndBatch
:NoListFile
echo %~f0:
echo Error: No list file %ListFile%
goto EndBatch
:NoSourceFolder
echo %~f0:
echo Error: No folder %SourceFolder%
:EndBatch
endlocal
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
dir /?
findstr /?
goto /?
if /?
move /?
set /?
This is a method to give you a list of filenames which don't exist in the file.txt
#echo off
cd /d "c:\folder\to\check"
for %%a in (*) do findstr /i "%%~nxa" "file.txt" >nul || echo "%%a" is missing
pause
It uses %%~nxa instead of %%a in case subdirectories are used at some point.

Findstr batch file in finding listener down servers

Hi I'm trying to create a batch file to filter out servers which has RDP/ICA listener down from a list of servers in a notepad file, I created this script with the below syntax, but for some reasons it won't work as expected, can some one help me fix the situation?
I've a list of servers in computer.txt file and I'm trying to find the one's which are down and if errorlevel is 0, meaning the string down is found, I want the server name to be printed in listenerdown.txt , but for some reasons, if I execute the batch file, all the servers in computer.txt gets written to listenerdown.txt file
below is the batch file
for /f %%i in (computer.txt) do(
qwinsta /server:%%i | findstr/i down >nul 2>&1
if %errorlevel% neq 1
echo %%i >>Listenerdown.txt
)
Move the echo onto the same line as the if statement or else use parentheses to establish scope and %ErrorLevel% will always be 0 because the variable does not get set in a loop without delayed expansion.
setlocal EnableDelayedExpansion
for /f %%i in (computer.txt) do(
qwinsta /server:%%i | findstr /i down >nul 2>&1
if !errorlevel! neq 1 echo %%i>>Listenerdown.txt
)
endlocal
or
setlocal EnableDelayedExpansion
for /f %%i in (computer.txt) do(
qwinsta /server:%%i | findstr /i down >nul 2>&1
if !errorlevel! neq 1 (
echo %%i>>Listenerdown.txt
)
)
endlocal
Cmd.exe parses batch files line by line and unless you tell it that the scope of the command continues onto the next line it will think the command is finished.
You should use setlocal EnableDelayedExpansion, and !errorlevel! instead of %errorlevel%:
#echo off
setlocal EnableDelayedExpansion
for /f %%i in (computer.txt) do (
qwinsta /server:%%i | findstr/i down >nul 2>&1
if !errorlevel! neq 1 echo %%i >>Listenerdown.txt
)
otherwise the value of errorlevel would be expanded only once, before entering the loop, and would not have the correct value. You also have to make sure that echo is in the same row as the if.

Can I use a variable as the search string using the FIND command in a batch file?

I have a batch file that I'd like to compare the contents of two text files (test1.txt and test2.txt). I'd like it to search through each entry in test1.txt and look for each entry in test2.txt and advise whether the entry has been found or not. I've been searching around for some input, but can't seem to come up with anything helpful.
For example, test1.txt contains:
red
blue
green
orange
and test2.txt contains:
red
blue
orange
Ideally I'd like it to tell me it can't find "green"...
I was thinking it should be something like this:
#ECHO OFF
FOR /F %%A IN (C:\test1.txt) DO (
FIND /I %%A C:\test2.txt
IF %ERRORLEVEL% EQU 0 (ECHO Sring found!) ELSE (ECHO string not found!)
)
... but this doesn't prove to do much for me. Any help would be greatly appreciated!
Your code has two problems:
1) The FIND command requires the search string to be quoted.
2) Your logic is almost correct. The problem is %ERRORLEVEL% is expanded when the line is parsed, and the entire parenthesized DO() block is parsed in one pass. So it always expands to the value that existed before the FOR loop executes - not what you want.
There are a number of simple solutions.
Use delayed expansion
#ECHO OFF
setlocal enableDelayedExpansion
FOR /F %%A IN (C:\test1.txt) DO (
FIND /I "%%A" C:\test2.txt
IF !ERRORLEVEL! EQU 0 (ECHO Sring found^^!) ELSE (ECHO string not found^^!)
)
Use IF ERRORLEVEL (IF ERRORLEVEL 1 is true if errorlevel is 1 or greater)
#ECHO OFF
FOR /F %%A IN (C:\test1.txt) DO (
FIND /I "%%A" C:\test2.txt
IF NOT ERRORLEVEL 1 (ECHO Sring found!) ELSE (ECHO string not found!)
)
Use the && and || conditional operators
#ECHO OFF
FOR /F %%A IN (C:\test1.txt) DO (
FIND /I "%%A" C:\test2.txt && (ECHO Sring found!) || (ECHO string not found!)
)
You can just use findstr with parameter /V to print lines that don't contain a match, and /G to read search strings from a file. As dbenham suggested, it's better also to add the /L option to force a literal search, like this:
findstr /L /V /G:text2.txt text1.txt
This will print all lines in text1.txt that are not present in text2.txt

Determining if batch script has been started/executed from the command line (cmd) -or- To pause or not to pause?

I like to have a typical "usage:" line in my cmd.exe scripts — if a parameter is missing, user is given simple reminder of how the script is to be used.
The problem is that I can't safely predict whether potential user would use GUI or CLI. If somebody using GUI double-clicks this script in Explorer window, they won't have chance to read anything, unless I pause the window. If they use CLI, pause will bother them.
So I'm looking for a way to detect it.
#echo off
if _%1_==__ (
echo usage: %nx0: filename
rem now pause or not to pause?
)
Is there a nice solution on this?
You can check the value of %CMDCMDLINE% variable. It contains the command that was used to launch cmd.exe.
I prepared a test .bat file:
#Echo Off
echo %CMDCMDLINE%
pause
When run from inside of open cmd.exe window, the script prints "C:\Windows\system32\cmd.exe".
When run by double-clicking, it prints cmd /c ""C:\Users\mbu\Desktop\test.bat" "
So to check if your script was launched by double-clicking you need to check if %cmdcmdline% contains the path to your script. The final solution would look like this:
#echo off
set interactive=1
echo %cmdcmdline% | find /i "%~0" >nul
if not errorlevel 1 set interactive=0
rem now I can use %interactive% anywhere
if _%1_==__ (
echo usage: %~nx0 filename
if _%interactive%_==_0_ pause
)
Edit: implemented fixes for issues changes discussed in comments; edited example to demonstrate them
:: exit if not interactive
echo %CMDCMDLINE% | find /i "/c"
if not ERRORLEVEL 1 goto:eof
Here, I wrote something...
Usage.bat
#echo off
if arg%1==arg goto help
goto action
:action
echo do something...
goto end
:help
set help1=This is Help line 1.
set help2=This is Help line 2.
cmd.exe /k "echo %help1% &echo %help2%"
goto end
:end
It's not perfect, but it works! :D
-joedf
This is only using the internal command. so effectively....
EnableDelayedExpansion
if "!cmdcmdline!" neq "!cmdcmdline:%~f0=!" pause >nul
or
if not "!cmdcmdline!" == "!cmdcmdline:%~f0=!" pause >nul
DisableDelayedExpansion
if "%cmdcmdline%" neq "%cmdcmdline:%~f0=%" pause >nul
or
if not "%cmdcmdline%" == "%cmdcmdline:%~f0=%" pause >nul
Start your batch checking for %WINDIR% in %cmdcmdline% like this:
echo "%cmdcmdline%" | findstr /ic:"%windir%" >nul && (
echo Interactive run of: %0 is not allowed
pause
exit /B 1
)
Please use findstr
echo %cmdcmdline% | findstr /ic:"%~f0" >nul && ( pause >nul )
or
setlocal EnableDelayedExpansion
.
.
echo !cmdcmdline! | findstr /ic:"%~f0" >nul && ( pause >nul )
.
.
endlocal
This is always worked...
for internal command
setlocal EnableDelayedExpansion
set "cmddiff=!cmdcmdline:~0,1!" & if !cmddiff! neq ^" ( pause >nul )
endlocal
or
setlocal EnableDelayedExpansion
set "cmddiff=!cmdcmdline:~28,1!" & if !cmddiff! neq ^" ( pause >nul )
endlocal
You can compare the different thing, but this is only worked within EnableDelayedExpansion. and I don't think that this will be always worked, cause windows version, etc...
Similar approach...
setlocal
set startedFromExplorer=
echo %cmdcmdline% | find /i "cmd.exe /c """"%~0""" >nul
if not errorlevel 1 set startedFromExplorer=1
...
if defined startedFromExplorer pause
goto :EOF
setlocal EnableDelayedExpansion
if "!cmdcmdline!" neq "!cmdcmdline:%comspec%=!" ( pause>nul )
Test is done in Windows 10. Using %windir%, it is a little dangerous or ambiguous. So %comspec% is super safe.

Resources