Link to home
Start Free TrialLog in
Avatar of altquark
altquark

asked on

CMD Script on Windows causes Batch Recursion error and aborts

Hi Guys

I've created a script that emails users when a file in a directory is more than 20 minutes old.  The script works really well, but after running for about 24 hours or so, it errors out with the following error :
******  B A T C H   R E C U R S I O N  exceeds STACK limits ******
Recursion Count=428, Stack Usage=90 percent
******       B A T C H   PROCESSING IS   A B O R T E D      ******
and I have to restart the script again.

The script looks at the spool directory on the local windows machine, and compares the creation date of the file against the system time.  If there is no file that is older than 20 minutes, then the script sleeps for 1 minute.  If there is a file older than 20 minutes, the script uses the vbscript to pull information about the print queue, and uses a program called "gbmail" to send an email to a distribution list (contained in emails.txt) with the output from the vbscript and then sleeps for 5 minutes before going back to the top of the script.

The following is the script (I modified slightly it to remove security information)

@echo off
:: Wmic removes regional differences - it has problems with commas in filenames.
:top
@echo iteration

setlocal

for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%" & set "Min=%dt:~10,2%" & set "Sec=%dt:~12,2%"

set "stamp=%YYYY% %MM% %DD% %HH% %Min%"

call :DateToMinutes %stamp% NowMins

for /f "delims=" %%a in ('dir C:\Windows\System32\spool\PRINTERS\*.SPL /a-d /b') do call :CheckMins "%%a"
goto :Restart

:CheckMins
::echo checkmins
set "filestamp="
set "filemins="
set "MinsOld="
set "YY=" & set "YYYY=" & set "MM=" & set "DD="
set "HH=" & set "Min=" & set "Sec=" & set "dt="
set "file=%~1"
set "filea=%file:\=\\%"
WMIC DATAFILE WHERE name="C:\\Windows\\System32\\spool\\PRINTERS\\%file%" get lastmodified | find "." >file.tmp
for /f %%a in (file.tmp) do set "dt=%%a"
set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%" & set "Min=%dt:~10,2%" & set "Sec=%dt:~12,2%"
set "filestamp=%YYYY% %MM% %DD% %HH% %Min%"
::echo %filestamp%
del file.tmp 2>nul

if not defined yyyy goto :EOF

call :DateToMinutes %filestamp% FileMins

set /a MinsOld=%NowMins%-%FileMins%
::echo Now:%NowMins% File:%FileMins% Fileage:%minsold% "%~1"
if %MinsOld% gtr 20 goto DoThis
goto :Restart

:DateToMinutes
setlocal
set yy=%1&set mm=%2&set dd=%3&set hh=%4&set nn=%5
if 1%yy% LSS 200 if 1%yy% LSS 170 (set yy=20%yy%) else (set yy=19%yy%)
set /a dd=100%dd%%%100,mm=100%mm%%%100
set /a z=14-mm,z/=12,y=yy+4800-z,m=mm+12*z-3,j=153*m+2
set /a j=j/5+dd+y*365+y/4-y/100+y/400-2472633
if 1%hh% LSS 20 set hh=0%hh%
if /i {%nn:~2,1%} EQU {p} if "%hh%" NEQ "12" set hh=1%hh%&set/a hh-=88
if /i {%nn:~2,1%} EQU {a} if "%hh%" EQU "12" set hh=00
if /i {%nn:~2,1%} GEQ {a} set nn=%nn:~0,2%
set /a hh=100%hh%%%100,nn=100%nn%%%100,j=j*1440+hh*60+nn
endlocal&set %6=%j%&goto :EOF

:DoThis
::echo oldfile "%file%"
::c:\batch\sysinternals\handle %file%
for /f "tokens=1,2,3,4* delims=. " %%a in ("%file%") do set spoolno=%%a
set spoolno=%spoolno:0=%
cscript C:\Windows\System32\Printing_Admin_Scripts\en-US\prnjobs.vbs -l -j %spoolno% >c:\batch\spoolfile.txt

for /f "tokens=*" %%a in (emails.txt) do C:\batch\gbmail.exe -to %%a -h smtp.host.com -from sender@host.com -s "%file% has been in the system for %MinsOld% minutes on %COMPUTERNAME%" -file spoolfile.txt >nul
::After emailing - sleep for 5 minutes
c:\batch\sleep 300

:Restart
c:\batch\sleep 60
Goto :top

Open in new window


I'd really appreciate it if someone could point me to a solution to prevent the recursion from happening.  Thankyou in advance !
Avatar of Bill Prew
Bill Prew

What is the name of the BAT file you are running and posted here?

~bp
Looking a little further, my initial thought would be that you are not returning from the "call :CheckMins" inside a FOR loop.  Rather you use GOTO statements during that call to restart the script at the top, and enter the FOR loop again.  This likely leaves the prior FOR loop waiting for the "call :CheckMins" toi return, which it never does.  Over time these pile up until it aborts.

I'll look at what the code is doing a little more and try to make a recommendation to correct.

~bp
Avatar of altquark

ASKER

Hi bill - the file name can be anything.  Currently it's called "testit.bat" !
ASKER CERTIFIED SOLUTION
Avatar of Bill Prew
Bill Prew

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Bill

The main issue has definitely gone - but now I'm getting a "Maximum setlocal recursion level reached." message.  This happens every minute now.  This doesn't seem to stop the batch program from running - so I'm in a lot better position.  However, its still annoying - can you shed some light onto this new error ?

Jon
Try moving line 7 above line 4.

~bp
ok - Modified and testing....I'll let you know how it goes !
It looks good after 7 hours.  So, I'm going to accept your script as a solution !  Thankyou !
Move line 7 (setlocal) to line 4 (before the :top) and it works great !  Thankyou !
Excellent, thanks for the feedback, glad that was helpful.

~bp