Monday, June 28, 2010

Script to backup directories on a regular basis v2 - with ZIPs

Update: Monday 21 May 2012, 02:30:59 PM. Added use of invisible script to hide DOS box from scheduled invocation.

Update: Monday 12 September 2011, 07:53:04 PM. Re-wrote use of FORFILES to use / switches. Included %ZIP% variable to avoid relying on 7z being in the path. Also added Pro Tip for changing paths depending on the environment.

Version 4 of my Script to backup directories on a regular basis, this one backs up the directories as ZIP files. The first version worked just by copying directories. The reason I didn't go straight to ZIP in the first place is that on Windows, there is no built in ZIP functionality suited to the purpose: Windows compress command isn't a real zip replacement; WinZip isn't free; and I wanted batch script rather than a bash script (though I still love Cygwin). So this one uses 7-zip, a FREE and open source alternative to WinZip. Version 4 adds invisibleness! The scheduler uses a vbs script so that each time Windows Scheduler invokes this script, you don't get a DOS box popping up.

The script below has two functions. The first is to backup a set of directories and delete old backups. You edit the script to define what directories it backs up, which directory they get backed up to and how long backups should be kept for. The second function is to schedule the script so that it will be called every few hours. You edit the script to define how often it should be called.

This is a Windows DOS Batch script. I have only tested it on Windows 7. It has two dependencies. The first is forfiles.exe which should be native to Windows 7, since XP. If you haven't got it, get it from the magnificent site: An A-Z Index of the Windows XP command line. Make sure to put it in the path before running this script. The second dependency is 7-zip, a FREE and open source alternative to WinZip. Download and install it, then edit the ZIP variable in the script if 7z wasn't installed here: C:\Program Files\7-Zip\7z.exe. Notes about running the script itself appear below the script.

@ECHO OFF

REM Directory backup utility.
REM http://robertmarkbramprogrammer.blogspot.com.au/2010/06/script-to-backup-directories-on-regular_28.html
REM    - v1. Written by Robert Mark Bram, 23/06/2010 5:10:55 PM.
REM    - v2. Robert Mark Bram, 28/06/2010 6:03:28 PM: modified to backup
REM       directories to zip files instead of backing by copying directories.
REM    - v3. Robert Mark Bram, Monday 12 September 2011, 07:34:52 PM
REM       modified the way FORFILES is called to use / switches.
REM       Plus, added ZIP variable instead of relying on it being in the PATH.
REM    - v4. Robert Mark Bram, Saturday 19 May 2012, 11:43:42 AM
REM       integrated invisible.vbs to hide DOS box.
REM - Tested on Win 7 and XP 64 bit.
REM - Dependency: invisible.vbs - small script that lets this batch file be run
REM    without popping up a DOS box. Is used when you schedule this batch.
REM    Put invisible.vbs in the same folder as this batch file.
REM    http://dl.dropbox.com/u/60106937/invisible.vbs
REM - Dependency: forfiles.exe - Windows 7/XP-bit and later should have the
REM    FORFILES command by default. For earlier Windows builds, get it from:
REM      http://ss64.com/nt/forfiles.html
REM    and make sure to put forfiles.exe in the PATH (e.g. C:\WINDOWS\system32\
REM    for Windows XP).
REM - Dependency: 7zip, a FREE and open source alternative to WinZip - get it
REM    from here: http://www.7-zip.org and edit the ZIP variable below if the
REM    path is NOT C:\Program Files\7-Zip\7z.exe.

REM BACKUP AND DELETE OLD BACKUPS
REM Run this script without arguments and it will backup selected directories to
REM a backup directory and delete old backup directories.

REM SCHEDULE BACKUP TASKS
REM Run this script with argument "sched" and it will schedule this script to run
REM every few hours. You will need to enter your Windows password.
REM For example:
REM    D:\work\MyProject>backupDataHourly.bat sched
REM    Scheduling task.
REM    The task will be created under current logged-on user name ("SPIKE\Robert Bram").
REM    Please enter the run as password for SPIKE\Robert Bram: **************
::
REM    SUCCESS: The scheduled task "Backup data hourly" has successfully been created.
REM    D:\work\MyProject>


