Example #1
0
        public int iBackupDoneScriptCopyFailuresWithBitField(bool abRerunLastArgs)
        {
            int liBackupDoneScriptCopyFailuresWithBitField = 0;

            // Before the "backup done" script can be initialized,
            // -BackupDoneScriptPathFile and -BackupDoneScriptHelp
            // must be initialized first.
            if ( moProfile.bValue("-BackupDoneScriptInit", false) )
            {
                moProfile.Remove("-BackupDoneScriptPathFile");
                moProfile.Remove("-BackupDoneScriptHelp");
            }

            string lsBackupDoneScriptPathFile = moProfile.sRelativeToProfilePathFile(
                    moProfile.sValue("-BackupDoneScriptPathFile", msBackupDoneScriptPathFileDefault));
            string lsBackupDoneScriptOutputPathFile = lsBackupDoneScriptPathFile + ".txt";

            // If the "backup done" script has not been redefined to point elsewhere,
            // prepare to create it from the current -BackupDoneScriptHelp content.
            // We do this even if the script file actually exists already. This way
            // the following default script will be written to the profile file if
            // it's not already there.
            if ( lsBackupDoneScriptPathFile == moProfile.sRelativeToProfilePathFile(msBackupDoneScriptPathFileDefault) )
            {
                bool    lbUseMainhostArchive    = moProfile.bValue("-UseVirtualMachineHostArchive", false);
                bool    lbUseConnectMainhost    = moProfile.bValue("-UseConnectVirtualMachineHost", false);
                string  lsBackupDoneScript      = moProfile.sValue("-BackupDoneScriptHelp", @"
@echo off
if %1=="""" goto :EOF
::
:: *** ""Backup Done"" script goes here. ***
::
:: This script is executed after each successful backup completes. If you 
:: prompt for input within this DOS script (eg. ""pause""), the script
:: will stay in memory. This is not recommended since such behavior would
:: be similar to a memory leak.
::
:: You can also create and edit another DOS script file and reference that
:: instead (see ""-BackupDoneScriptPathFile"" in ""{ProfileFile}""). You
:: can access several parameters from the completed backup via the DOS shell
:: command-line:
::
:: %1 = ""BackupOutputPathFile""
::
::      This is the full path\file specification of the backup file.
::      It includes the output filename as well as the embedded date.
::
:: %2 = ""BackupOutputFilename""
::
::      This is the backup filename only (ie. no path). It includes the
::      embedded date as well as the filename extension.
::
:: %3 = ""BackupBaseOutputFilename""
::
::      This is the backup filename with no path and no date. It's just
::      the base output filename name with the filename extension.
::
:: %4 = ""LocalArchivePath""
::
::      This is the local archive folder.
::
:: %5 = ""VirtualMachineHostArchive""
::
::      This is the virtual machine host archive share name.
::
:: %6 = ""LogPathFile""
::
::      This is the full path\file specification of the backup log file.
::
::
:: Note: All arguments will be passed with double quotation marks included.
::       So don't use quotes here unless you want ""double double"" quotes.
::       Also, ERRORLEVEL is not reliable enough to be heavily used below.
::
:: The following example copies the backup file to the root of drive C:
:: (if it's ""AdministratorFiles.zip""). Then it outputs a directory listing
:: of the archive folder.
::
:: Example:
::
:: if not %3.==""AdministratorFiles.zip"". goto :EOF
::
::     echo copy %1 C:\  ] ""{BackupDoneScriptOutputPathFile}"" 2>&1
::          copy %1 C:\ ]] ""{BackupDoneScriptOutputPathFile}"" 2>&1
::
:: dir %4               ]] ""{BackupDoneScriptOutputPathFile}"" 2>&1
::
::                      ^^  Replace brackets with darts.

:: The ""CopyFailures"" environment variable is used to keep count of errors to be returned.
set CopyFailures=0

:: Initialize the ""backup done"" script log file. It's for this run only.
echo.                    > ""{BackupDoneScriptOutputPathFile}"" 2>&1
"
+
(!lbUseMainhostArchive ? "" :
@"
:: This references the backup destination copy on the VM host:
set FileSpec=%5\%2

echo.                                                                       >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
echo This copies the backup to the virtual machine host archive:            >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
echo.                                                                       >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
echo copy %1 %5                                                             >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
     copy %1 %5                                                             >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
     if not exist %FileSpec% echo   Error: %FileSpec% is not there.         >> ""{BackupDoneScriptOutputPathFile}"" 2>&1

     if not exist %FileSpec% set /A CopyFailures += 1
"
)
+
@"
echo.                                                                       >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
echo The following copies the backup (base name) to each attached backup    >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
echo device with the file ""{BackupDriveToken}"" at its root.               >> ""{BackupDoneScriptOutputPathFile}"" 2>&1

set BackupOutputPathFile=%1
set BackupBaseOutputFilename=%3

set BackupDeviceDecimalBitField=0
set BackupDevicePositionExponent=23

:: There are 23 drive letters listed (ie. possible backup devices). A 32-bit integer
:: can handle no more when a corresponding bit field is combined with copy failures.
for %%d in (D: E: F: G: H: I: J: K: L: M: N: O: P: Q: R: S: T: U: V: W: X: Y: Z:) do call :DoCopy %%d

:: Set bit 24 (ie. add 2^23 = 8,388,608) to preserve bit field's leading zeros.
:: Combine the bit field and the copy failures into a single composite value.
:: The factor of 100 means that there can be a maximum of 99 copy failures.

set /A CompositeResult = 100 * (8388608 + %BackupDeviceDecimalBitField%) + %CopyFailures%

echo   CompositeResult=%CompositeResult%                                    >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
exit  %CompositeResult%

:DoCopy
set /A BackupDevicePositionExponent -= 1
dir %1 > nul 2> nul
if ERRORLEVEL 1 goto :EOF
if not exist %1\""{BackupDriveToken}"" goto :EOF

:: Determine the bit position (and the corresponding decimal value) from the exponent.
set BitFieldDevicePosition=1
for /L %%x in (1, 1, %BackupDevicePositionExponent%) do set /A BitFieldDevicePosition *= 2

:: Add the calculated positional value to the bit field for the current backup device.
set /A BackupDeviceDecimalBitField += %BitFieldDevicePosition%


:: This references the backup destination copy on the current backup device (%1):
set FileSpec=%1\%BackupBaseOutputFilename%

echo.                                                                       >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
echo This removes the previous backup (if any) from %1                      >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
echo.                                                                       >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
echo del %FileSpec%                                                         >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
     del %FileSpec%                                                         >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
     if exist %FileSpec% echo   Error: %FileSpec% is still there.           >> ""{BackupDoneScriptOutputPathFile}"" 2>&1

     if exist %FileSpec% set /A CopyFailures += 1

echo.                                                                       >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
echo This copies the current backup to %1                                   >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
echo.                                                                       >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
echo copy %BackupOutputPathFile% %FileSpec%                                 >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
     copy %BackupOutputPathFile% %FileSpec%                                 >> ""{BackupDoneScriptOutputPathFile}"" 2>&1
     if not exist %FileSpec% echo   Error: %FileSpec% is not there.         >> ""{BackupDoneScriptOutputPathFile}"" 2>&1

     if not exist %FileSpec% set /A CopyFailures += 1
"
)
                        .Replace("{ProfileFile}", Path.GetFileName(moProfile.sLoadedPathFile))
                        .Replace("{BackupDoneScriptOutputPathFile}", Path.GetFileName(lsBackupDoneScriptOutputPathFile))
                        .Replace("{BackupDriveToken}", this.sBackupDriveToken)
                        ;

                // Write the default "backup done" script if it's
                // not there or if -BackupDoneScriptInit is set.
                if (       !File.Exists(lsBackupDoneScriptPathFile)
                        || moProfile.bValue("-BackupDoneScriptInit", false) )
                {
                    StreamWriter loStreamWriter = null;

                    try
                    {
                        loStreamWriter = new StreamWriter(lsBackupDoneScriptPathFile, false);
                        loStreamWriter.Write(lsBackupDoneScript);

                        // This is used only once then reset.
                        moProfile["-BackupDoneScriptInit"] = false;
                        moProfile.Save();
                    }
                    catch (Exception ex)
                    {
                        this.ShowError(string.Format("File Write Failure: \"{0}\"\r\n"
                                , lsBackupDoneScript) + ex.Message
                                , "Failed Writing File"
                                );
                    }
                    finally
                    {
                        if ( null != loStreamWriter )
                            loStreamWriter.Close();
                    }
                }
            }

            try
            {
                this.LogIt("");
                this.LogIt("Running \"backup done\" script ...");

                // Cache the arguments to be passed to the script.
                tvProfile  loArgs = new tvProfile();
                            if ( abRerunLastArgs )
                            {
                                loArgs.LoadFromCommandLine(moProfile.sValue("-BackupDoneArgs", ""), tvProfileLoadActions.Append);
                            }
                            else
                            {
                                loArgs.Add("-BackupOutputPathFile"          , msCurrentBackupOutputPathFile                                          );
                                loArgs.Add("-BackupOutputFilename"          , Path.GetFileName(msCurrentBackupOutputPathFile)                        );
                                loArgs.Add("-BackupBaseOutputFilename"      , Path.GetFileName(this.sBackupOutputPathFileBase())                     );
                                loArgs.Add("-LocalArchivePath"              , this.sArchivePath()                                                    );
                                loArgs.Add("-VirtualMachineHostArchivePath" , moProfile.sValue("-VirtualMachineHostArchivePath", "")                 );
                                loArgs.Add("-LogPathFile"                   , moProfile.sRelativeToProfilePathFile(this.sLogPathFile)                );

                                moProfile["-BackupDoneArgs"] = loArgs.sCommandBlock();
                                moProfile.Save();
                            }

                // Run the "backup done" script.
                Process loProcess = new Process();
                        loProcess.StartInfo.FileName = lsBackupDoneScriptPathFile;
                        loProcess.StartInfo.Arguments = string.Format(
                                  " \"{0}\" \"{1}\" \"{2}\" \"{3}\" \"{4}\" \"{5}\" \"{6}\" \"{7}\" \"{8}\" \"{9}\" "
                                , loArgs.sValue("-BackupOutputPathFile"         , "")
                                , loArgs.sValue("-BackupOutputFilename"         , "")
                                , loArgs.sValue("-BackupBaseOutputFilename"     , "")
                                , loArgs.sValue("-LocalArchivePath"             , "")
                                , loArgs.sValue("-VirtualMachineHostArchivePath", "")
                                , loArgs.sValue("-LogPathFile"                  , "")
                                , ""
                                , ""
                                , ""
                                , ""
                                );
                        loProcess.StartInfo.UseShellExecute = true;
                        loProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                        loProcess.Start();

                // Wait for the "backup done" script to finish.
                while ( !this.bMainLoopStopped && !loProcess.HasExited )
                {
                    System.Windows.Forms.Application.DoEvents();
                    System.Threading.Thread.Sleep(moProfile.iValue("-MainLoopSleepMS", 100));
                }

                // If a stop request came through, kill the "backup done" script.
                if ( this.bMainLoopStopped && !this.bKillProcess(loProcess) )
                    this.ShowError("The \"backup done\" script could not be stopped."
                            , "Backup Failed");

                if ( !this.bMainLoopStopped )
                {
                    // The exit code is defined in the script as a combination of two integers:
                    // a bit field of found backup devices and a count of copy failures (99 max).
                    liBackupDoneScriptCopyFailuresWithBitField = loProcess.ExitCode;

                    double  ldCompositeResult = liBackupDoneScriptCopyFailuresWithBitField / 100.0;
                    int     liCurrentBackupDevicesBitField = (int)ldCompositeResult;   // The integer part is the bit field.

                    // The fractional part (x 100) is the number of copy failures.
                    int liBackupDoneScriptCopyFailures = (int)Math.Round(100 * (ldCompositeResult - liCurrentBackupDevicesBitField));

                    // Compare the bit field of current backup devices to the bit field of devices selected by the user.
                    List<char> loMissingBackupDevices = this.oMissingBackupDevices(liCurrentBackupDevicesBitField);

                    if (0 == liBackupDoneScriptCopyFailures && 0 == loMissingBackupDevices.Count)
                    {
                        this.LogIt("The \"backup done\" script finished successfully.");
                    }
                    else
                    {
                        if ( 0 != liBackupDoneScriptCopyFailures )
                        {
                            this.LogIt(string.Format("The \"backup done\" script had {0} copy failure{1}.\r\n"
                                    , liBackupDoneScriptCopyFailures
                                    , 1 == liBackupDoneScriptCopyFailures ? "" : "s")
                                    );

                            // Get the output from the "backup done" script.

                            string lsFileAsStream = this.sFileAsStream(lsBackupDoneScriptOutputPathFile);

                            this.LogIt("Here's output from the \"backup done\" script:\r\n\r\n" + lsFileAsStream);

                            if ( moProfile.bValue("-ShowBackupDoneScriptErrors", true) )
                                this.DisplayFileAsErrors(lsFileAsStream, "Backup Done Script Errors");
                        }

                        if ( 0 != loMissingBackupDevices.Count )
                            this.LogIt(string.Format("The \"backup done\" script noticed {0} backup device{1} missing.\r\n"
                                    , loMissingBackupDevices.Count
                                    , 1 == loMissingBackupDevices.Count ? "" : "s")
                                    );
                    }
                }

                loProcess.Close();
            }
            catch (Exception ex)
            {
                ++liBackupDoneScriptCopyFailuresWithBitField;
                this.SetBackupFailed();
                this.ShowError(ex.Message, "Failed Running \"Backup Done\" Script");
            }

            return liBackupDoneScriptCopyFailuresWithBitField;
        }