At work, I do my development on my local hard disk. I do this mainly for speed. But in between CVS check-ins I need to make sure I don’t lose any data. The company gives us all network drives that they keep backed up so I decided I would backup my local data to the network drive every night. I didn’t want to do this every day before I left work so I decided to write a script to automate the process. I had a few goals for this script to accomplish:
- Back up all the data in my local folder to a designated folder on my network drive.
- Keep each days backup in a separate folder labeled with the date of the backup.
- Automatically check the backup directory for backups older than a specified amount of days. I wanted to keep 5 days of backups at a time.
So I started to write a simple batch script to accomplish my goals. I always try to start with the simplest language to solve my problem. There is no reason to write a full blown application for a such a simple task. As I was writing the batch script the backing up part was easy to write but I couldn’t quite get my automatic deletion of older backups to work the way I wanted to. So I decided to abandon the batch script and move up to the next level. I examined the tools I could use and I decided to utilize another scripting technology built into Windows: the Windows Script Host or WSH.
There are two types of languages you can use to write WSH scripts: VBScript and JScript. VBScript is a simple scripting language based on Visual Basic and JScript is the same but based on JavaScript. I am familiar with both Visual Basic and JavaScript so I had a choice to make. I decided to use JScript because I like the syntax style better than Visual Basic.
So I hopped onto MSDN and read up on WSH and JScript syntax and a few hours later, had a finished script. I was pleasantly surprised at the power that the WSH and how easy it was to develop the script. Below is the script:
/*
* Local to Network Drive Backup Script
* Version 1.0.2 -- 2008-10-22
* Written by Matt Bertolini
*
* Copyright (c) 2008 Matt Bertolini
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// Variables to customize
var appName = "Local to Network Drive Backup Script";
var appVersion = "1.0.2";
var appVersionDate = "2008-10-22";
var sourceDir = "C:\\path\\to\\files\\to\\backup";
var backupDir = "C:\\path\\to\\backup\\folder";
var numDaysSaved = 5;
// Editing below this line is not recommended.
// Windows Script Host objects
var out = WScript.StdOut;
var fso = WScript.CreateObject("Scripting.FileSystemObject");
var WshShell = WScript.CreateObject("WScript.Shell");
var currentDateObj = new Date();
// Event log constants
var LOG_EVENT_SUCCESS = 0;
var LOG_EVENT_ERROR = 1;
var LOG_EVENT_WARNING = 2;
var LOG_EVENT_INFORMATION = 4;
var LOG_EVENT_AUDIT_SUCCESS = 8;
var LOG_EVENT_AUDIT_FAILURE = 16;
// Display script information to console.
out.WriteLine("===============================================================================");
out.WriteLine("\n " + appName + "\n");
out.WriteLine(" Version " + appVersion + " -- " + appVersionDate);
out.WriteLine(" Written by Matt Bertolini\n");
out.WriteLine(" Script Directory: " + WScript.ScriptFullName);
out.WriteLine(" Backing up files for date: " + dateToIsoString(currentDateObj));
out.WriteLine(" Number of days to keep backups: " + numDaysSaved);
out.WriteLine(" Directory being backed up: " + sourceDir);
out.WriteLine(" Backing up to directory: " + backupDir);
out.WriteLine("\n===============================================================================\n");
// Execute script functions.
backupFolder(sourceDir, backupDir);
deleteOldBackups(backupDir, numDaysSaved);
WScript.Quit(0);
function deleteOldBackups(backupDir, numDaysSaved)
{
// Create folder object for backup directory
var backupDirObj = fso.GetFolder(backupDir);
var fc = new Enumerator(backupDirObj.SubFolders);
for(; !fc.atEnd(); fc.moveNext())
{
var folderName = fc.item().Name;
var cutoffDateObj = new Date();
cutoffDateObj.setDate(currentDateObj.getDate() - numDaysSaved);
if(fc.item().DateCreated < cutoffDateObj)
{
out.Write("Deleting backup " + folderName + "... ");
fso.DeleteFolder(fc.item(), true);
out.WriteLine("done");
WshShell.LogEvent(LOG_EVENT_SUCCESS, appName + " - Old backup " + folderName + " deleted successfully.");
}
}
}
function backupFolder(sourceDir, backupDir)
{
try
{
if(fso.FolderExists(backupDir) == false)
{
out.Write("Backup folder does not exist. Creating folder...");
fso.CreateFolder(backupDir);
out.WriteLine("done");
}
}
catch(e)
{
out.WriteLine("Could not create backup folder.");
WshShell.LogEvent(LOG_EVENT_ERROR, appName + " - Could not create backup folder -- " + e);
}
try
{
out.Write("Creating folder for today\'s backup...");
backupDir = backupDir + "\\" + dateToIsoString(currentDateObj);
fso.CreateFolder(backupDir);
out.WriteLine("done");
out.Write("Backing up files...");
fso.CopyFolder(sourceDir, backupDir);
out.WriteLine("done");
WshShell.LogEvent(LOG_EVENT_SUCCESS, appName + " - " + "Backup successful.");
}
catch(e)
{
out.WriteLine("Backup failed.");
WshShell.LogEvent(LOG_EVENT_ERROR, appName + " - Backup failed -- " + e);
}
}
function dateToIsoString(dateObj)
{
var yearStr = dateObj.getYear().toString();
var monthStr = (dateObj.getMonth() + 1).toString();
var dayStr = dateObj.getDate().toString();
if(monthStr.length == 1)
{
monthStr = "0" + monthStr;
}
if(dayStr.length == 1)
{
dayStr = "0" + dayStr;
}
return yearStr + "-" + monthStr + "-" + dayStr;
}
Next, I wrote a small batch file to call the Windows Script Host with the parameters that I wanted. Here is the batch file:
@echo off
cls
setlocal
title Local to Network Drive Backup Script
call cscript.exe //nologo backup.js
endlocal
cls
exit
Now for the best part. I am releasing the script under the MIT License so everyone is free to use and modify the script. All you have to do is keep the license at the top. Now I know the script is not perfect so if you find any bugs or have any suggestions on how to improve it, comment in this post and I will see what I can do.
Update 1 – 2008-10-02
I found a small bug in the ISO date formatting function so I have updated the script and bumped the version up to 1.0.1.
Update 2 – 2008-10-22
I have updated the script to version 1.0.2 by adding some more logging features (to the Windows Event Viewer) and to fix a bug with the deletion of old backups).