Delete old files by the last access date

Last Updated: 

👉 This post was initially written in 2006 and referred to specific software versions. When tunning your system, always consider which version you are running. Information below may be outdated. Use it at your own risk.

In my professionnal experience I had to manage many PC running with Windows XP. Those boxes were used for broadcasting video streams and download a lot of media files which aren't managed by our software. Naturally, I had to find a solution to dynamically purge the large amount of media files that were generated daily. As everyone working in system administration (I suppose...), I didn't have lot of time for doing this job and our software developper couldn't add the possibility to prune old files (still due to lot of projects and short timeline...), so I decided to use the Windows schedule (AT) and wrote a small batch file.

Below I describe each steps run by this script and that cover five parts:

Get and check the script arguments

I decide to use two arguments in this batch files, first one for define the directory path to purge (variable PURGE_DIR), the second one for define the minimum day of validity (variable DAY_LIMIT).

IF \[%1] == [\] ( GOTO :MISSING ) ELSE ( SET PURGE_DIR=%1 )
IF \[%2] == [\] ( GOTO :MISSING ) ELSE ( SET DAY_LIMIT=%2 )

As you can see, in case of missing arg I use a GOTO and a label MISSING. I use it for displaying a default help message. I think it's important to do this basical stuff because of the team work ! Many co-workers of mine doesn't know anything about batch script but touch the box, so it carefullest to display some help messages or error messages.

Checking dates (OS date format, maximum validity date)

Now we have to check the date format of the current Windows. I use the date format dd/MM/yyyy, any other date format could be use. You just have to adapt the code. In my case, most of the computer where install with this date format so I use it. For the misconfigured PC, I just have to go in the panel configuration fo windows for choose the appropriate date format. A nice tips posted by Mike Bikoulis is to define the date delimiter from the reg entry.

FOR /F "skip=4 tokens=3″ %%y IN ('REG QUERY "HKCU\Control Panel\International" /v sDate') DO (
SET DATE_DELIM=%%y
)

For checking the date format we have to use the system registry entry HKEY_CURRENT_USER\Control Panel\International\sShortDate. For checking the registry entry I use a FOR loop that skip the 4 first rows and take the third data considering a tab delimiter.

FOR /F "skip=4 tokens=3 delims= " %%y IN ('REG QUERY "HKCU\Control Panel\International" /v sShortDate') DO (
IF NOT "%%y" == "dd%DATE_DELIM%MM%DATE_DELIM%yyyy" GOTO :DATEFORMAT
)

Now that we are sure of our date format we can parse the DATE variable. I split this variable in three other variable YEAR, MONTH, DAY. In second time we check the validity of the day and month number because we can have a value with 1 or 2 characters.

:: SET CURRENT DATE MINUS DAYS ARGUMENT 
SET YEAR=%DATE:~6,4%  
SET MONTH=%DATE:~3,2%  
SET DAY=%DATE:~0,2%

IF %MONTH:~0,1% EQU 0 ( SET MONTH=%MONTH:~1,1% )  
IF %DAY:~0,1% EQU 0 ( SET DAY=%DAY:~1,1% )

I use a UNIX timestamp like as basis of my dates comparison, probably due to my habits to script under linux instead of windows. In fact, it's not a real unix timestamp but just some compute values, but that will be our reference for define the oldest date of validity for a file to delete. We store this value in the variable LIMIT_UNIX_TIMESTAMP.

SET /A LIMIT_UNIX_TIMESTAMP = (((%YEAR% \* 365) + (%MONTH% \* 31) + %DAY%) \* 24 \* 60 ) - ( %DAY_LIMIT% \* 24 \* 60 )

Parsing the directory to purge and get last access date of files

We have to parse the directory to purge for define the file list and getting their last access date. For doing this stuff I use again the FOR loop, quite useful IMHO ! 😉

Don't forget to use the option usebackq in case of file name with special character especially spaces. Each time that we get a file we set a variable CURRENT_FILE for a further usage then we pass the file properties to a subroutine named TESTSTRING. This subroutine is in charge to get the last access date of the file then send it to the finall subroutine that compare dates and delete old files.

FOR /F "usebackq delims=" %%a IN (`DIR /A:-D /B /S %PURGE_DIR%`) DO (

SET CURRENT_FILE=%%a  
IF EXIST "%%a" (

FOR /F "usebackq skip=5 tokens=1" %%b IN (`DIR /T "%%a"`) DO (  
CALL :TESTSTRING %%b  
)  
)  
)  
GOTO :END

:TESTSTRING  
FOR /F "tokens=1-3 delims=" %%c IN ("%1") DO (  
IF NOT \[%%e] == [\] (  
CALL :TESTDATE %%e %%d %%c  
)  
)

GOTO :END

Testing date and delete useless files

The last but not the less... We have to define a new variable that we'll use in our UNIX like date comparison. So, we define a FILE_UNIX_TIMESTAMP variable with the parameters passed to the subroutine TESTDATE. We compare FILE_UNIX_TIMESTAMP and LIMIT_UNIX_TIMESTAMP with a simple IF structure. Before delete file we still check that the file still exist, if it's the case we can delete the file by using the command DEL. We could use ERASE command but this command delete also subdirectories. This is really dangerous if used without precaution and could be really damageable !

:TESTDATE

SET YEAR=%1  
SET MONTH=%2  
SET DAY=%3

IF %MONTH:~0,1% EQU 0 ( SET MONTH=%MONTH:~1,1% )  
IF %DAY:~0,1% EQU 0 ( SET DAY=%DAY:~1,1% )