REM =======================================
REM EDIT THIS SECTION.
REM =======================================
REM Where is 7zip installed to?
SET ZIP="C:\Program Files\7-Zip\7z.exe"

REM Where do you want to put the backup files?
SET BACKUP_HOME=D:\files\backups

REM How long (days) do you want to keep them?
SET DAYS_B4_DELETE=10

REM Define path and label (no spaces) for each directory you want to backup.
SET DIR1="D:\work\MyProjects\FirstProject"
SET LBL1=FIRST_PROJ
SET DIR2="D:\work\MyProjects\SecondProject"
SET LBL2=SECOND_PROJ

REM How many dir/lbl combinations did you define?
SET MAX=2

REM How often (in hours) do you want to run this script?
SET HOURS=1

REM What name to give the scheduled task.
SET SCHED_TASK_LABEL=Backup data hourly

REM =======================================
REM DON'T CHANGE BELOW THIS POINT unless you know what you are doing!
REM =======================================

REM Directory Checks
IF "%BACKUP_HOME%" == "" (
   echo Warning: BACKUP_HOME has not been set.
   GOTO END
)
IF NOT EXIST "%BACKUP_HOME%"  (
   echo Warning: BACKUP_HOME [%BACKUP_HOME%] does not exist.
   GOTO END
)

REM Are we scheduling or backing up?
IF "%1" == "sched" GOTO :SCHEDULE
GOTO :BACKUP

REM Schedule this script to run regularly - user will have to enter password.
:SCHEDULE
echo Scheduling task: %0.
REM Schedule task.
schtasks /create /SC HOURLY /MO %HOURS% /tn "%SCHED_TASK_LABEL%" /tr "wscript.exe %~dp0invisible.vbs %0"
GOTO :END

REM Run backup tasks.
:BACKUP
echo Backing up files.

REM Create timestamp.
SET hh=%time:~0,2%
if "%time:~0,1%"==" " SET hh=0%hh:~1,1%
SET YYYYMMDD_HHMMSS=%date:~10,4%%date:~7,2%%date:~4,2%_%hh%%time:~3,2%%time:~6,2%

REM Backup selected paths.
SetLocal EnableDelayedExpansion
For /L %%i in (1,1,%MAX%) Do (
   IF EXIST !DIR%%i! (
      %ZIP% a -tzip -r "%BACKUP_HOME%\!LBL%%i!_%YYYYMMDD_HHMMSS%.zip" !DIR%%i!
   )
)
EndLocal


REM Delete old backups.
echo Deleting old files.
IF "%DAYS_B4_DELETE%" == "" (
   echo WARNING! DAYS_B4_DELETE not set. Not deleting old backups.
   GOTO :END
)

REM SetLocal EnableDelayedExpansion
SetLocal EnableDelayedExpansion
For /L %%i in (1,1,%MAX%) Do (
   FORFILES /P "%BACKUP_HOME%" /M !LBL%%i!_*.zip /D -%DAYS_B4_DELETE% ^
      /C "CMD /C del /F /Q @FILE & echo Deleted @FILE "
)
EndLocal

REM Use this for testing - echo what files will be deleted.
REM SetLocal EnableDelayedExpansion
REM For /L %%i in (1,1,%MAX%) Do (
REM    FORFILES /P "%BACKUP_HOME%" /M !LBL%%i!_*.zip /D -%DAYS_B4_DELETE% ^
REM       /C "CMD /C echo @FILE will be deleted"
REM )
REM EndLocal

:END

