commit e674d75a2066c7b5dfdbdb6d3bbc55cf066849e6 Author: Michael H.G. Schmidt Date: Wed May 26 00:54:46 2021 +0200 . diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eac7b00 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.exe +*.log +!snapcontrol.exe + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..b69e7ff --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2019-2021 Michael H.G. Schmidt + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8f0f27e --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ +# Snapcontrol + +Drive snapshot backup controller. +A backup wrapper program for Windows boxes. + + - Starts a backup via Windows Scheduler using Drive Snapshot + - Asks the user for permission to start backup + - Different backup targets (LOCAL drive, SMB, FTP) + - Encryption support (via Drive Snapshot) + - Verifies the backup (optional) + - Full backup every month + - Daily differential backup + - Writes detailed logfile and history log + - Sends reports via email + +This tool creates an image backups of windows machines, it uses the [Drive Snapshot](http://www.drivesnapshot.de/en/order.htm) tool by Tom Ehlert Software. Please support this great tool and buy a license. + +It is a - so called - wrapper program. + +This is a short description. Detailed documentation follows in the next days. + +## USAGE + +```dos +C:\>snapcontrol.exe /? +usage: snapcontrol.exe + /I = install program and config + /U = update scheduler job + /D = dry run + /V = show version +``` + +```dos +C:\>snapcontrol.exe /V +Version = V1.02 +``` + +## Example run + +```dos +[2021.05.25 (23:57:07)] ============== starting BACKUP ============== +[2021.05.25 (23:57:07)] snapcontrol.exe version = [ V1.02 ] +[2021.05.25 (23:57:07)] snapshot.exe version = [ V1.48 ] +[2021.05.25 (23:57:07)] OK. Running as Admin ... +[2021.05.25 (23:57:07)] INFO: using a NETWORK share for backup ... +[2021.05.25 (23:57:07)] INFO: found [ MARS_snapshot_05_ful_C.sna ] +[2021.05.25 (23:57:07)] INFO: found [ MARS_snapshot_05_ful_HD1-1.sna ] +[2021.05.25 (23:57:07)] INFO: Starting QUICKCHECK for [ MARS_snapshot_05_ful_C.sna ] + + +23:57:07 Start of Snapshot 1.48.18895 [May 6 2021] at 25.05.2021 +23:57:07 Running on Windows 10 Professional 64-bit (19042) +23:57:07 Memory Info: Total: 7887Mb, Free: 4645Mb, Pagefile total: 9103Mb, Pagefile free: 5835Mb +23:57:07 Command line: c:\tools\snapshot64.exe --Logfile:c:\snapshot\backup.log --QuickCheck:\\bar\drive\image\MARS_snapshot_05_ful_C.sna +23:57:07 The file structure of \\bar\drive\image\MARS_snapshot_05_ful_C.sna is okay. +23:57:07 End of Snapshot 1.48 [May 6 2021] at 25.05.2021 +[2021.05.25 (23:57:07)] INFO: Starting QUICKCHECK for [ MARS_snapshot_05_ful_HD1-1.sna ] + + +23:57:07 Start of Snapshot 1.48.18895 [May 6 2021] at 25.05.2021 +23:57:07 Running on Windows 10 Professional 64-bit (19042) +23:57:07 Memory Info: Total: 7887Mb, Free: 4642Mb, Pagefile total: 9103Mb, Pagefile free: 5835Mb +23:57:07 Command line: c:\tools\snapshot64.exe --Logfile:c:\snapshot\backup.log --QuickCheck:\\bar\drive\image\MARS_snapshot_05_ful_HD1-1.sna +23:57:07 The file structure of \\bar\drive\image\MARS_snapshot_05_ful_HD1-1.sna is okay. +23:57:07 End of Snapshot 1.48 [May 6 2021] at 25.05.2021 +[2021.05.25 (23:57:07)] INFO: executing command [ c:\tools\snapshot64.exe ] +[2021.05.25 (23:57:07)] DumpFile: [ \\bar\drive\image\MARS_snapshot_05_$type_$disk.sna ] +[2021.05.25 (23:57:07)] HashFile: [ -h\\bar\drive\image\MARS_snapshot_05_$type_$disk.hsh ] +[2021.05.25 (23:57:07)] LogFile: [ c:\snapshot\backup.log ] + + +23:57:08 Start of Snapshot 1.48.18895 [May 6 2021] at 25.05.2021 +23:57:08 Running on Windows 10 Professional 64-bit (19042) +23:57:08 Memory Info: Total: 7887Mb, Free: 4641Mb, Pagefile total: 9103Mb, Pagefile free: 5836Mb +23:57:08 Command line: c:\tools\snapshot64.exe --Logfile:c:\snapshot\backup.log -T --EjectDriveAfterBackup --NetUse:\\bar\drive\image,guest,******************** --FullIfHashIsMissing --CreateDir -W -L65536 HD1:* \\bar\drive\image\MARS_snapshot_05_$type_$disk.sna -h\\bar\drive\image\MARS_snapshot_05_$type_$disk.hsh +23:57:10 Disks in backup: +23:57:10 C: -> \\bar\drive\image\MARS_snapshot_05_dif_C.sna +23:57:10 HD1:1 -> \\bar\drive\image\MARS_snapshot_05_dif_HD1-1.sna +23:57:10 Preparing for backup +23:57:10 Drive HD1:1 is not supported by the Volume Shadow copy service +23:57:23 No exchange writer involved, using internal backup engine +23:57:24 Start differential backup of C: -> \\bar\drive\image\MARS_snapshot_05_dif_C.sna +23:57:24 free space info: total 244.095MB, 199.181MB free, 43.698MB must be saved +23:57:24 C: -> \\bar\drive\image\MARS_snapshot_05_dif_C.sna +23:59:11 4 sectors need more than 100ms to read +23:59:11 C: 44.914MB in use - stored in 26.228KB - 1:47 minutes +23:59:11 Success +23:59:11 Start verification of: \\bar\drive\image\MARS_snapshot_05_dif_C.sna +23:59:12 Success! +23:59:12 Start differential backup of HD1:1 -> \\bar\drive\image\MARS_snapshot_05_dif_HD1-1.sna +23:59:12 free space info: total 102.396KB, 75.424KB free, 26.972KB must be saved +23:59:13 HD1:1 -> \\bar\drive\image\MARS_snapshot_05_dif_HD1-1.sna +23:59:13 HD1:1 26.972KB in use - stored in 1.040KB - 0:00 minutes +23:59:13 Success +23:59:13 Start verification of: \\bar\drive\image\MARS_snapshot_05_dif_HD1-1.sna +23:59:13 Success! +23:59:13 Snapshot finished successfully +23:59:13 End of Snapshot 1.48 [May 6 2021] at 25.05.2021 +[2021.05.25 (23:59:13)] INFO: END of BACKUP with result SUCCESS ! +[2021.05.25 (23:59:13)] return=0 +[2021.05.25 (23:59:13)] INFO: sending mail to: michael@schmidt2.de +[2021.05.25 (23:59:13)] INFO: MailServer = smtp.gmail.com +[2021.05.25 (23:59:14)] INFO: mail sent +``` diff --git a/snapcontrol.exe b/snapcontrol.exe new file mode 100644 index 0000000..c94266d Binary files /dev/null and b/snapcontrol.exe differ diff --git a/snapcontrol.ini b/snapcontrol.ini new file mode 100644 index 0000000..1cd02d3 --- /dev/null +++ b/snapcontrol.ini @@ -0,0 +1,112 @@ +; SNAPCONTROL config file. +; https://github.com/mhgschmidt/snapcontrol +; +; This tool creates an image backups of windows machines, +; it uses the Drive Snapshot tool by Tom Ehlert Software. +; Please support this great tool and buy a license. +; http://www.drivesnapshot.de/en/order.htm +; +; Copyright (c) 2019-2021 Michael H.G. Schmidt +; EMAIL: michael@schmidt2.de +; Released under the MIT license. +; +; IMPORTANT: DO NOT USE quotation marks in this INIFILE ! +; + + +[INSTALL] +; where to install the exe and the infile ... +InstallTo = c:\snapshot + +; path where snapshot.exe is located ... +BinPath = c:\tools + + +[BACKUP] +; target PATH examples: +; - "D:\BACKUP" (LOCAL path on drive d:) +; - "\\example\share" (SMB share on server "example") +; - "/backup" (some path on FTP server) +TargetPath = D:\BACKUP + +; active FTP backup with "yes" +FtpBackup = no + +; name of ftp server +FtpServer = ftp.example.com + +; target USER (only for SMB/FTP mode needed) +TargetUser = ftpbackup + +; target PASSWORD (only for SMB/FTP mode needed) +TargetPassword = mypassword + +; backup schedule modes: +; TIME -> absolute start time (format = hh:mm) +; LOGIN -> delay before starting the backup after login (format = mmmm:ss) +BackupSched = LOGIN +BackupStart = 0005:00 + +; disks to dump (please use Drive Snapshot format!) +; see http://www.drivesnapshot.de/en/commandline.htm +Disks2Dump = HD1:* + +; maximum size of dumpfiles in MB (reduce for fat32 target drives to 4095) +DumpSize = 4095 + +; verify the backup ? +Verify = yes + +; delete all files in the recycle bin before starting the backup ? +BurnTrash = no + +; encrypt the backup ? +; no: do NOT encrypt +; dynamic: generate a password. will be sent via mail +; HINT: Generation happens only ONCE and only in case +; that "encryptpw" ist empty. snapcontrol will write +; the generated password into the inifile ! +; yes: use the password in variable "encryptpw" +Encrypt = no + +; some hard to guess password ---> WRITE IT DOWN !!! +; and DO NOT USE quotation marks ! +EncryptPW = + +; limit write IO in MB/s +LimitIO = + +; should drive/media be ejected after backup ? (yes/no) +EjectMedia = yes + + +[LOGGING] +LogFile = backup.log +HistLog = history.log + + +[MAIL] +; +; The mail setup in this config file was tested and works perfectly +; for gmail (please be aware that you will have to change your +; gmail security settings in case you plan to use gmail) +; + +; shall we send a mail ? +MailReport = no + +; mail recipient... +MailTo = backup@example.com + +; address of SMTP server (TLS/SSL only !) +MailServer = smtp.gmail.com + +; port of SMTP server (in most cases it's 465 or 587) +MailPort = 465 + +; user for sending mail +MailUser = example@gmail.com + +; password on mailserver +MailPass = mypassword + diff --git a/snapcontrol.pb b/snapcontrol.pb new file mode 100644 index 0000000..abcdd3d --- /dev/null +++ b/snapcontrol.pb @@ -0,0 +1,540 @@ +; snapcontrol.pb +; https://github.com/mhgschmidt/snapcontrol +; ------------------------------------------------------------ +; Drive snapshot backup controller +; - starts backups using drive snapshot +; - sends reports via email +; LICENSE : MIT License +; AUTHOR : Michael H.G. Schmidt +; EMAIL : michael@schmidt2.de +; DATE : 20210526 +; ------------------------------------------------------------ +; +; This tool creates an image backups of windows machines, +; it uses the Drive Snapshot tool by Tom Ehlert Software. +; Please support this great tool and buy a license. +; http://www.drivesnapshot.de/en/order.htm +; +; Copyright (c) 2019-2021 Michael H.G. Schmidt +; Released under the MIT license. +; + + +; +; INIT (set vars, read args, read inifile etc. pp.) +; + +OpenConsole() +EnableGraphicalConsole(0) + +Dim filelist$(0) + +Global VERSION$="V1.02" +Global installme = 0 +Global updatesched = 0 +Global dryrun = 0 +Global hostname$ = GetEnvironmentVariable("COMPUTERNAME") +Global jobname$ = "snapcontrol" +Global month$ = FormatDate("%mm", Date()) +Global day$ = FormatDate("%dd", Date()) +Global DriveSnapshotVersionOk = 0 + +; valid versions for Drive Snapshot we support ... +NewList DriveSnapshotVersion$() + AddElement(DriveSnapshotVersion$()) + DriveSnapshotVersion$() = "V1.46" + + AddElement(DriveSnapshotVersion$()) + DriveSnapshotVersion$() = "V1.47" + + AddElement(DriveSnapshotVersion$()) + DriveSnapshotVersion$() = "V1.48" + +Procedure Usage() + PrintN ("usage: snapcontrol.exe ") + PrintN (" /I = install program and config") + PrintN (" /U = update scheduler job") + PrintN (" /D = dry run") + PrintN (" /V = show version") + End 99 +EndProcedure + +; check commandline... +If ( CountProgramParameters() >1 ) + Usage() +EndIf + +; set path for inifile ... +inifile$ = RTrim(GetPathPart(ProgramFilename()),"\") + "\snapcontrol.ini" + +; install job, update job, show version, dry run ... +If ( UCase(ProgramParameter(0)) = "/I" ) + installme = 1 +ElseIf ( UCase(ProgramParameter(0)) = "/U" ) + updatesched = 1 +ElseIf ( UCase(ProgramParameter(0)) = "/V" ) + PrintN ("Version = " + VERSION$) + End 0 +ElseIf ( UCase(ProgramParameter(0)) = "/D" ) + dryrun = 1 +ElseIf ( UCase(ProgramParameter(0)) = "/?" ) + Usage() +EndIf + +; Procedure "RunProgram" aborts after writing approx. 8GB data with snapshot64... +; so we will use native "system" command... +ImportC "msvcrt.lib" + system(str.p-ascii) +EndImport + +If (Not OpenPreferences(inifile$)) + PrintN ("FATAL: cannot read inifile [ " + inifile$ + " ] ---> EXIT.") + End 98 +EndIf + +PreferenceGroup("install") +Global InstallTo$ = ReadPreferenceString("InstallTo","c:\snapshot") +Global BinPath$ = ReadPreferenceString("BinPath","c:\tools") + +PreferenceGroup("backup") +Global TargetPath$ = ReadPreferenceString("TargetPath","\\server\share") +Global FtpBackup$ = ReadPreferenceString("FtpBackup","no") +Global FtpServer$ = ReadPreferenceString("FtpServer","none") +Global TargetUser$ = ReadPreferenceString("TargetUser","guest") +Global TargetPassword$ = ReadPreferenceString("TargetPassword","guest") +Global BackupschedMode$ = ReadPreferenceString("BackupschedMode","LOGIN") +Global BackupStart$ = ReadPreferenceString("BackupStart","0005:00") +Global Disks2Dump$ = ReadPreferenceString("Disks2Dump","HD1:*") +Global DumpSize$ = ReadPreferenceString("DumpSize","4095") +Global Verify$ = ReadPreferenceString("Verify","yes") +Global BurnTrash$ = ReadPreferenceString("BurnTrash","no") +Global Encrypt$ = ReadPreferenceString("Encrypt","no") +Global EncryptPW$ = ReadPreferenceString("EncryptPW","") +Global LimitIO$ = ReadPreferenceString("LimitIO","") +Global EjectMedia$ = ReadPreferenceString("EjectMedia","yes") + +PreferenceGroup("logging") +Global LogFile$ = ReadPreferenceString("LogFile","backup.log") +Global HistLog$ = ReadPreferenceString("HistLog","history.log") + +; add PATH to logfiles ... +LogFile$ = InstallTo$ + "\" + LogFile$ +HistLog$ = InstallTo$ + "\" + HistLog$ + +PreferenceGroup("mail") +Global MailReport$ = ReadPreferenceString("MailReport","no") +Global MailTo$ = ReadPreferenceString("MailTo","") +Global MailServer$ = ReadPreferenceString("MailServer","") +Global MailPort = Val(ReadPreferenceString("MailPort","")) +Global MailUser$ = ReadPreferenceString("MailUser","") +Global MailPass$ = ReadPreferenceString("MailPass","") + +; which Drive Snapshot version should be used ? +arch$ = GetEnvironmentVariable("PROCESSOR_ARCHITECTURE") +If ( arch$ = "x86" ) + SnapshotBin$ = BinPath$ + "\snapshot.exe" +Else + SnapshotBin$ = BinPath$ + "\snapshot64.exe" +EndIf + +; Drive Snapshot found ? +If ( FileSize ( SnapshotBin$ ) < 0 ) + PrintN("ERROR: [ " + SnapshotBin$ + " ] NOT found.") + End 1 +EndIf + +; Version check for Drive Snapshot ... +DriveSnapshot = RunProgram(SnapshotBin$, "/?", "", #PB_Program_Open | #PB_Program_Read) +If DriveSnapshot + While ProgramRunning(DriveSnapshot) + Out$ = Out$ + ReadProgramString(DriveSnapshot) + Wend + CloseProgram(DriveSnapshot) +EndIf + +ForEach DriveSnapshotVersion$() + If ( FindString(Out$, DriveSnapshotVersion$()) >0 ) + DriveSnapshotVersionOk = 1 + Break + EndIf +Next + +If ( DriveSnapshotVersionOk = 0 ) + PrintN("ERROR: Drive Snapshot version is NOT supported!") + PrintN(" Supported versions are:") + ForEach DriveSnapshotVersion$() + PrintN(" - " + DriveSnapshotVersion$()) + Next + End 1 +EndIf + +; +; PROCEDURES +; + +Procedure LogMe(Message$) + Protected h = OpenFile(#PB_Any, LogFile$, + #PB_File_Append | #PB_File_NoBuffering | #PB_Ascii | #PB_File_SharedRead) + If h + WriteStringN(h, FormatDate("[%yyyy.%mm.%dd (%hh:%ii:%ss)] ", Date()) + Message$) + PrintN(FormatDate("[%yyyy.%mm.%dd (%hh:%ii:%ss)] ", Date()) + Message$) + CloseFile(h) + ProcedureReturn 1 + EndIf + ProcedureReturn 0 +EndProcedure + +Procedure LogMeRaw(Message$) + Protected h = OpenFile(#PB_Any, LogFile$, + #PB_File_Append | #PB_File_NoBuffering | #PB_Ascii | #PB_File_SharedRead) + If h + WriteStringN(h, Message$) + PrintN(Message$) + CloseFile(h) + ProcedureReturn 1 + EndIf + ProcedureReturn 0 +EndProcedure + +Procedure IsAdmin() + ProcedureReturn(system("reg.exe ADD HKLM /F >nul 2>&1")) +EndProcedure + +Procedure LogSend(subject$, filename$) + InitNetwork() + Protected e = 0 + Protected MailText$ = "" + + If CreateMail(0, "system@" + hostname$ , subject$) + AddMailRecipient(0, MailTo$, #PB_Mail_To) + LogMe("INFO: MailServer = " + Mailserver$) + If ReadFile(0, filename$, #PB_File_SharedRead) + While Eof(0) = 0 + MailText$ + ReadString(0) + Chr($0d) + Chr($0a) + Wend + CloseFile(0) + SetMailBody(0, MailText$) + EndIf + + ; send mails ALWAYS with SSL... + e = SendMail(0, MailServer$, MailPort, #PB_Mail_UseSSL, MailUser$, MailPass$) + EndIf + + ProcedureReturn e +EndProcedure + +Procedure EndProg(err) + Protected s$ = "" + + If ( err = 0 ) + LogMe("INFO: END of BACKUP with result SUCCESS !") + s$ = "BACKUP report - { SUCCESS } @" + hostname$ + Else + LogMe("ERROR: END of BACKUP with result FAILED !") + s$ = "BACKUP report - { ERROR ! } @" + hostname$ + EndIf + + ; write return code of last command (snapshot.exe) to logfile + LogMe("return=" + err) + + ; send a report via mail ? + If ( LCase(MailReport$) = "yes" ) + LogMe("INFO: sending mail to: " + MailTo$) + If ( LogSend(s$, Logfile$) ) + LogMe("INFO: mail sent") + Else + LogMe("FATAL: could not send backup report via email...") + LogMeRaw(" please inform your Administrator !") + EndIf + EndIf + + ; adding actual logfile to histlog... + If ReadFile(0, Logfile$, #PB_File_SharedRead) + While Eof(0) = 0 + LogText$ + ReadString(0) + Chr($0d) + Chr($0a) + Wend + CloseFile(0) + EndIf + + If OpenFile(0, HistLog$, #PB_File_Append | #PB_File_NoBuffering | #PB_File_SharedRead ) + FileSeek(0, Lof(0)) + WriteString(0,LogText$) + CloseFile(0) + EndIf + + ; remove backup share... + dummy = system("net use " + TargetPath$ + " /DELETE >nul 2>&1") + + ClosePreferences() + CloseConsole() + End err +EndProcedure + +Procedure.s mkpass(password_length) + chars$ = "abcdef-" ; possible characters, keep these lcase + For a = 1 To password_length + Select Random(1) ; 0 = char, 1 = digit + Case 1 ; is digit + pass$ + Str(Random(9)) + Case 0 ; is character + position = Random(Len(chars$)) ; random character selector + pass$ + Mid(chars$,position,1) + EndSelect + Next + ProcedureReturn pass$ +EndProcedure + + +; +; MAIN +; + +; installation requested ? +If ( installme = 1 ) + + ; delete old logfiles ... + LogMe("INFO: deleting old logfiles ...") + dummy = system("del /F /Q " + LogFile$ + " 2>nul") + dummy = system("del /F /Q " + HistLog$ + " 2>nul") + + ; create directory ... + LogMe("INFO: creating directory [ " + InstallTo$ + " ] ...") + dummy = system("mkdir " + InstallTo$ + " >nul 2>&1") + + ; copy binary and inifile ... + LogMe("INFO: copy binary and inifile to folder [ " + InstallTo$ + " ] ...") + dummy = system("copy /Y " + inifile$ + " " + InstallTo$ + " 2>nul") + dummy = system("copy /Y " + ProgramFilename() + " " + InstallTo$ + " 2>nul") + + ; update jobscheduler (selfcall) ... + dummy = system(InstallTo$ + "\snapcontrol.exe /U 2>nul") + + ClosePreferences() + CloseConsole() + End + +EndIf + +; update for jobscheduler requested ? +If ( updatesched = 1 ) + username$ = GetEnvironmentVariable("USERNAME") + + ; generate call string for task... + jobcmd$ = ProgramFilename() + + ; check jobtype ... + If ( LCase(BackupschedMode$) <> "login" And LCase(BackupschedMode$) <> "time" ) + PrintN("WARNING: unknown BackupschedMode [ " + BackupschedMode$ + " ] ---> IGNORING. Type will be set to LOGIN.") + BackupschedMode$ = "LOGIN" + EndIf + + ; update the job ... + PrintN ("Updating windows jobscheduler ...") + If ( LCase(BackupschedMode$) = "time" ) + dummy = system("schtasks /create /F /RL HIGHEST /SC daily /ST " + BackupStart$ + " /TN " + jobname$ + " /TR " + jobcmd$) + ElseIf ( LCase(BackupschedMode$) = "login" ) + dummy = system("schtasks /create /F /RL HIGHEST /SC onlogon /DELAY " + BackupStart$ + " /TN " + jobname$ + " /TR " + jobcmd$) + EndIf + + ; show job and print some status messages... + dummy = system("schtasks /query /FO List /V /TN " + jobname$) + PrintN (Chr(13) + "READY." + Chr(13)) + + ClosePreferences() + CloseConsole() + End + +EndIf + + +; +; ASK the user for permission to start ... +; + +; FTP backup requested ? +If ( FtpBackup$ = "yes" ) + TargetPath$ = "ftp://" + TargetUser$ + "@" + FtpServer$ + TargetPath$ +EndIf + +Result = MessageRequester("SnapControl", + "Start BACKUP now?" + Chr(13) + + "Targetpath => " + TargetPath$, + #PB_MessageRequester_YesNo | #PB_MessageRequester_Info) + +If Result = #PB_MessageRequester_No + Result = MessageRequester("SnapControl", + "backup ABORTED.", + #PB_MessageRequester_Ok | #PB_MessageRequester_Warning) + CloseConsole() + End 0 +EndIf + + +; cleanup: delete old Logfile, remove old drive letter... +dummy = DeleteFile(LogFile$, #PB_FileSystem_Force) + +LogMe("============== starting BACKUP ==============") +LogMe("snapcontrol.exe version = [ " + VERSION$ + " ]") +LogMe(" snapshot.exe version = [ " + DriveSnapshotVersion$() + " ]") + +If ( dryrun = 1 ) + LogMe("DRYRUN - (simulating a backup run) !!!") +EndIf + +e = IsAdmin() +If ( e = 0 ) + LogMe("OK. Running as Admin ...") +Else + PrintN("ERROR: Please run as Administrator !") + PrintN(" cannot continue ---> EXIT") + End 97 +EndIf + +; +; GENERATE the BACKUP command... +; + +; encryption enabled ? +If ( LCase(Encrypt$) = "yes" ) + params$ = "-PW=" + EncryptPW$ + " " + If ( EncryptPW$ = "" ) + LogMe("WARNING: ENCRYPTED backup requested but PASSWORD is not set in infile !") + Else + LogMe("WARNING: encryption requested. The backup will be encrypted.") + LogMeRaw(" --> PLEASE WRITE DOWN YOUR PASSWORD AND STORE IT IN A SAFE PLACE !") + EndIf +EndIf + +If ( LCase(Encrypt$) = "dynamic" ) + If ( EncryptPW$ = "" ) + EncryptPW$ = mkpass(20) + LogMe("WARNING: ENCRYPTED backup requested and DYNAMIC password was requested !") + LogMeRaw(" Generated password is: --->>> " + EncryptPW$ + " <<<---") + LogMe("INFO: writing password to inifile...") + PreferenceGroup("Global") + dummy = WritePreferenceString("EncryptPW", EncryptPW$) + Else + LogMe("WARNING: ENCRYPTED backup requested. Using DYNAMIC password in inifile !") + LogMeRaw(" The password is: --->>> " + EncryptPW$ + " <<<---") + EndIf + params$ = "-PW=" + EncryptPW$ + " " +EndIf + +; limit the write rate ? +If ( LimitIO$ <> "" ) + params$ + "--LimitIORate:" + LimitIO$ + " " +EndIf + +; verify the backup ? +If ( LCase(Verify$) = "yes" ) + params$ + "-T " +EndIf + +; burn all the trash in the recyclebin ? +If ( LCase(BurnTrash$) = "yes" ) + params$ + "-R " +EndIf + +; eject media ? +If ( EjectMedia$ = "yes" ) + params$ + "--EjectDriveAfterBackup " +EndIf + + +; FTP backup requested ? +If ( FtpBackup$ = "yes" ) + + LogMe("INFO: FTP backup, using server [ " + FtpServer$ + " ] for backup ...") + + ; add ftp account ... + e = system(SnapshotBin$ + " --AddFTPAccount:" + TargetUser$ + "," + FtpServer$ + "," + TargetPassword$) + + ; generate filenames for backup ... + DumpFile$ = TargetPath$ + "/" + hostname$ + "_snapshot_" + month$ + "_$type_$disk.sna" + HashFile$ = "-h" + InstallTo$ + "\" + hostname$ + "_snapshot_" + month$ + "_$type_$disk.hsh" + +Else + + ; network share or local drive ? + colonpos = FindString(TargetPath$, ":") + If ( colonpos = 0 ) + ; no colon found in path this means we are using a network share ... + params$ + "--NetUse:" + TargetPath$ + "," + TargetUser$ + "," + TargetPassword$ + " " + LogMe("INFO: using a NETWORK share for backup ...") + Else + ; found a ':' at some position means we are using a drive letter ... + DRIVE$ = Left(TargetPath$, colonpos) + LogMe("INFO: using DRIVE [ " + DRIVE$ + " ] for backup ...") + EndIf + + ; check if there is a full backup file ... in case it was deleted ... + If ( FileSize ( TargetPath$ + "\" + hostname$ + "_snapshot_" + month$ + "_ful*.sna" ) < 0 ) + LogMe("WARNING: no full backup found.") + If ( FileSize ( TargetPath$ + "\" + hostname$ + "_snapshot_" + month$ + "_ful*.hsh" ) >= 0 ) + dummy = system("del /F /Q " + TargetPath$ + "\" + hostname$ + "_snapshot_" + month$ + "_ful*.hsh") + LogMe("INFO: [ " + TargetPath$ + "\" + hostname$ + "_snapshot_" + month$ + "_ful*.hsh ] deleted.") + EndIf + EndIf + + ; check the actual FULL backup file for errors ... + ; ( must be done BEFORE we run a backup because we don't know - for sure + ; - wether the last backup was interrupted or not... ) + i = 1 + If ExamineDirectory(0, TargetPath$, hostname$ + "_snapshot_" + month$ + "_ful*.sna") + While NextDirectoryEntry(0) + If DirectoryEntryType(0) = #PB_DirectoryEntry_File + ReDim filelist$(i) + filelist$(i-1) = DirectoryEntryName(0) + LogMe("INFO: found [ " + filelist$(i-1) + " ]") + i + 1 + EndIf + Wend + FinishDirectory(0) + EndIf + + e = 0 + For i = 1 To ArraySize(filelist$()) + LogMe("INFO: Starting QUICKCHECK for [ " + filelist$(i-1) + " ]") + e = system(SnapshotBin$ + " --Logfile:" + LogFile$ + " --QuickCheck:" + TargetPath$ + "\" + filelist$(i-1)) + If ( e <> 0 ) + LogMe("ERROR: DELETING last full backup [ REASON: corrupt file! ]") + dummy = system("del /F /Q " + TargetPath$ + "\" + hostname$ + "_snapshot_" + month$ + "_ful*.*") + Break + EndIf + Next i + + ; generate filenames for backup ... + DumpFile$ = TargetPath$ + "\" + hostname$ + "_snapshot_" + month$ + "_$type_$disk.sna" + HashFile$ = "-h" + TargetPath$ + "\" + hostname$ + "_snapshot_" + month$ + "_$type_$disk.hsh" + +EndIf + + +; +; run BACKUP... +; + +; extend params ... +params$ + " --FullIfHashIsMissing --CreateDir -W -L" + DumpSize$ + " " + Disks2Dump$ + +LogMe("INFO: executing command [ " + SnapshotBin$ + " ]") +LogMe(" DumpFile: [ " + DumpFile$ + " ]") +LogMe(" HashFile: [ " + HashFile$ + " ]") +LogMe(" LogFile: [ " + LogFile$ + " ]") + +If ( dryrun = 0 ) + e = system(SnapshotBin$ + " --Logfile:" + LogFile$ + " " + params$ + " " + DumpFile$ + " " + HashFile$) +EndIf + +; end with return code... +EndProg(e) + +; IDE Options = PureBasic 5.73 LTS (Windows - x64) +; ExecutableFormat = Console +; CursorPosition = 58 +; FirstLine = 20 +; Folding = -- +; EnableXP +; Executable = snapcontrol.exe +; DisableDebugger +; Warnings = Display \ No newline at end of file