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).