REM Uncomment the "pause" line if you want the command window to stick around
REM until you "Press any key to continue . . ."
REM (Let's you see the output of every run.)
REM pause


You can run the script just by double clicking it or running it on the command line without any parameters, but the intention is that you schedule the script to run every few hours.

You can get invisible.vbs from my Dropbox. It's just a one line script however, so you can just as easily save it to a file yourself from this: CreateObject("Wscript.Shell").Run """" & WScript.Arguments(0) & """", 0, False. Save it to the same directory as the backup script itself (also available from my Dropbox).

Save the backup and invisible script somewhere and edit the variables in the section labelled EDIT THIS SECTION. Make sure to give values to the variables there:

  • ZIP - location where 7z is installed, C:\Program Files\7-Zip\7z.exe by default.
  • BACKUP_HOME - where to store the backups.
  • DAYS_B4_DELETE - how many days backups should be kept before deleting them.
  • DIRX and LBLX - a directory and label combination for each directory you want to back up. For example, DIR1="D:\work\MyProjects\FirstProject" and LBL1=FIRST_PROJECT will result in a backup ZIP being created such as FIRST_PROJECT_20100624_004014.zip - the label plus a time stamp.
  • MAX - how many DIRX and LBLX combinations you have (needed for loop control).
  • HOURS - how often to run the script (in hours).
  • SCHED_TASK_LABEL - what to call the task in the Scheduled Tasks applet.

Once you have edited the values, you can just run the script to create the backups - or you can run the script to schedule backups by running it with the parameter “sched”. You will have to enter your login password. Here is an example:

D:\work\MyProjects>backupDataHourly.bat sched
Scheduling task.
The task will be created under current logged-on user name ("SPIKE\Robert Bram").
Please enter the run as password for SPIKE\Robert Bram: **************

SUCCESS: The scheduled task "Backup data hourly" has successfully been created.
D:\work\MyProjects>

Pro Tip: Change Configuration per Environment

Pro Tip. I like to run my own personal source control system and check my important scripts into it. If possible, I like to set up my various computers such that the same script will run equally everywhere. The biggest road-block for having this work is paths: no matter how much I try, I always end up with different paths on my different machines. No matter, for this script, you can set different paths depending on what machine you are running on! Do it with code like that shown below.


SET ZIP="C:\Program Files\7-Zip\7z.exe"

REM My Workplace
if "%computername%" == "WORKLAPTOP" (

   REM Where do you want to put the backup files?
   SET BACKUP_HOME=D:\files\backups

   REM How long (days) do you want to keep them?
   SET DAYS_B4_DELETE=10

   REM Define path and label (no spaces) for each directory you want to backup.
   SET DIR1="D:\work\MyProjects\FirstProject"
   SET LBL1=FIRST_PROJ
   SET DIR2="D:\work\MyProjects\SecondProject"
   SET LBL2=SECOND_PROJ

   REM How many dir/lbl combinations did you define?
   SET MAX=2

   REM How often (in hours) do you want to run this script?
   SET HOURS=1

   REM What name to give the scheduled task.
   SET SCHED_TASK_LABEL=Backup data hourly

) else if "%computername%" == "HOMEPC" (

   REM Where do you want to put the backup files?
   SET BACKUP_HOME=C:\files\backups

   REM How long (days) do you want to keep them?
   SET DAYS_B4_DELETE=10

   REM Define path and label (no spaces) for each directory you want to backup.
   SET DIR1="C:\work\MyProjects\ThirdProject"
   SET LBL1=THIRD_PROJ
   SET DIR2="C:\work\MyProjects\FourthProject"
   SET LBL2=FOURTH_PROJ

   REM How many dir/lbl combinations did you define?
   SET MAX=2

   REM How often (in hours) do you want to run this script?
   SET HOURS=1

   REM What name to give the scheduled task.
   SET SCHED_TASK_LABEL=Backup data hourly
)

In this example, I have all the same paths, except that on my work machine everything is in D:, but in C: at home! Also, when I am at home, I work on different projects - I don't want to back up work projects, so I change what projects (path and label pairs) are targeted. Find out %computername% simply by opening up a DOS command shell and typing echo %computername%

So now I am sure I has backups!