Batch Files – Basic Error Checking and Running as Scheduled Tasks

Batch files may be considered “old hat” by a lot of people (or a complete mystery to the younger ones!) but they are sometimes still the easiest way to execute simple jobs as they have practically no requirements other than a command shell process to run within – yes there is a strong probability that a script could achieve an identical (or at least equivalent) result, but the fact is that it will be more complex and therefore longer to create and administer.

Something that trips up a fair number of people is the difference between double-clicking a .BAT file and scheduling it as a task to run at a certain time, on a trigger or on a schedule – it can seem that the batch file just simply does not run at all, and the return code sent back to the Task Scheduler is often 0x2, “path not found”, even though the file most definitely is there.

 

When you double-click a .BAT or .CMD file through Explorer, a cmd.exe process is started to provide the environment in which it will run.
The credentials used are your own (or more correctly, inherited from the Explorer process).
The “current working directory” is set to that where the batch file lives.

When the Task Scheduler service starts the same batch file it actually invokes an instance of cmd.exe (as SYSTEM impersonating the user whose credentials are defined in the task) to carry out the process and waits for it to exit with a return code – the current working directory for this process is not that of the batch file, but that of cmd.exe itself.
i.e. %windir%\system32

 

Now, if your batch file assumes that you launched it through Explorer or from an existing command prompt with the current working directory set to its own location, you can run into problems.

One simple way to verify if your batch file should work as a scheduled task is to call it from an existing cmd.exe process from a different current working directory (such as your profile, or a temp folder).

Be very, very careful if your batch file does any kind of file deletion – especially if wildcards are involved – you do not want to be in the wrong context when doing this (especially not a system folder or your profile!).

 

The trick is to do some basic error checking at the start and throughout your batch files, and possibly even some rudimentary logging by piping messages to a file.

One simple solution is to have the batch file set the current working directory itself as one of its first tasks.
e.g. cd /d “J:\Batch Jobs\mrsnrub”
(The “/d” switch is used to set the current drive as well as the directory, and the quotation marks are essential if the path contains any spaces.)

An alternative is to have every action explicitly have a fully qualified path, but this can make things a lot harder to read later.

 

As far as basic error checking goes, it is always wise to check for the existence of essential files before working with them – a simple “if exist” condition can control a single statement (or alternatively “if not exist” can be used to jump to somewhere else in the batch file).

For simple logging, the “>” instruction will start a new log and “>>” will append to it.

 

Putting the theory together for a simple example:

@echo off
echo [%date% - %time%] Log start > %temp%\MyBatch.log
if not exist "J:\Batch Jobs\mrsnrub\" goto ERROR1
cd /d "J:\Batch Jobs\mrsnrub"
if exist "GetFiles.txt" ftp –s:GetFiles.txt
goto END
:ERROR1
echo Unable to locate folder containing FTP script, aborting
echo ERROR – folder not present >> %temp%\MyBatch.log
:END

This isn’t the most flexible of solutions and it doesn’t log success or failure of attempting to launch FTP.EXE with the script file, but hopefully it should serve as an example of how to achieve basic logging and error checking (including piping the current time and date to a log file, as this is often essential).

 

One last useful tip is to output or log the “last error” as the last action, using the ERRORLEVEL variable within the batch file – 0 is generally used to indicate “no error”:
ECHO Batch file return code: %ERRORLEVEL%
ECHO Batch file return code: %ERRORLEVEL% >> %temp%\MyBatch.log

 

One of the best friends you have for debugging batch files is Process Monitor – this lets you verify your batch file (as a cmd.exe process, remember) and lets you see what it was trying to do, along with the results, in particular the Tools / Process Tree view is of great value when looking at the parent/child relationship between processes (ensure to uncheck the “Only show processes still running at the end of current trace” option).

There is a lot more power to batch file programming, this is just scratching the surface, but the main principle here is to ensure you have the right context when executing commands.

