I am trying to create a batch file to restart multiple computers from a TXT file. Everything works fine as long as the /c "comment here" parameter has no spaces. If I pass "Testing" as the comment, I get "Testing" in the pop-up for the restart, as expected. If I pass "Testing spaces" as the comment, I still only get "Testing" in the pop-up. With #echo off, I have verified the comment retains the spaces when it is passed to VBS, so I think the problem is that I am running through an "invisible.vbs" script to prevent another CMD window from opening and hanging the original BAT script.
I would like to be able to have a final command run similar to:
shutdown /r /m \\127.0.0.1 /t 120 /c "Your computer will shut down for maintenance tasks in two minutes"
Any help with this would be greatly appreciated!
The essential part of restart.bat:
for /f "tokens=1-3" %%c in (%FilePath%) do WScript /nologo "%windir%\myscripts\invisible.vbs" "shutdown /r /m \\%%c /t %delay% /c %message%"
I have also tried adding extra quotes around %message% with no success:
for /f "tokens=1-3" %%c in (%FilePath%) do WScript /nologo "%windir%\myscripts\invisible.vbs" "shutdown /r /m \\%%c /t %delay% /c "%message%""
The invisible.vbs script (found on StackExchange):
CreateObject("Wscript.Shell").Run "" & WScript.Arguments(0) & "", 0, False
Any help would be greatly appreciated!
EDIT: Using your third method suggested, I am getting a script error:
Script: C:\Windows\myscripts\invisible.vbs
Line: 1
Char: 46
Error: The system cannot find the file specified
Code: 80070002
Source: (null)
EDIT 2: I just tried the first method also, and I now get a vbscript echo pop-up with the correct command that I wish to be sent, but the command is not sent. I am far from a programmer, and the only VBS I have used is stuff I have found online. I do appreciate the help you have offered so far, but I still can't get this to work.
You can not do it. The logic behind the Arguments object in WScript seems to remove quotes.
So, i can think in at least three alternatives
1) The most simple: use another character as an indicator of a quote and replace it with quote in the vbs script
cmd code : cscript myscript.vbs "shutdown /r /m \\%%c /t %delay% /c '%message%'"
vbs code : WScript.CreateObject("WScript.Shell").Run replace(WScript.Arguments(0),"'",""""), 0, False
The only problem with it is at some point, probably, you will need to use the placeholder character as a real character.
2) The most complex: use wmi to retrieve the current process id and from here retrieve the original command line of the script. A lot of code, if interested, here at StackOverflow there are some nice samples.
3) The easy, fast, and unusual. Use environment variables. Save the command into a variable and pass the name of the variable to the script. From it, retrieve the variable contents and use it
cmd code : set "runVar=shutdown /r /m \\%%c /t %delay% /c "%message%""
wscript //nologo "%windir%\myscripts\runInvisible.vbs" runVar
vbs code : With WScript.CreateObject("WScript.Shell") : .Run .ExpandEnvironmentStrings("%" & WScript.Arguments(0) & "%"), 0, False : End With
cmd code or bat code:
wscript //nologo invisible.vbs "hello world" 0
somehow the zero on the end, causes the part between quotes being seen as one argument still
Related
If a script which should get exited in subroutines without closing the terminal when calling EXIT 1. There for I use this if which calls the script again.
This worked fine until I now discovered some issue with a quoted vertical bar as a parameter "!". I get an error stating that the command is misspelled.
Here is the part of the script that fails:
#ECHO OFF
SETLOCAL DISABLEDELAYEDEXPANSION
IF "%selfWrapped%"=="" (
REM this is necessary so that we can use "exit" to terminate the batch file,
REM and all subroutines, but not the original cmd.exe
SET selfWrapped=true
%ComSpec% /s /c ""%~0" %*"
GOTO :EOF
)
echo %*
ENDLOCAL
EXIT /B 0
Call:
test.cmd "hello world" "|"
Expected Output:
"hello world" "|"
I checked the the value of %* inside the IF but for it seems totally legitimate to use a vertical bar as well as any other quoted string.
So...
Why does the script fails?
How can I fix it?
I do not agree with some of the description in the link.
See exit /? accurate help description.
exit exits the interpreter.
exit 1 exits the interpreter with exitcode 1.
exit /b has similar behavior as goto :eof which exits
the script or called label. Errorlevel is not reset so allows
errorlevel from the previous command to be accessable after
exit of the script or the called label.
exit /b 1 exits the script or the called label with errorlevel 1.
If you oddly use exit /b at a CMD prompt, it is going to exit the interpreter.
Main code:
#ECHO OFF
SETLOCAL DISABLEDELAYEDEXPANSION
SET args=%*
SET "self=%~f0"
IF "%selfWrapped%"=="" (
#REM this is necessary so that we can use "exit" to terminate the batch file,
#REM and all subroutines, but not the original cmd.exe
SET "selfWrapped=true"
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO !ComSpec! /s /c ""!self!" !args!"
"!ComSpec!" /s /c ""!self!" !args!"
GOTO :EOF
)
ECHO(%*
EXIT /B 0
Both use of GOTO :EOF and EXIT /B 0 will exit the script.
ENDLOCAL is implied at exit of the script.
Explicit use of ENDLOCAL is for when you want to end the
current local scope and continue the script. As always, being
explicit all the time is a choice.
Setting %* to args keeps the double quoting paired.
Quoting i.e. set "args=%*" can cause issue sometimes
though not using quotes allow code injection i.e.
arguments "arg1" ^& del *.*. If the del *.* is not going
to execute at the set line, then it will probably happen
at the ComSpec line. For this example, I chose not quote.
So, it is a choice.
You are using disabled expansion at start of the script. That
saves the ! arguments which is good. Before you execute
ComSpec though, enable delayed expansion and use !args!
which is now protected from the interpreter now not seeing |
or any other special character which may throw an error.
Your script fails as the | argument is exposed.
C:\Windows\system32\cmd.exe /s /c ""test.cmd" " | ""
The above is echoed evaluation of the ComSpec line with
setting #ECHO ON. Notice the pairing of quotes
i.e. "", " " and "". Notice the extra spacing inserted
around the | character as the interpreter does not consider
it as part of a quoted string.
Compared to updated code changes of echoed evaluation...:
"!ComSpec!" /s /c ""!self!" !args!"
The string between the quotes remain intact. No extra spacing
inserted into the string. The echoed evalution looks good and
executes good.
Disclaimer:
Expressing the workings of CMD is like walking a tight rope.
Just when you think you know, fall off the rope you go.
I don't see the necessity to append the parameter to your %ComSpec% /s /c ""%~0" %*" at all.
As you already use a variable (selfWrapped) to detect, if the wrapper call is necessary, you could also put your arguments into a variable.
set args=%*
Then you can simply use !args! in your child instance.
#ECHO OFF
setlocal DisableDelayedExpansion
IF "%selfWrapped%"=="" (
#REM this is necessary so that we can use "exit" to terminate the batch file,
#REM and all subroutines, but not the original cmd.exe
SET "selfWrapped=true"
SET ^"args=%*"
"%ComSpec%" /s /c ""%~f0""
GOTO :EOF
)
:Main
setlocal EnableDelayedExpansion
ECHO(!args!
EXIT /B 0
Now the only problem left, is the set args=%*.
If you can't control the content, then there is no way to access %* in a simple safe way.
Think of this batch invokations
myBatch.bat "abc|"
myBatch.bat abc^|
myBatch.bat abc^|--"|"
But you could use How to receive even the strangest command line parameters?
or Get arguments without temporary file
Btw. You could spare your child process, you can also exit from a function
Look at Exit batch script from inside a function
One correction to above answers.
Yes, ENDLOCAL is implied at the end of the script, but there's a catch.
I've found that with nested scripts, if you don't ENDLOCAL before you EXIT /B 1 you will not get your return code of 1 at the next level out script.
If you only ever EXIT /B 0, then this will not matter as the default return code is 0.
I am using a command:
find /c "abc" "C:\Users\abc\Desktop\project\string.txt"
Output:
---------- C:\Users\abc\Desktop\project\string.txt: 4
I want to assign this value 4 to a variable so that I can use it for an if statement.
I would use:
For /F %%A In ('Find /C "abc"^<"C:\Users\abc\Desktop\project\string.txt"') Do (
Set "mlc=%%A")
Your %mlc% varaiable would hold the matched line count.
I'm not sure if this is the best method to do this, but it works:
find /c "abc" "C:\Users\abc\Desktop\project\string.txt" > tmpFile
set /p myvar= < tmpFile
del tmpFile
with your snytax the output is ---------- C:\Users\abc\Desktop\project\string.txt: 4
There is another syntax: type file.txt|find /c "abc", which gives you a beautiful output of just:
15
To get it into a variable, use a for /f loop:
for /f %%a in ('type file.txt^|find /c "abc"') do set count=%%a
echo %count%
(for use directly on commandline (not in a batchfile) use %a instead of %%a)
I am not a batch script / Windows command line pro, but I got this to work with the following, without a temporary file:
for /f "delims=" %%a in ('dir "%~dpSomeFolder\*.suffix" /b ^|find /c "suffix"') do set "fileCount=%%a"
Explanation:
I found it very confusing, why assigning a variable with a batch script, is so weird, considering it's "Windows", the most used operating system. Anyways this answer here is helpful. Even if it is a duplicate, I like the formatting more:
Assign command output to variable in batch file
%~dp0: basically translates to "path of this script". You can find info about this online.
SomeFolder\*.suffix: In my case this I was looking to count the number of files ending with a certain suffix. I had problems using the dir command with \s as this listed all the matches in subfolders I did not expect him too look. As if this was referenced to the path from which I executed this script from. Therefore, the path name with the asterisk "\*.suffix" solved that issue for me.
^|: When using the pipe sign "|" in "for command", specified inside the single quotation marks, you need to use a circumflex "^|", instead of just the "|", which you would normally use when just typing in the command in cmd (f.e. like dir "%~dp0Folder*.suffix" /b | find /c "suffix"
%%a: You have to use the "double percentage", as this is just a locale variable when writing this in a batch script.
FYI: you can have a look at the command help/ manual ("man" as I am used to Linux), with the command /? (f.e. dir /? or find /?)
I thought I would also mention how I then used this variable, as this might save some time for you ;) (batch code coloring somehow did not work here...).
IF %fileCount% NEQ 1 (ECHO Number of SUFFIX files does not equal 1! Found %fileCount% SUFFIX files inside the SomeFolder. Aborting script! & PAUSE & EXIT)
I have set up a batch file to be default to open .txt files. In an earlier question I found out that %1 gives me the path of the file which was actually calling the batch file. The Problem is: if the file name contains white space, it gets interpreted as multiple parameters.
Example:
opening file "C:\Users\Desktop\space true.txt"
%1 gives:"C:\Users\Desktop\space" and then %2 gives: "true.txt"
How could I get just the full file path with the name and white space without trying to do a loop to attempt to get the full path by combining %1%2%3%4...
UPDATE-----------------------
Sorry there was a miss communication. The code below is working. The trick was to put "%*" instead of "%1"
here the code:
#echo on
set var= "%*"
c:
cd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar"%var%
pause
I do the whole changing the path, because the file which I double click and the the the batch file are in different directories. I had to change it to this.
UPDATE 2 --------------------------
The solution which worked best for me was from this fine gentlemen dbenham.
#echo off
pushd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar" %*
The only complain I have is, that there is a case, where %* does not return the path with quotes. So I am searching for a final solution. Something like this "%~*" But this doesn't work.
Thanks in advance
The following is not quite correct - I thought the file associations would put quotes around the file name like drag and drop does. But I was mistaken
This line is the source of your problem:
set var= "%*"
When files are dragged onto your batch script, or if a text file is double clicked, any file name(s) containing space will automatically be enclosed within quotes.
When you add your own additional quotes, it defeats the purpose of the quotes - the space is no longer quoted.
For example, a string like "name with space.txt" is treated as a single arg, but with added quotes, ""name with space.txt"" becomes three arguments.
There is no need for your var variable. You can use %* directly in your START command.
#echo on
pushd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar" %*
pause
I'm not sure the above works properly if multiple files are passed. I suspect you may want the following:
#echo on
pushd "C:\Users\MyText Editor"
for %%F in (%*) do start javaw -jar "MyTextEditor.jar" %%F
pause
There is one potential problem. Windows has a bug in that file names containing & are not automatically quoted as they should. See "Droplet" batch script - filenames containing ampersands for more info.
EDIT - The following should work
OK, I did some tests and I believe your best bet is to modify the command associated with .txt files.
I tested association changes via the command line. This must be done via an elevated command prompt with admin rights. On my machine I go to the Start menu, click on "All Programs", click on "Accessories" folder, right click "Command Prompt", and select "Run as administrator", then click "Yes" to allow the program to make changes to the system.
The following command will show which file type needs to be modified
assoc .txt
On my machine it reports .txt=txtfile, so txtfile is what must be modified using FTYPE.
I believe the following should work for you:
ftype txtfile="C:\pathToYourScrpt\yourScript.bat" "%1"
Obviously you would need to fix the path to your batch script :-)
Once you have made the change, the filename will automatically be quoted every time your script is invoked via a file association.
Your batch script can then look like the following, and it should work no matter how it is invoked (excepting drag and drop with file name containing & but no space):
#echo off
pushd "C:\Users\MyText Editor"
for %%F in (%*) do start javaw -jar "MyTextEditor.jar" %%F
It seems to me you should be able to eliminate the batch script and configure FTYPE TXTFILE to open your java editor directly. I should think something like the following:
ftype txtfile="c:\pathToJava\javaw.exe" -jar "C:\Users\MyText Editor\MyTextEditor.jar" "%1"
When calling your batch file, you must enclose your parameter in quotes if there is spaces in it.
E.g.: Batch.cmd "C:\Users\Desktop\space true.txt"
Eric
%*
Here's a list of characters.
& seperates commands on a line.
&& executes this command only if previous command's errorlevel is 0.
|| (not used above) executes this command only if previous command's errorlevel is NOT 0
> output to a file
>> append output to a file
< input from a file
| output of one command into the input of another command
^ escapes any of the above, including itself, if needed to be passed to a program
" parameters with spaces must be enclosed in quotes
+ used with copy to concatinate files. E.G. copy file1+file2 newfile
, used with copy to indicate missing parameters. This updates the files modified date. E.G. copy /b file1,,
%variablename% a inbuilt or user set environmental variable
!variablename! a user set environmental variable expanded at execution time, turned with SelLocal EnableDelayedExpansion command
%<number> (%1) the nth command line parameter passed to a batch file. %0 is the batchfile's name.
%* (%*) the entire command line.
%<a letter> or %%<a letter> (%A or %%A) the variable in a for loop. Single % sign at command prompt and double % sign in a batch file.
Your problem is really that the syntax of your set command is wrong. In a batch
file, a set command looks like this:
set "var=%1"
That will give you your variable exactly as received. If the user quoted it,
then the variable's value will have quotes around it. To remove the quotes,
you'd put a ~ in front of the number:
set "var=%~1"
Notice how the quotes go around the entire assignment, and not just around the
value you are assigning. It is not set var="%1".
If you use set var= "%*", you haven't really fixed the fundamental problem
that your syntax is wrong. Plus, often you really do want %1 and not the
entire command line.
Here is an example script to test various quoting behaviors:
#echo off
set var="%*"
echo 1. var="%%*" --^> [%var%] (wrong)
set "var=%*"
echo 2. "var=%%*" --^> [%var%]
set "var=%1"
echo 3. "var=%%1" --^> [%var%]
set "var=%~1"
echo 4. "var=%%~1" --^> [%var%]
set "var=%~2"
echo 5. "var=%%~2" --^> [%var%]
set "var=%~3"
echo 6. "var=%%~3" --^> [%var%]
And here is the output of that script. Note how arg1, arg2, and arg3 are all
quoted:
C:\batch> all_args.cmd "arg 1" "this is arg 2" "arg 3"
1. var="%*" --> [""arg 1" "this is arg 2" "arg 3""] (wrong)
2. "var=%*" --> ["arg 1" "this is arg 2" "arg 3"]
3. "var=%1" --> ["arg 1"]
4. "var=%~1" --> [arg 1]
5. "var=%~2" --> [this is arg 2]
6. "var=%~3" --> [arg 3]
You can see that numbers 4, 5, and 6 correctly pulled out their quoted arguments
and saved the value into var. You typically want to save the argument without quotes, and then quote it when you use it in your script. In other words, your script should look like this:
#echo on
set "var=%~1"
c:
cd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar" "%var%"
pause
#echo on
set var= "%*"
c:
cd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar"%var%
pause
Becomes removing redundant commands
start "" javaw -jar "C:\Users\MyText Editor\MyTextEditor.jar" "%*"
pause
Echo is already on unless turned off by you.
We don't put things into variables for no reason, and it's already in %*. It just makes convoluted code and removes meaning from the name of the variable.
When programming (unlike typing) we don't change paths (and cd /d C:\Users\MyText Editor does drive and folder anyway).
We specify full path on the command line. This makes your meaning quite clear.
The main problem was there was no space between .jar and %var% and start command the first quotes on the line are assumed to the CMD's window title. I would code the path to javaw and not use start. Start is asking the Windows' graphical shell to start the file, not CMD.
Here's a batch file that starts vbs files. I don't specify path to cscript as it's a Windows' command.
It's complexity is to make use fairly idiot proof and easy for others.
#echo off
Rem Make sure filter.vbs exists
set filter=
set filterpath=
Call :FindFilter filter.vbs
Rem Add filter.bat to the path if not in there, setx fails if it's already there
setx path %~dp0;%path% 1>nul 2>nul
Rem Test for some command line parameters
If not "%1"=="" goto main
echo.
echo -------------------------------------------------------------------------------
echo.
echo Filter.bat
echo ==========
echo.
echo The Filter program is a vbs file for searching, replacing, extracting, and
echo trimming console output and text files.
echo.
echo Filter.bat makes Filter.vbs easily usable from the command line. It
echo controls unicode/ansi support and debugging.
echo.
echo Type Filter Help or Filter HTMLHelp for more information.
echo.
cscript //nologo "%filter%" menu
Goto :EOF
:Main
echo %date% %time% %~n0 %* >>"%~dp0\FilterHistory.txt"
rem echo Batch file ran
rem echo %*
Rem /ud Unicode and Debug
If %1==/ud FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u //x %%j&Goto :EOF
Rem /u Unicode
If %1==/u FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u %%j&Goto :EOF
Rem /d Ansi Debug
If %1==/d FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //x %%j&Goto :EOF
Rem -ud Unicode and Debug
If %1==-ud FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u //x %%j&Goto :EOF
Rem /u Unicode
If %1==-u FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u %%j&Goto :EOF
Rem -d Ansi Debug
If %1==-d FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //x %%j&Goto :EOF
Rem ANSI
cscript "%filter%
" //nologo %*&Goto :EOF
Goto :EOF
:FindFilter
If Exist "%~dpn0.vbs" set filter=%~dpn0.vbs&set filterpath=%~dp0&goto :EOF
echo find filter 1
If Not "%~dpnx$PATH:1" == "" set filter=%~dpnx1&set filterpath=%~dp1&goto :EOF
echo find filter 2
If Exist "%temp%\filter.vbs" set filter=%temp%\filter.vbs&set filterpath=%temp%&goto :EOF
copy "%~dpnx0" "%~dpn0.bak"
if not errorlevel 1 (
echo creating "%~dpn0.vbs"
goto :EOF
)
copy "%~dpnx0" "%temp%\filter.bak"
echo Error %errorlevel%
if not errorlevel 1 (
echo creating "%temp%\filter.bak"
Goto :EOF
)
Goto :EOF
I am still stuck with this. Can anyone of you please help me out to figure out how to achieve this.
First of all, thanks for all your help!
I am in need of a batch script which need to do the following.
Suppose a path is there (D:\test)
Script should go to the above path and search for text files as in ( D:\test*.skc)
If .skc files are found. It should trigger a mail where all the .skc files should be mentioned in the mail body.
This should be running all the time like daemons and trigger the mail only if .skc is found.
Please help me achieving this.
I tried doing something from my end, where i am able to put the .skc files in a log file. but getting results as expected above.
please find my work below.
#echo off
set file_path="D:\test"
forfiles /d -0 /p %file_path% /m *.skc /c "cmd /c echo #file" >> "D:\test\example.log"
Or at-least please help me get the following.
The below batch script which will pull out all the files with extension .skc from a specific path and all this will be written in #file as below.
forfiles /d -0 /p %file_path% /m *.skc /c "cmd /c echo #file"
I need to put this #file in a variable, like
output=#file
echo %output%
Can you please help me achieve this?
#ECHO OFF
SETLOCAL
SET "logfiledir=u:\destdir"
SET "monitordir=u:\destdir"
ECHO(skc files report>"%logfiledir%\log.1"
SET /a nextlog=0
:monitor
SET /a prevlog=1-nextlog
ECHO(skc files report>"%logfiledir%\log.%nextlog%"
dir /b /a-d "%monitordir%\test*.skc" >>"%logfiledir%\log.%nextlog%" 2>NUL
FINDSTR /v /g:"%logfiledir%\log.%prevlog%" ".skc" "%logfiledir%\log.%nextlog%" >NUL 2>nul
IF NOT ERRORLEVEL 1 (
ECHO(CALL BLAT using "%logfiledir%\log.%nextlog%"
)
SET /a nextlog=(nextlog + 1) %% 2
timeout /t 2 >nul
GOTO monitor
Hmm - interesting exercise.
This batch allows you to set up the directory to keep thisbatch's logfiles and the directory to monitor separately.
It maintains files log.1 and log.0 and looks for changes.
First step is to create a dummy previous-log file with a set string and then establish which is the next logfile to use.
Within the loop, we derive the previous logfile name and generate a new version of the current logfile with our set string
append to the current logfile a /b (bare - names only) /a-d (and no directorynames) directory list of the directory to monitor.
Find whether there are any lines in the new file that are not in the old (setting errorlevel 0 if so, non-zero if not)
Invoke the email if there were new entries. I use blat - you pays your money, you takes your choice...
Then change the next logfile identity
wait (I chose 2 seconds for testing) and repeat ad infinitum.
The problem with findstr is that it doesn't like an empty exclude file (/g:...) so identical strings need to be inserted into each log file as dummies.
Don't remove the timeout otherwise this procedure will become a processor-hog.
I like to have a final PAUSE in my *.bat scripts so I can just double click on them in Windows explorer and have the chance to read the output. However, the final PAUSE is an annoyance when I run the same script from the command line.
Is there any way to detect whether we are running the script from a command prompt (or not) and insert the PAUSE (or not) accordingly?
(Target environment is Windows XP and greater.)
Update
I've managed to compose this from Anders's answer:
(((echo.%cmdcmdline%)|find /I "%~0")>nul)
if %errorlevel% equ 0 (
set GUI=1
) else (
set CLI=1
)
Then, I can do stuff like this:
if defined GUI pause
#echo off
echo.Hello World
(((echo.%cmdcmdline%)|find /I "%~0")>nul)&&pause
...NT+ only, no %cmdcmdline% in Win9x probably.
As pointed out by E M in the comments, putting all of this on one line opens you up to some edge cases where %cmdcmdline% will escape out of the parenthesis. The workaround is to use two lines:
#echo off
echo.Hello World
echo.%cmdcmdline% | find /I "%~0" >nul
if not errorlevel 1 pause
I doubt that there's a distinction, because I think it just starts a command prompt and then runs the bat when you double click on it.
However, if you make shortcuts to the bat files and go to Properties and add in an extra argument (something like "/p") in the "Target" field, then you could check for the presence of that argument at the end of the script and pause if it is set. Then, running from the shortcut would cause it to end in a pause and running from command line wouldn't.
I was hoping the answer by #Anders would work in its own .bat file. Unfortunately, it does not for me. Based on #DarinH's comment, perhaps it does for some. The script below should work for all, but requires an extra parameter.
The key lies in the %CmdCmdLine% environment variable, which I imagine might be a bit different for a few edge cases.
PauseIfGui.bat
#echo off
if "%~1" == "" ((echo.%CmdCmdLine%)|"%WinDir%\System32\find.exe" /I "%~0")>nul && pause & exit /b
((echo.%CmdCmdLine%)|"%WinDir%\System32\find.exe" /I "%~1")>nul && pause
This accepts one optional parameter: the full path of calling script. If no params are passed, it runs the same as #Anders script.
AnyOtherFile.bat
#echo off
call PauseIfGui.bat %~f0
If opened from Explorer (i.e. double-clicking) , AnyOtherFile.bat will pause. If called from a command prompt, it will not.