Simple Backup Script using Windows Script Host and JScript

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:

  1. Back up all the data in my local folder to a designated folder on my network drive.
  2. Keep each days backup in a separate folder labeled with the date of the backup.
  3. 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).