In my professionnal experience I have to manage many PC running with Windows XP. Those box are used for broadcasting some video flow and download lot of media files which aren’t managed by our software. Naturally, I had to find a solution for dynamically purge the lot of useless media files daily generated. 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 destroy old files (still due to lot of projects and short timeline…), so I decide to use the Windows schedule (AT) and doing a batch file.

As we had different software version - and for a maximum flexibility in case of any “kidding” evolution of this software - I take care to use arguments to my script. Here by I’ll describe all the process of this script that can be resume in five parts :

  1. Get and check our arguments
  2. Checking some dates (OS date format, maximum vailidity date)
  3. Parsing the directory to purge and get last access date of files
  4. Testing date and delete useless files
  5. Scheduling the batch file

This script is probably not the best way for doing this stuff, if you have suggestion and comments about it don’t hesitate to share with me your feeling ! ;-)

  • Get and check arguments

I decide to use two argument 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).

1
2
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 some 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.

1
2
3
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.

1
2
3
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.

1
2
3
4
5
6
7
:: 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.

1
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 usefull 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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 !

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
: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 !

Job is soon done, we juste have 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 usefull 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Ă  ! ;-)

Follow is the full source code with some comments.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
::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

Comments