Jumlins TechBlog

The coding hell and the daily IT of Niklas Jumlin

October 26th, 2010 by Niklas Jumlin

A colleague asked me if I could write a script that would move files within a folder or its subfolders that were older than one year into a new location but still keep the directory structure.
I figured it would be quite a challenge so I decided to do it for him; kind as I am =)

As I haven’t been providing this blog with something new in a long time I figured I could make it useful to more people if I added a few things, like different date formats and other various settings.

So here it goes:

REM Made by Niklas Jumlin. http://blog.jumlin.com
@echo off
cls
setLocal EnableDelayedExpansion
setLocal EnableExtensions
 
REM for safety precautions, nothing will actually run or be modified if you run this script.
REM to actually make us of this script you should edit the safety variable below to "no"
set safety=yes
if /i "%safety%"=="yes" set run=ECHO
if /i "%safety%"=="no" set run=@
 
set yourOldFolder=d:\folder-to-be-scanned
set yourNewFolder=e:\destination
set logfile=%AppData%\filemove_log.txt
set TmpFile=%AppData%\variables.txt
set debug=no
 
REM possible formats are "mm dd yyyy", "dd mm yyyy" and "yyyy mm dd"
set DateFormat=yyyy mm dd
REM possible separators are - (dash), / (slash) or . (dot)
set DateSeparator=-
 
REM script
dir /s /b /a:-D %yourOldFolder% > %TmpFile%
for /f "Tokens=* Delims= " %%a In (%AppData%\variables.txt) Do (
	REM from now on, to use variables set within this FOR loop, an expression sign (!) is needed at start and end of the variable. e.g !var! instead of %var%
	REM this also requires: setLocal EnableDelayedExpansion
	REM set a variable to modified date of the current file
	call set md=%%~ta
 
	REM split up dd/mm/yyyy hh:mm to yyyy, mm and dd	
	if "%DateFormat%"=="dd mm yyyy" (
		for /f "Tokens=1,2,3 Delims=%DateSeparator% " %%i In ('echo !md!') do set md=%%i& set mm=%%j& set my=%%k
		)
	REM split up yyyy-mm-dd hh:mm to yyyy, mm and dd	
	if "%DateFormat%"=="yyyy mm dd" (
		for /f "Tokens=1,2,3 Delims=%DateSeparator% " %%i In ('echo !md!') do set my=%%i& set mm=%%j& set md=%%k
		)
	REM split up mm/dd/yyyy hh:mm to yyyy, mm and dd	
	if "%DateFormat%"=="mm dd yyyy" (
		for /f "Tokens=1,2,3 Delims=%DateSeparator% " %%i In ('echo !md!') do set mm=%%i& set md=%%j& set my=%%k
		)
	REM merge vars into one var
	call set mdate=!my! !mm! !md!
 
	REM remove spaces in mdate
	call set mdate=!mdate: =!
 
	REM debug1
		if /i "%debug%"=="yes" (
			echo CASE:
			echo File: %%~na
			echo Path: %%~pa
			echo Filetype: %%~xa
			echo Filesize: %%~za byte
			echo Full filepath: %%a
			echo Full path: %%~da%%~pa
			echo Modified date: !mdate!
			)
	REM end of debug1
 
	REM get current date, split up dd/mm/yyyy hh:mm to yyyy, mm and dd	
	if "%DateFormat%"=="dd mm yyyy" (
		for /f "Tokens=1-4 Delims=%DateSeparator%" %%i In ('date /t') Do set cd=%%i& set cm=%%j& set cy=%%k
		)
	REM get current date, split up yyyy-mm-dd hh:mm to yyyy, mm and dd	
	if "%DateFormat%"=="yyyy mm dd" (
		for /f "Tokens=1-4 Delims=%DateSeparator%" %%i In ('date /t') Do set cy=%%i& set cm=%%j& set cd=%%k
		)
	REM get current date, split up mm/dd/yyyy hh:mm to yyyy, mm and dd	
	if "%DateFormat%"=="mm dd yyyy" (
		for /f "Tokens=1-4 Delims=%DateSeparator%" %%i In ('date /t') Do set cm=%%i& set cd=%%j& set cy=%%k
		)
	REM set YYYY - (MINUS) 1 year
	call set /a cy=!cy!-1	
	REM merge vars into one var
	call set cdate=!cy! !cm! !cd!
	REM remove spaces in cdate
	call set cdate=!cdate: =!
 
	REM debug2
		if /i "%debug%"=="yes" (
			echo. 
			echo ACTION:
			echo "%%~nxa" is modified "!mdate!"
			echo If it would have been modified "!cdate!" it would be moved.
			echo. 
			echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			echo.
			echo See how the action would look like?
 
			REM confirm
			set /p confirm=y/n?:
				if /i "!confirm!"=="y" (
					cls
					echo move %%a %yourNewFolder%\olderThanOneYear%%~pa%%~nxa 
					echo. 
					pause 
					cls
					)
			REM end of confirm
			)
	REM end of debug2
 
	REM actual job
		if !mdate! LEQ !cdate! (
			REM write to logfile
			echo. >> %logfile%
			echo File: %%a >> %logfile%
			echo Modified: !mdate! - above file is more than one year old, will be moved >> %logfile%
			echo New path: %yourNewFolder%\olderThanOneYear%%~pa%%~nxa >> %logfile%
			echo Will delete, if empty: %%~da%%~pa >> %logfile%
			REM create directory structure of parent directories in %yourNewFolder% path. Requires: setLocal EnableExtensions
			%run% mkdir %yourNewFolder%\olderThanOneYear\%%~pa
			REM move file to new destination
			%run% move %%a %yourNewFolder%\olderThanOneYear%%~pa%%~nxa
			REM delete parent directory if empty
			%run% rmdir %%~da%%~pa
			)
			REM end of actual job
	)
	REM end of script
 