SET /A FILE_UNIX_TIMESTAMP = ((%YEAR% \* 365) + (%MONTH% \* 31) + (%DAY% \* 1 )) \* 24 * 60

IF %FILE_UNIX_TIMESTAMP% LSS %LIMIT_UNIX_TIMESTAMP% (  
IF EXIST "%CURRENT_FILE%" (  
ECHO DELETE "%CURRENT_FILE%"  
DEL /Q /F "%CURRENT_FILE%"  
)  
)

GOTO :END

Windows Schedule and coffee time !

Almost done, we now need to put our batch file in a windows schedule (for my part it's a daily schedule). Don't forget to give the two arguments to the script when configuring your schedule.

This script can be really useful if you have to manage lot of Windows XP computer on which you have to purge some directories and you don't want to go further in the windows possibilities (especially if you are most a linux user than windows user !).

Now you can go for your hourly coffee, and Voilà ! 😉

Below is the full source code with some comments.

::BATCH FILE FOR DELETE OLD FILES BY LAST ACCESS DATE
::AUTHOR "Nicolas Brousse"
@ECHO OFF

:: FIRST ARGS MUST BE THE PATH TO THE DIRECTORY TO PURGE
:: SECOND ARGS MUST BE A NUMBER OF DAYS
IF [%1] == [] ( GOTO :MISSING ) ELSE ( SET PURGE_DIR=%1 )
IF [%2] == [] ( GOTO :MISSING ) ELSE ( SET DAY_LIMIT=%2 )

:: WE GET THE PC LOCAL DATE DELIMITER (contrib from Mike Bikoulis)
FOR /F "skip=4 tokens=3" %%y IN ('REG QUERY "HKCU\Control Panel\International" /v sDate') DO (
SET DATE_DELIM=%%y
)

:: WE CHECK THE PC LOCAL SHORT DATE FORMAT
FOR /F "skip=4 tokens=2* delims=     " %%y IN ('REG QUERY "HKCU\Control Panel\International" /v sShortDate') DO (
IF NOT "%%z" == "dd%DATE_DELIM%MM%DATE_DELIM%yyyy" GOTO :DATEFORMAT
)

:: SET CURRENT DATE MINUS DAYS ARGUMENT
SET YEAR=%DATE:~6,4%
SET MONTH=%DATE:~3,2%
SET DAY=%DATE:~0,2%

IF %MONTH:~0,1% EQU 0 ( SET MONTH=%MONTH:~1,1% )
IF %DAY:~0,1% EQU 0 ( SET DAY=%DAY:~1,1% )

SET /A LIMIT_UNIX_TIMESTAMP = (((%YEAR% * 365) + (%MONTH% * 31) + %DAY%) * 24 * 60 ) - ( %DAY_LIMIT% * 24 * 60 )

:: PARSE THE DIRECTORY TO PURGE THEN CHECK FILES ON THEIR LAST ACCESS DATE
FOR /F "usebackq delims=" %%a IN (`DIR /A:-D /B /S %PURGE_DIR%`) DO (
SET CURRENT_FILE=%%a
IF EXIST "%%a" (

ECHO ---------------------------------------------------------
ECHO TEST "%%a"

FOR /F "usebackq skip=5 tokens=1" %%b IN (`DIR /T "%%a"`) DO (
CALL :TESTSTRING %%b
)
)
)

GOTO :END

:: GET FILE LAST ACCESS DATE
:TESTSTRING
FOR /F "tokens=1-3 delims=%DATE_DELIM%" %%c IN ("%1") DO (
IF NOT [%%e] == [] (
CALL :TESTDATE %%e %%d %%c
)
)
GOTO :END

:: TEST DATE WITH LIMIT_UNIX_TIMESTAMP
:: DELETE TOO OLD FILES, WE COULD DO AN ERASE BUT IT'S LESS SECURE
:TESTDATE

SET YEAR=%1
SET MONTH=%2
SET DAY=%3

IF %MONTH:~0,1% EQU 0 ( SET MONTH=%MONTH:~1,1% )
IF %DAY:~0,1% EQU 0 ( SET DAY=%DAY:~1,1% )

SET /A FILE_UNIX_TIMESTAMP = ((%YEAR% * 365) + (%MONTH% * 31) + (%DAY% * 1 )) * 24 * 60

ECHO    FILE_UNIX_TIMESTAMP  = %FILE_UNIX_TIMESTAMP%
ECHO    LIMIT_UNIX_TIMESTAMP = %LIMIT_UNIX_TIMESTAMP%

IF %FILE_UNIX_TIMESTAMP% LSS %LIMIT_UNIX_TIMESTAMP% (
IF EXIST "%CURRENT_FILE%" (
ECHO DELETE "%CURRENT_FILE%"
DEL /Q /F "%CURRENT_FILE%"
)
)

GOTO :END

:MISSING
ECHO USE : %0 [PATH] [DAYS]
GOTO :END

:DATEFORMAT
ECHO THIS PC HAS MUST HAVE A SHORT DATE FORMAT LIKE dd%DATE_DELIM%MM%DATE_DELIM%yyyy
GOTO :END

:END
Related windows posts that you may like...
8 Tips to Get the Most of an Old Windows XP
8 command line tips to get the most value of your old Windows XP, Windows Server 2003, and others.
Running Bash script with Ubuntu on Windows 10 using WSL
No-hassle! Learn how to run Bash on Windows by installing your favorite Linux distribution natively on Windows 10 using Windows Subsystem for Linux, aka WSL.
Removing ^M in imported Windows files
Learn how to quickly and easily handle files with newline and carriage return between linux, mac, and windows. This post will explain how to remove or replace the often annoying ^M character.