A Do It Yourself back-up solution

A client, working in health care, had a special request: each working day she was filling in forms in a database with patient data. After the day was finished she wanted a back-up. In general, a back-up of an in use database is a bad idea. She was using Windows with a custom database application.

So what I wanted was a shortcut to a batch file for starting the database and as a next step – after closing the database – calling the back-up procedure. That is the nice thing about a batch file, it starts the next step only when the previous step is finished and if the next step is after a day work, so be it.

If you just want a button with a back-up script, it is even easier, read on. Anyway, this example back-ups to a local drive, an attached USB-drive and Google drive.

I learned from this exercise myself and I thought it might be a good idea to share it, the techniques are very useful in general.


Now if you say back-up, I say rsync. Rsync is incredible powerfull GPL software used all over the world for mission critical smart file copying. See https://en.wikipedia.org/wiki/Rsync. The challenge is to get that typical Unix stuff working under Windows. So I say Cygwin, which gives you a Linux command line inside Windows, another challenge solved. See https://en.wikipedia.org/wiki/Cygwin.

These are the main ingredients, but some additional programs are needed too. For communication with the user, some pop ups are wanted. A nice and easy to use utility for this is “The Wizard’s Apprentice”, see http://wizapp.sourceforge.net/. That is all, except for one, caveat. Because you use Linux on Windows you may run into trouble when editing text files. It boils down to the following for every enter given in a text file: Think of old type writers, end of line markers in Windows are CR (Carriage Return) and LF (Line Feed), LF in Unix and CR when using an Apple. So we need to edit files in an end of line marker aware program, and that is where Notepad++ comes up. See https://notepad-plus-plus.org/.

Finally your own scripts are part of the ingredients as well, so you can make a nice distribution of the complete bunch.



Installing everything is pretty straight forward:

  • Cygwin can be downloaded and installed, follow instructions.
    • During installation of packages, search for rsync and install that too.
  • The Wizard’s Apprentice: just put the executable and the rest in a folder.
  • Notepad++: Follow instructions.

Considering the external USB drive: don’t use drive letters because they can change. Use a mount point inside your c: drive, mount it to a folder like c:\mnt\extdrive.

The Desktop shortcut

This is tricky when you want to run a program from a batch file, normally you’ll get a bonus in the form of a DOS-window. It is hard to avoid that window and if you search the net you’ll find many examples of how to solve that. However, so far there is only one that has been practical useful. Your shortcut should be something like

C:\Windows\System32\wscript.exe "C:\bin\sitapps\invisible.vbs" "C:\bin\sitapps\runapps.bat"

If you don’t have wscript, get it from Microsoft. What is inside invisible.vbs? This:

CreateObject("Wscript.Shell").Run """" & WScript.Arguments(0) & """", 0, False

Now no DOS-windows is launched and runapps.bat will run after opening your shortcut. So what has runapps.bat in store?

The solution

Now it starts to become interesting. About runapps.bat:

rem Where is script located...
set sitloc=C:\bin\sitapps
rem Main application
start /wait "C:\Program Files (x86)\YourProgram\program.exe" c:\data\database\yourdatabase
rem Follow up application - remove start for hidden
rem start %sitloc%\followup.bat
rem pause

So this is basically the real work flow, offering you your program and after that a file called followup.bat is fired up. Yes it is a chain of commands. Let’s list followup.bat

set cygwinbinloc=C:\cygwin64\bin
set sitlocposix=/cygdrive/c/bin/sitapps
set PATH=%cygwinbinloc%;%PATH%
%cygwinbinloc%\bash.exe %sitlocposix%/bash1.sh

The back-up script

So followup.bat clears the way for Cygwin by setting some variables and then launches bash1.sh. That is where the real action occurs as shown below. The first line of this file should start with #!/bin/bash.

## (c) 2015,2016 NedCAD
# See manual...
## Setting vars, watch trailing slashes...

# Location to backup from without trailing slash, NO SPACES, make junctions
# Junctions: mklink /j "c:\dir 0\some spaces" "c:\dir1\nospaces"
strsrcloc="/cygdrive/c/data/database /cygdrive/c/data/versleuteld"

# Locations w.o. trailing slash to backup to, local, googledrive, removable

# Delete older than n days, l local, o online, r removable (values like 30 for 30 days, -1 to remove all back-ups)

# Location sitapps

# End of variables

printf "=====================\n" > backuplog.txt
printf "StringIT back-up-log\n" >> backuplog.txt
strdate=$(date -Idate)
printf "Backup date stamp: $strdate\n" >> backuplog.txt
printf "=====================\n" >> backuplog.txt
cd "$sitapps"
printf "Current directory,            sitapps       = $sitapps\n" >> backuplog.txt
printf "Delete local after days,      deloldloc     = $deloldloc\n" >> backuplog.txt
printf "Delete online after days,     deloldgdr     = $deloldgdr\n" >> backuplog.txt
printf "Delete removable after days,  deloldrem     = $deloldrem\n" >> backuplog.txt
printf "Dirs to local back-up,        strsrcloc     = $strsrcloc\n" >> backuplog.txt
printf "Dirs to Google Drive back-up, strsrcgdr     = $strsrcgdr\n" >> backuplog.txt
printf "Dirs to Rem. Drive back-up,   strsrcrem     = $strsrcrem\n" >> backuplog.txt
printf "Dirs to Rem. Dr. Static,      strsrcremstat = $strsrcremstat\n" >> backuplog.txt
printf "Local destination,            destloc       = $destloc/$strdate\n" >> backuplog.txt
printf "On line destination,          destgdr       = $destgdr/$strdate\n" >> backuplog.txt
printf "Removable destination,        destrem       = $destrem/$strdate\n" >> backuplog.txt
printf "Removable destination, Static,destremstat   = $destremstat\n" >> backuplog.txt