:exit
echo. 
echo Logfile: %logfile%
echo. 
EndLocal
pause
Share on Facebook

6 Responses to “ Move files in folders and subfolders older than one year ”

  1. Mike says:

    How can this script be modified to delete files older than 30 days or better yet, can the “older than” be a variable?

  2. Yep. It can be rewritten for that purpose.
    I couldn’t really come up with a good solution to have it as a variable.

    Have a look here:

    REM set YYYY – (MINUS) 1 year
    call set /a cy=!cy!-1

    It takes cy (current year) and subtracts 1.
    You could write cm (current month) or cd (current day) at both occurrences on that line and subtract whatever you want to have it delete files older than what the result gives.
    Take note from whenever the month is 01 and you subtract 1, its gonna go 0.

    However!!!
    Any variable that has numbers “08” or “09” can not be calculated.
    They don’t work because some idiot decided that nums of the form 0x are octal.

    Have a look here:
    http://www.computing.net/answers/programming/batch-file-set-number-trouble/17354.html

    If you are fine with 08 and 09 not working then you could rewrite it like this:

    REM set MM – (MINUS) 1 month
    call set /a cm=!cm!-1
    REM fix for january
    if !cm!==01 set cm=12

  3. Rob D says:

    You’re a Legend, changed your script to move files older than 6 years by changing:
    call set /a cy=!cy!-1
    To
    call set /a cy=!cy!-6

    Brilliant!!

    Thanks

  4. TimT says:

    The builtin command FORFILES combined with MOVE should be able to achieve most, if not all, of the above.

  5. FORFILES is nothing that is built-in, but rather its something that can easily be integrated. Its part of Resource Kit (http://ss64.com/links/windows.html#kits) Cheers.

  6. Naresh says:

    Hi,

    I need some help with tweakingyour code.

    My Source folder is D:\CV
    My Destination is D:\
    Consider my source has a few folders.

    ACCORDING TO YOUR CODE, if I remane “olderThanOneYear” to “CV_Archive” the result after runnung the batch would be,

    D:\CV_Archive\CV\…\…\..txt

    The output I need is

    D:\CV_Archive\…\…\..txt

    I hope it is possible.

    Regards,
    Naresh

Leave a Reply