Comments

  • Anonymous
    January 01, 2003
    Ah, yes, I see - the "%time:0,2%" will indeed pull exactly 2 characters from the %time% string, including a leading space rather than a 0 if that is how the locale is set up. What you could do is to store "%time:0,1%" into a temporary variable, then test it against " " - if it matches then reset it to "%time:1,1%", then use the temporary variable in the filename (whether or not it was altered, it will now be correct). You also have the option to prepend a leading 0 if you wish, to help with sorting by filename or consistency of the naming convention. HTH, Paul

  • Anonymous
    January 01, 2003
    You need a bunch of "GOTO :EOF" statements there - first before the ":raw" label just so if you edit the set of games later but forget to add a new case, and as a replacement for every instance of "cls".

    You don't need the pause either - if the idea is to keep the command prompt window open while the selected game is playing then use "start /w" to launch the executable and wait until it exits.

  • Anonymous
    January 01, 2003
    The comment has been removed

  • Anonymous
    January 01, 2003
    The comment has been removed

  • Anonymous
    January 01, 2003
    good one.

  • Anonymous
    January 01, 2003
    Perfect!My issue fixed. Thank you!

  • Anonymous
    January 01, 2003
    Hi Jon, I'm not sure how you can schedule a task without knowing the path to the batch file... but in case you're looking at simply picking up the drive letter for a batch file launched interactively by a user, the environment variable %CD% can be used to get the folder for a batch file when invoked through Explorer, and if you wanted only the drive letter then you can use %CD:~0,2%. Otherwise, I can only suggest cycling through the drive letters using "IF EXIST" to find the batch file name, but that might throw "drive not ready" errors for removable drives such as CD/DVD drives & card readers. Cheers, Paul

  • Anonymous
    January 01, 2003
    Hi Baljeet, You can use %ERRORLEVEL% as described to check the status after calling the executable - if it is 1 (or higher) then some kind of error was returned either in calling the executable (e.g. not found, access denied) or by the executable itself. Batch files are limited in their ability to handle files, and logs are generally manually reviewed to see if corrective action is needed - return values & error levels are typically used for automated error handling. Automated parsing of log files usually requires a lot more complex actions, such as regular expressions or a grep-like utility. Cheers, Paul

  • Anonymous
    February 20, 2012
    Can you tell me how to specify command if connect to ftp fail or files could not be copied? thank you

  • Anonymous
    July 23, 2012
    The comment has been removed

  • Anonymous
    October 19, 2012
    Hi, How do I write a batch file to copy files when the starting file location is uncertain (eg running from a usb stick on a random computer) as a batch file starts running from %windir%system32?

  • Anonymous
    October 23, 2012
    The comment has been removed

  • Anonymous
    October 29, 2012
    The problem was actually that if I schedule it at 4am, the 2 digit for "hour" would actually have a space like " 4" rather than "04" and the result would be funny. Thanks for the help.

  • Anonymous
    March 13, 2013
    Hi Kevin, i use this script to compress all .txt and .cpi files into the backup folder in separated files with 7zip. After the files are zipped i delete the original files. However this script has a logical flaw. Lets say if the 7zip program fails to run, the files will also get deleted. How can i change the script so that it should not delete the files if they don't get zipped first. Also how can i change this script so it zips files that are older than 7 days? Thanks for your help. @echo off setlocal set _source=C:test7zipbak set _dest=C:test7zipbak set _wrpath=C:Program Files7-Zip if NOT EXIST %_dest% md %_dest% for %%I in (%_source%.txt,%_source%.cpi) do "%_wrpath%7z" a "%_dest%%%~nI.7z" "%%I" & del "%%I" pause Thanks, Jason

  • Anonymous
    April 18, 2014
    I am also making a batch that could open the file but it opens every file written to it plz help
    echo off
    Title GAME @ DX's KKS
    set /p ks=Select any 1 game and Type its name {WWE, NFS, COD, MAX PAYNE, ENTER THE MATRIX or Resident evil (Type as given here)}
    if %ks%==WWE goto raw
    if %ks%==wwe goto raw
    if %ks%==NFS goto speed
    if %ks%==nfs goto speed
    if %ks%==COD goto duty
    if %ks%==cod goto duty
    if %ks%==max payne goto kk
    if %ks%==MAX PAYNE goto kk
    if %ks%==enter the matrix goto 123
    if %ks%==ENTER THE MATRIX goto 123
    if %ks%==resident evil goto evil
    if %ks%==RESIDENT EVIL goto evil
    :raw
    "D:WORLD CLASS APPSKKSWWERAW.exe"
    cls
    :speed
    "D:WORLD CLASS APPSNEED FOR SPEED GAMESNFS U2speed2.exe"
    cls
    :duty
    "D:WORLD CLASS APPSCall of DutyDataCoDSP.exe"
    cls
    :kk
    "D:WORLD CLASS APPSMax payne 2Max Payne 2MaxPayne2.exe"
    cls
    :123
    "D:WORLD CLASS APPSMATRIXMatrix.exe"
    cls
    :evil
    "D:WORLD CLASS APPSResident Evil 4game_me.exe"
    cls
    PAUSE

  • Anonymous
    June 02, 2014
    Thanks !! that helped