## Making dirs
printf "\nMaking dirs\n" >> backuplog.txt

# Dir name is date stamp Iso

# Check if dirs exist
if [ ! -d "$destloc" ]; then
        printf "$destloc does not exist.\n" >> backuplog.txt
if [ ! -d "$destgdr" ]; then
        printf "$destgdr does not exist.\n" >> backuplog.txt
if [ ! -d "$destrem" ]; then
        printf "$destrem does not exist.\n" >> backuplog.txt
if [ ! -d "$destremstat" ]; then
        printf "$destremstat does not exist.\n" >> backuplog.txt

# Make dirs
mkdir -v "$destloc/$strdate" >> backuplog.txt 2>&1
mkdir -v "$destgdr/$strdate" >> backuplog.txt 2>&1
mkdir -v "$destrem/$strdate" >> backuplog.txt 2>&1

## Do the dance
# rsync
printf "\n=====================\nSyncing to $destloc/$strdate\n=====================\n" >> backuplog.txt
rsync -avhHPs --del --progress --no-compress --log-file=./backuplog.txt $strsrcloc "$destloc/$strdate"
printf "\n=====================\nSyncing to $destgdr/$strdate\n=====================\n" >> backuplog.txt
rsync -avhHPs --del --progress --no-compress --log-file=./backuplog.txt $strsrcgdr "$destgdr/$strdate"
printf "\n=====================\nSyncing to $destrem/$strdate\n=====================\n" >> backuplog.txt
rsync -avhHPs --del --progress --no-compress --log-file=./backuplog.txt $strsrcrem "$destrem/$strdate"
printf "\n=====================\nSyncing to $destremstat (Static)\n=====================\n" >> backuplog.txt
rsync -avhHPs --del --progress --no-compress --log-file=./backuplog.txt $strsrcremstat "$destremstat"

## Keep it clean (delete old back-ups)
printf "\n=====================\nDeleting n days old back-ups,\nn = $deloldloc local, $deloldgdr online, $deloldrem removable\n=====================\n" >> backuplog.txt
find "$destloc" -mindepth 1 -maxdepth 1 -type d -ctime +$deloldloc >> backuplog.txt
#if [ $? -eq 0 ];then printf "Dirs found in $destgdr.\n"; else echo "nothing";fi
find "$destloc" -mindepth 1 -maxdepth 1 -type d -ctime +$deloldloc -exec rm -rf {} \+ >> backuplog.txt
find "$destgdr" -mindepth 1 -maxdepth 1 -type d -ctime +$deloldgdr >> backuplog.txt
find "$destgdr" -mindepth 1 -maxdepth 1 -type d -ctime +$deloldgdr -exec rm -rf {} \+ >> backuplog.txt
find "$destrem" -mindepth 1 -maxdepth 1 -type d -ctime +$deloldrem >> backuplog.txt
find "$destrem" -mindepth 1 -maxdepth 1 -type d -ctime +$deloldrem -exec rm -rf {} \+ >> backuplog.txt
printf "\n\nEND OF LOG FILE\n" >> backuplog.txt
# Change log to DOS (default commented)
# sed -i 's/$/\r/' backuplog.txt
# If all is fine comment the last line (or not...)
read -p "Druk op [Enter] om af te sluiten..."

There is a lot to tell about the actions above but most things are quite obvious. Just search the net for strings that are not clear to you. I am sorry to be so brief here but one can write books about BASH scripting.

Final pieces

At the part where directory locations are checked there is a command – when failure – saying actions/checkdirs.bat. This is where the wizzard’s apprentice comes into action. Checkdirs.bat looks like:

set watitle=IMPORTANT!
set watext=One or more destination folders are not found.~~No back-up is made!~~Check if your disk is connected.~Check settings and or contact your organization.
start /w wa\wizapp MB INFORMATION

Another is near the end: actions/finish.bat, as follows:

set watitle=Back-up is finished
set watext=Back-up procedure is finished.~It is useful to check the log file of the last back-up from time to time.~~Click OK to view the log file.~~Click Cancel to close the program.
start /w wa\wizapp MB QUES
if errorlevel 2 exit
if errorlevel 0 if not errorlevel 2 goto show_log
start firefox backuplog.txt
rem pause

That is about it. I hope it inspires you to build something like this or copy paste the whole or parts of it.

Leave a Reply

Your email address will not be published. Required fields are marked *