A batch file that deletes files by age in a directory with multiple subdirectories

I need a batch file that will delete files from a directory and it's subdirectories that are older than 30 days.  I can't use the deltree command because there are files younger than 30 days that need to stick around.  I also don't want the .bat file to have to be in the directory because I don't want it deleting itself.  This is what I have so far but it only deletes files from the main directory and won't delete any from the subdirectories.

:: ---------------EXAMPLE.BAT-----------------
@ECHO on
:: Change directory
cd C:\Documents and Settings\user\Desktop\test\
:: ------------
:: This is where you set the number
:: of minutes you want subtracted
:: from the current date/time.
:: ------------
SET MyDays=30

:: ------------
:: Get current date/time
:: ------------
FOR /F "TOKENS=2-4 DELIMS=/ " %%F IN ('DATE /T') DO (
 SET YYYY=%%H
 SET MM=%%F
 SET DD=%%G
)

IF %DD% LSS 10 (SET DD=%DD:~1%)
IF %MM% LSS 10 (SET MM=%MM:~1%)

: ------------
:: Subtract days from current date.
:: ------------
SET /A DD=%DD% - %MyDays%

:: ------------
:: Do the massively painful
:: reverse calculations.. :(
:: ------------
:LoopDate
IF /I %DD% GTR 0 (GOTO DONE)
set /A mm=%mm% - 1
if /I %mm% GTR 0 goto ADJUSTDAY
set /A mm=12
set /A yyyy=%yyyy% - 1
:ADJUSTDAY
if %mm%==1 goto SET31
if %mm%==2 goto LEAPCHK
if %mm%==3 goto SET31
if %mm%==4 goto SET30
if %mm%==5 goto SET31
if %mm%==6 goto SET30
if %mm%==7 goto SET31
if %mm%==8 goto SET31
if %mm%==9 goto SET30
if %mm%==10 goto SET31
if %mm%==11 goto SET30
if %mm%==12 goto SET31
goto ERROR
:SET31
set /A dd=31 + %dd%
goto LoopDate
:SET30
set /A dd=30 + %dd%
goto LoopDate
:LEAPCHK
set /A tt=%yyyy% %% 4
if not %tt%==0 goto SET28
set /A tt=%yyyy% %% 100
if not %tt%==0 goto SET29
set /A tt=%yyyy% %% 400
if %tt%==0 goto SET29
:SET28
set /A dd=28 + %dd%
goto LoopDate
:SET29
set /A dd=29 + %dd%
goto LoopDate
:DONE
IF %dd% LSS 10 set dd=0%dd%
IF %mm% LSS 10 set mm=0%mm%

for %%i in (*.*) do (
 set FileName=%%i
 SET FTIME=%%~ti
 CALL :PROCESSFILE
)

set mm=
set yyyy=
set dd=
set thedate=
goto :EOF

:PROCESSFILE
set fyyyy=%FTIME:~6,4%
set fmm=%FTIME:~0,2%
set fdd=%FTIME:~3,2%

if /I %fyyyy% GTR 2069 set fyyyy=19%FTIME:~6,2%

:: +*************************************+
:: | This is where the files are deleted |
:: | Change the ECHO command to DEL to   |
:: | delete. ECHO is used for test.      |
:: +*************************************+
if /I %yyyy%%mm%%dd% GEQ %fyyyy%%fmm%%fdd% (
  DEL %FileName%"
  ECHO Delete %FileName%
)
ECHO Cacldate=%yyyy%%mm%%dd%

set temp=
set fyyyy=
set fmm=
set fdd=

:EXIT
:: ----------END-EXAMPLE.BAT-------------

Please Help
LVL 2
whiting002Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

SteveGTRCommented:
Can your for loop from:

for %%i in (*.*) do (
 set FileName=%%i
 SET FTIME=%%~ti
 CALL :PROCESSFILE
)

to:

for /f "delims=" %%i in ('dir /s /b /a-d 2^>NUL') do (
 set FileName=%%i
 SET FTIME=%%~ti
 CALL :PROCESSFILE
)

Good Luck,
Steve
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Danny ChildIT ManagerCommented:
try the FORFILES.EXE server resource kit tool

example:
FORFILES -p"C:\Documents and Settings\user\Desktop\test" -s -m*.* -d-30 -c"CMD /C del @FILE"

-p = path
-s = include subdirs
-m = match filetype
-d = age in days (can also be set as an absolute date ie DDMMYYYY)
-c = command to execute

Note there are no spaces between the switches and their arguments.
info here:
http://www.jsiinc.com/SUBL/tip5600/rh5645.htm
Download it here:
http://www.dynawell.com/support/ResKit/winnt.asp
0
whiting002Author Commented:
Steve,

I tried your suggestion but now nothing deletes.

Dan
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

whiting002Author Commented:
DanCh99,

I was hoping to keep this as a normal batch file without any extra dependencies.  I figure this has to be an issue people have been facing for years and there has to be a solution out there.

Dan
0
SteveGTRCommented:
Place an echo statement above the date compare code:

echo if /I %yyyy%%mm%%dd% GEQ %fyyyy%%fmm%%fdd% (DEL %FileName%"  ECHO Delete %FileName%)

Let's see what it says.
0
whiting002Author Commented:
Steve,

I figured out why it wasn't deleting anything.  When I copied the code you provided at first, I left out a " in my delete statement.  Anyways that's taken care of but now instead of just deleting files that are 30 days or older it deletes everything.

This is what I get when the batch executes up till the deletion of the first file:
C:\Documents and Settings\jdw\Desktop\wat>cd C:\Documents and Settings\jdw\Deskt
op\test

C:\Documents and Settings\jdw\Desktop\test>SET MyDays=30

C:\Documents and Settings\jdw\Desktop\test>FOR /F "TOKENS=2-4 DELIMS=/ " %F IN (
'DATE /T') DO (
SET YYYY=%H
 SET MM=%F
 SET DD=%G
)

C:\Documents and Settings\jdw\Desktop\test>(
SET YYYY=2004
 SET MM=11
 SET DD=12
)

C:\Documents and Settings\jdw\Desktop\test>IF 12 LSS 10 (SET DD=2 )

C:\Documents and Settings\jdw\Desktop\test>IF 11 LSS 10 (SET MM=1 )

C:\Documents and Settings\jdw\Desktop\test>SET /A DD=12 - 30

C:\Documents and Settings\jdw\Desktop\test>IF /I -18 GTR 0 (GOTO DONE )

C:\Documents and Settings\jdw\Desktop\test>set /A mm=11 - 1

C:\Documents and Settings\jdw\Desktop\test>if /I 10 GTR 0 goto ADJUSTDAY

C:\Documents and Settings\jdw\Desktop\test>if 10 == 1 goto SET31

C:\Documents and Settings\jdw\Desktop\test>if 10 == 2 goto LEAPCHK

C:\Documents and Settings\jdw\Desktop\test>if 10 == 3 goto SET31

C:\Documents and Settings\jdw\Desktop\test>if 10 == 4 goto SET30

C:\Documents and Settings\jdw\Desktop\test>if 10 == 5 goto SET31

C:\Documents and Settings\jdw\Desktop\test>if 10 == 6 goto SET30

C:\Documents and Settings\jdw\Desktop\test>if 10 == 7 goto SET31

C:\Documents and Settings\jdw\Desktop\test>if 10 == 8 goto SET31

C:\Documents and Settings\jdw\Desktop\test>if 10 == 9 goto SET30

C:\Documents and Settings\jdw\Desktop\test>if 10 == 10 goto SET31

C:\Documents and Settings\jdw\Desktop\test>set /A dd=31 + -18

C:\Documents and Settings\jdw\Desktop\test>goto LoopDate

C:\Documents and Settings\jdw\Desktop\test>IF /I 13 GTR 0 (GOTO DONE )

C:\Documents and Settings\jdw\Desktop\test>IF 13 LSS 10 set dd=013

C:\Documents and Settings\jdw\Desktop\test>IF 10 LSS 10 set mm=010

C:\Documents and Settings\jdw\Desktop\test>for /F "delims=" %i in ('dir /s /b /a
-d 2>NUL') do (
set FileName=%i
 SET FTIME=%~ti
 CALL :PROCESSFILE
)

C:\Documents and Settings\jdw\Desktop\test>(
set FileName=C:\Documents and Settings\jdw\Desktop\test\082604.txt
 SET FTIME=08/26/2004 06:27 AM
 CALL :PROCESSFILE
)

C:\Documents and Settings\jdw\Desktop\test>set fyyyy=2004

C:\Documents and Settings\jdw\Desktop\test>set fmm=08

C:\Documents and Settings\jdw\Desktop\test>set fdd=26

C:\Documents and Settings\jdw\Desktop\test>if /I 2004 GTR 2069 set fyyyy=1920

C:\Documents and Settings\jdw\Desktop\test>echo if /I 20041013 GEQ 20040826 (
if /I 20041013 GEQ 20040826 (

C:\Documents and Settings\jdw\Desktop\test>DEL "C:\Documents and Settings\jdw\De
sktop\test\082604.txt"

C:\Documents and Settings\jdw\Desktop\test>ECHO Delete C:\Documents and Settings
\jdw\Desktop\test\082604.txt
Delete C:\Documents and Settings\jdw\Desktop\test\082604.txt

C:\Documents and Settings\jdw\Desktop\test>PAUSE
Press any key to continue . . .

Dan
0
whiting002Author Commented:
Steve,

I got it working thanks so much for the help.  I do have one more question for you, I'm familiar with programming in VB and C but I've never done much with scripts.  Can you help me by commenting out some of this code for me so I can see exactly what everything is doing?  I'm a little confused for instance with "FOR /F "TOKENS=2-4 DELIMS=/ " %%F IN ('DATE /T') DO (", I realize this is a for statement but what is the '/F' and what is the '=/".  Also what does the '%' mean in a script.  Another question is the '/I' and the '/A' that are in the code, what are these.  Arrays maybe?  If you can help take me through this code I'll throw in an extra 100 points.  If you don't feel like it that fine to I'll still award you the 250 but I would like to learn a little bit about the batch scripting.


:: ---------------EXAMPLE.BAT-----------------
@ECHO OFF
:: ------------
:: This is where you set the number
:: of minutes you want subtracted
:: from the current date/time.
:: ------------
cd C:\Documents and Settings\jdw\Desktop\test
SET MyDays=30


:: ------------
:: Get current date/time
:: ------------
FOR /F "TOKENS=2-4 DELIMS=/ " %%F IN ('DATE /T') DO (
 SET YYYY=%%H
 SET MM=%%F
 SET DD=%%G
)

IF %DD% LSS 10 (SET DD=%DD:~1%)
IF %MM% LSS 10 (SET MM=%MM:~1%)

: ------------
:: Subtract days from current date.
:: ------------
SET /A DD=%DD% - %MyDays%

:: ------------
:: Do the massively painful
:: reverse calculations.. :(
:: ------------
:LoopDate
IF /I %DD% GTR 0 (GOTO DONE)
set /A mm=%mm% - 1
if /I %mm% GTR 0 goto ADJUSTDAY
set /A mm=12
set /A yyyy=%yyyy% - 1
:ADJUSTDAY
if %mm%==1 goto SET31
if %mm%==2 goto LEAPCHK
if %mm%==3 goto SET31
if %mm%==4 goto SET30
if %mm%==5 goto SET31
if %mm%==6 goto SET30
if %mm%==7 goto SET31
if %mm%==8 goto SET31
if %mm%==9 goto SET30
if %mm%==10 goto SET31
if %mm%==11 goto SET30
if %mm%==12 goto SET31
goto ERROR
:SET31
set /A dd=31 + %dd%
goto LoopDate
:SET30
set /A dd=30 + %dd%
goto LoopDate
:LEAPCHK
set /A tt=%yyyy% %% 4
if not %tt%==0 goto SET28
set /A tt=%yyyy% %% 100
if not %tt%==0 goto SET29
set /A tt=%yyyy% %% 400
if %tt%==0 goto SET29
:SET28
set /A dd=28 + %dd%
goto LoopDate
:SET29
set /A dd=29 + %dd%
goto LoopDate
:DONE
IF %dd% LSS 10 set dd=0%dd%
IF %mm% LSS 10 set mm=0%mm%

::for %%i in (*.*) do (
for /f "delims=" %%i in ('dir /s /b /a-d 2^>NUL') do (
 set FileName=%%i
 SET FTIME=%%~ti
 CALL :PROCESSFILE
)

set mm=
set yyyy=
set dd=
set thedate=
goto :EOF

:PROCESSFILE
set fyyyy=%FTIME:~6,4%
set fmm=%FTIME:~0,2%
set fdd=%FTIME:~3,2%

if /I %fyyyy% GTR 2069 set fyyyy=19%FTIME:~6,2%

:: +*************************************+
:: | This is where the files are deleted |
:: | Change the ECHO command to DEL to   |
:: | delete. ECHO is used for test.      |
:: +*************************************+
if /I %yyyy%%mm%%dd% GEQ %fyyyy%%fmm%%fdd% (
  DEL "%FileName%"
  ECHO Delete %FileName%
)
ECHO Cacldate=%yyyy%%mm%%dd%

set temp=
set fyyyy=
set fmm=
set fdd=

:EXIT
:: ----------END-EXAMPLE.BAT-------------
0
SteveGTRCommented:
No problem. First help is available for all the commands by typing command /? at the DOS prompt (example: if /?).

The for statement has been improved greatly. I'll breakdown the following:

FOR /F "TOKENS=2-4 DELIMS=/ " %%F IN ('DATE /T') DO (

The /F reads the file our output from the command in the (). In this case we have 'date /t'. The /t parameter of date just outputs the date:

Fri 11/12/2004

The delims option tells the for how to breakup the line items. The default is a space, but in this case we are using the date slash and a space. So the for statement will breakup the output from date into 4 tokens: Fri, 11, 12, 2004.

The tokens options says we want the 2nd through 4th token. This skips the day of week and extracts the 11, 12, and 2004. The %%f  is the variable for the 1st token, %%g for the 2nd, and %%h for the 3rd. If we used %%a then the tokens would be distributed from %%a to %%c. In our usage here is what the values would equate to:

%%f = 11
%%g = 12
%%h = 2004

The /I option is used for the if statement. It says to use case insensitive string compares. So "a" is equal to "A".

The /A option of the set statement allows you to activate numeric processing. For example:

set /a n=2 * 10
echo n=%n%

Would output 20.

The only thing you have to watch out for with set /a is octal numbers. This happens alot when parsing dates because of the leading zeros. I get around this by doing the following.

set mm=09
set /a mm=1%mm% - 100

This strips the leading zero by saying 109 - 100 = 9. If you didn't do this the next time you tried to use mm to say add 1 to the month you'd receive an error - invalid octal number.

I hope that helps :)
0
whiting002Author Commented:
Steve,

Thanks a lot I really appreciate it.

Dan Whiting
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft DOS

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.