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. https://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
How can this script be modified to delete files older than 30 days or better yet, can the “older than” be a variable?
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
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
The builtin command FORFILES combined with MOVE should be able to achieve most, if not all, of the above.
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.
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