3

What is the correct syntax for testing the errorlevel of TASKKILL in the context of the batch file shown below?

:Launch
   start "CloseMe" "C:\Program Files\internet explorer\iexplore.exe" "file://C:\ProgramData\Schneider Electric\Citect SCADA 2016\User\1173051_SM_STP\Files\Stony Mountain Institute Lift Station.html"
   TIMEOUT 1 & 
:ShiftFocus
   wscript "C:\ProgramData\Schneider Electric\Citect SCADA 2016\User\1173051_SM_STP\Files\SendAltTab.vbs"
   TASKKILL /IM iexplore.exe /FI "WINDOWTITLE eq CloseMe - Internet Explorer"
   if %errorlevel% == 1 GOTO ShiftFocus
:End
exit

I'm trying to get my batch file to run TASKKILL then test the result.

If the result is "INFO: No tasks running with the specified criteria." I need the batch file to try TASKKILL again.

If the result is "SUCCESS: Sent termination signal to ... ." I need the batch file to close.

To accomplish this I'm using if statements, labels and gotos which I learned about here and here.

I'm suspect I'm using errorlevel incorrectly because no matter what TASKKILL does its errorlevel, from my batch files perspective, is 0. Some answers to similar posts are using %errorlevel% and others are using errorlevel. No matter which I use in my batch file its sees an error level of 0 regardless of the actual result of TASKKILL.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
mike_yung
  • 117
  • 2
  • 11

4 Answers4

4

The taskkill clears ErrorLevel when you have provided a filter /FI which results in no match! However, when you only filter for image names (/IM) or process IDs (/PID), ErrorLevel becomes set to 128 if no matches have been encountered.

Therefore I would prefilter the processes by tasklist and use taskkill together with its /PID filter:

:LOOP
rem // Establish a short wait time to not heavily load the processor:
> nul timeout /T 1 /NOBREAK
rem // Prefilter processes and retrieve the PID of the applicable one:
set "PID=" & for /F "tokens=1* delims=:" %%T in ('
    tasklist /FI "IMAGENAME eq iexplore.exe" /FI "WINDOWTITLE eq CloseMe - Internet Explorer" /FO LIST
') do if "%%T"=="PID" for /F %%W in ("%%U") do set "PID=%%W"
rem // Loop back in case no PID could be retrieved:
if not defined PID goto :LOOP
rem // Try to kill the task and loop back in case of failure:
taskkill /PID %PID% || goto :LOOP
aschipfl
  • 33,626
  • 12
  • 54
  • 99
2

Open a command prompt window and run if /?. The output help explains how to correct check for an errorlevel with command IF using the syntax if errorlevel X ... working since MS-DOS and also within a command block.

if %errorlevel% == 1 goto ShiftFocus does not work in a command block starting with ( and ending with matching ) as beginners in batch file writing expect because of Windows command processor replaces all occurrences of %variable% in entire command block by value of referenced environment variable before the command block is executed at all. This can be seen on running a batch file without @echo off from within a command prompt window.

See also single line with multiple commands using Windows batch file explaining how to evaluate the exit code of a command or application with if errorlevel X ... or using the operators && and ||.

It is also possible to use if errorlevel 1 if not errorlevel 2 goto ShiftFocus which means exit code is greater or equal 1 but is not greater or equal 2, i.e. like if ((errorlevel >= 1) && (errorlevel < 2)) in C, C++, C#, JavaScript, etc., in case of an explicit test on exit code 1 is wanted with excluding exit code 128.

It would be also possible to enable delayed expansion and use it as explained by help of command SET output on running set /? in a command prompt window with if !errorlevel! == 1 goto ShiftFocus. But usage of delayed expansion which can cause other troubles and make batch file processing slower because of double parsing of each command line is really not recommended by me on using it just for evaluation of exit code of a command or application.

However, the real problem is that on Internet Explorer not running the batch file should jump to label ShiftFocus according to explanation in question which can be simply achieved by using if errorlevel 128 goto ShiftFocus.

So the entire batch file could be:

:Launch
start "CloseMe" "C:\Program Files\Internet Explorer\iexplore.exe" "file://C:\ProgramData\Schneider Electric\Citect SCADA 2016\User\1173051_SM_STP\Files\Stony Mountain Institute Lift Station.html"
%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK >nul

:ShiftFocus
%SystemRoot%\System32\wscript.exe "C:\ProgramData\Schneider Electric\Citect SCADA 2016\User\1173051_SM_STP\Files\SendAltTab.vbs"
%SystemRoot%\System32\taskkill.exe /IM iexplore.exe /FI "WINDOWTITLE eq CloseMe - Internet Explorer"
if errorlevel 128 %SystemRoot%\System32\timeout.exe /T 1 /NOBREAK >nul & goto ShiftFocus

exit /B

It is better to use the console applications (external commands) with full path and file extension to make the batch file independent on environment variables PATH and PATHEXT.

And command exit should not be used without option /B as it makes testing a batch file very difficult on running it from within a command prompt window instead of double clicking it. See debugging a batch file for the details.

There is one extra wait for one second added before jumping to ShiftFocus and running the script once again because rapidly running the script and taskkill in a loop does not make sense to me.

But this batch file does not work for the reason explained by aschipfl: TASKKILL does not exit with value 128 as written by CatCat on using filter option /FI and there is not running process matching the filter.

A language independent solution to work around this quirks of TASKKILL was posted by aschipfl.

A language dependent solution would be using this batch file:

:Launch
start "CloseMe" "C:\Program Files\Internet Explorer\iexplore.exe" "file://C:\ProgramData\Schneider Electric\Citect SCADA 2016\User\1173051_SM_STP\Files\Stony Mountain Institute Lift Station.html"
%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK >nul

:ShiftFocus
%SystemRoot%\System32\wscript.exe "C:\ProgramData\Schneider Electric\Citect SCADA 2016\User\1173051_SM_STP\Files\SendAltTab.vbs"
for /F "delims=:" %%I in ('%SystemRoot%\System32\taskkill.exe /IM iexplore.exe /FI "WINDOWTITLE eq CloseMe - Internet Explorer"') do if "%%I" == "INFO" %SystemRoot%\System32\timeout.exe /T 1 /NOBREAK >nul & goto ShiftFocus

exit /B

The TASKKILL command line is executed by FOR in a separate command process started with cmd /C in background. The line output by TASKKILL to handle STDOUT in this background command process is captured by FOR. Then the captured line is split into substrings using colon as delimiter. The string up to first colon is assigned to loop variable I. This string is here language dependent either INFO or SUCCESS. In case of INFO no instance of Internet Explorer was found with window title CloseMe - Internet Explorer resulting in a jump to ShiftFocus after 1 second and running the VBScript and TASKKILL once again.

This Windows language dependent solution should not be used if the batch file should run on any Windows machine with Windows Vista or a later Windows version independent on language of Windows.

Mofi
  • 46,139
  • 17
  • 80
  • 143
1
taskkill /f /im wscript.exe
echo %errorlevel%
pause

%errorlevel% is

0 for success

1 for Access Denied

128 for nothing to kill

Albert Einstein
  • 7,472
  • 8
  • 36
  • 71
CatCat
  • 483
  • 4
  • 5
0

You can keep your filters, when you pipe the output to a find command, so you evaluate the errorlevel of find instead of the errorlevel of taskkill:

:ShiftFocus
...
TASKKILL /IM iexplore.exe /FI "WINDOWTITLE eq CloseMe - Internet Explorer" | find "SUCCESS:" && goto :eof
goto :ShiftFocus

or

:ShiftFocus
...
TASKKILL /IM iexplore.exe /FI "WINDOWTITLE eq CloseMe - Internet Explorer" | find "No tasks running" && goto :ShiftFocus
Stephan
  • 53,940
  • 10
  • 58
  • 91