:: *** BUTOZIP BAT - 24 Aug 2021 14:35:49 - KNAUTH @SETLOCAL @SET VERSION=1.8 :: BUTOZIP copies a specified set of files to a zip file which is then :: written to a named directory on a target drive. Each time the BAT :: file is run, a new uniquely named (sequence number, date, and userid) :: zip file is created, thus allowing many generations of the file set :: to be kept in the same directory. Optionally the zip file can be :: encrypted. :: The target drive and directory can be specified as a parameter when :: BUTOZIP is invoked, e.g., "BUTOZIP X:\DAILY_BACKUPS". The default is :: "D:\BACKUPS". :: For a detailed description of the externals, internals, and history :: of BUTOZIP, see http://jgkhome.name/PC_Info/BUTOZIP.BAT_Overview.htm. :: A good reference for Windows command line functions and syntax is :: http://ss64.com/nt/index.html. :: Set colors for command window: COLOR [background][foreground] :: 0 = Black 1 = Blue 2 = Green 3 = Aqua :: 4 = Red 5 = Purple 6 = Yellow 7 = White :: 8 = Gray 9 = Light Blue A = Light Green B = Light Aqua :: C = Light Red D = Light Purple E = Light Yellow F = Bright White :: ===================================================================== @COLOR B0 @ECHO OFF SET REPORT_FILE_EXISTS=N SET BUREPORT=NONE SET TB=OK :: Specify the 7-Zip encryption password, which can be null. :: ===================================================================== SET BUPWD=%2 :: Specify the user ID whose data structure is to be copied. :: ===================================================================== SET UNAME=%USERNAME% :: Specify a work directory for use by 7-Zip. Anyone using BUTOZIP.BAT :: must have read/write/erase/create access for files in this directory. :: Caution: RMDIR will be used on a tree in this directory. :: ===================================================================== SET BUWORK=C:\BUTOZIP_TEMP IF NOT EXIST "%BUWORK%" MD "%BUWORK%" :: Make sure the work directory exists. IF NOT EXIST "%BUWORK%" ( SET ABORTMSG="%BUWORK%" does not exist. BUTOZIP should have created it. GOTO :ABORT ) :: The BU Report file records XCOPY result messages: "nn File(s) copied" SET BUREPORT="%BUWORK%\%UNAME%.BUTOZIP_REPORT.TXT" :: Test that files can be written to and erased from the work directory. ERASE %BUREPORT% > NUL 2>&1 IF EXIST %BUREPORT% ( SET ABORTMSG=Cannot erase %BUREPORT%. GOTO :ABORT ) :: Create the report file by writing the first line to it. ECHO BUTOZIP version %VERSION% report on %DATE% > %BUREPORT% ECHO. IF NOT EXIST %BUREPORT% ( SET ABORTMSG=Cannot create %BUREPORT%. GOTO :ABORT ) SET REPORT_FILE_EXISTS=Y ECHO ---------------------------------------------------------- %TIME% >> %BUREPORT% :: The open source 7-Zip program is required by BUTOZIP.BAT. You can :: get the command line version from http://www.7-zip.org/download.html. :: Use that program (7za.exe -- the command line version) and place it :: in the directory you specify by the SET command below; that directory :: does not have to be named C:\JGK\7ZIP. :: ===================================================================== SET ZIP="C:\JGK\7ZIP\7ZA.EXE" :: ********************************************************************* :: Make sure the command line 7-Zip executable exists. IF NOT EXIST %ZIP% ( SET ABORTMSG=File %ZIP% does not exist. GOTO :ABORT ) :: Specify the target drive and directory. You MUST have created this :: directory before running BUTOZIP to copy zip files to it. The :: default directory name is D:\BACKUPS, but it can be named something :: else. :: ===================================================================== SET BUTARGET=D:\BACKUPS IF [%1] NEQ [] SET BUTARGET=%1 :: Save original input for display in error messages. SET BUINPUT=%BUTARGET% :: Remove a single trailing "\" from BUTARGET if it is present. IF %BUTARGET:~-1%. == \. SET BUTARGET=%BUTARGET:~0,-1% :: Make sure the target drive has a ":" as the second character. IF %BUTARGET:~1,1%. NEQ :. ( SET ABORTMSG=Specified target directory "%BUINPUT%" does not have a ":" as second character. GOTO :ABORT ) :: Make sure the target is not the root directory of the drive IF %BUTARGET:~3,1%. EQU . ( SET ABORTMSG=Specified target directory "%BUINPUT%" must not be the drive's root directory. GOTO :ABORT ) :: Make sure the target drive and directory exist. IF NOT EXIST "%BUTARGET%" ( SET ABORTMSG=Target directory "%BUINPUT%" does not exist. You must create it first. GOTO :ABORT ) :: Make sure the target directory is suitable for input by first erasing a test file :: (if it exists) in the directory and then creating that file by writing to it. ERASE %BUTARGET%\TEST.TXT 2>NUL IF EXIST %BUTARGET%\TEST.TXT ( SET ABORTMSG=Cannot erase %BUTARGET%\TEST.TXT. %BUTARGET% is not a good target directory. GOTO :ABORT ) ECHO %DATE% %TIME% > %BUTARGET%\TEST.TXT IF NOT EXIST %BUTARGET%\TEST.TXT ( SET ABORTMSG=Cannot write to %BUTARGET%\TEST.TXT. %BUTARGET% is not a good target directory. GOTO :ABORT ) :: The BU Count file remembers the generation number of the last backup. :: --------------------------------------------------------------------- SET BUCNTFILE="%BUTARGET%\%UNAME%.BUTOZIP_COUNT.TXT" :: If the BU Count file doesn't exist, initialize it with a line of "0". IF NOT EXIST %BUCNTFILE% ECHO 0 > %BUCNTFILE% :: Get the count, increment it, and save it back in the BU Count file. SET /P BUCOUNT= < %BUCNTFILE% SET /A BUCOUNT+=1 ECHO %BUCOUNT% > %BUCNTFILE% :: Parse today's date into month, day, and year tokens. :: Windows DATE output has a format like: Sun 09/08/2019 FOR /F "TOKENS=1-4 DELIMS=/ " %%G IN ("%DATE%") DO ( SET MONTH=%%H SET DAY=%%I SET YEAR=%%J ) :: Create a target subdirectory name from the user name, count, and :: parsed date tokens. :: --------------------------------------------------------------------- SET NODIR=%UNAME%_#%BUCOUNT%__%YEAR%-%MONTH%-%DAY% SET TDIR=%BUWORK%\%NODIR% :: --------> TDIR = C:\BUTOZIP_TEMP\Jeff_#1537__2012-11-29 <-------- example :: Note: If any of the components of TDIR contain blanks (or any other file :: or directory names in the XCOPYs below contain blanks), be sure to surround :: the full names with quotes, the normal Windows requirement, e.g., as in :: XCOPY "C:\MISC DIR\*.*" "%TDIR%\MISC\*.*" /S /H /Q >> %BUREPORT% 2>&1 :: Specify the files to be copied. Be sure to adjust for Windows :: version dependencies which change the names and locations of some :: directories, e.g.. for the "My Documents" directory. For more :: details, see http://jgkhome.name/PC_Info/BUTOZIP.BAT_Overview.htm. :: In the sample XCOPYs below, note the use of preceding SETs to avoid having :: to enter long path names in the XCOPYs. Note also that if you use Firefox :: and/or Thunderbird, you must replace the "????????.????????"s with the :: appropriate profile names. The "/S" option means copy all subdirectries. :: "/H" means copy hidden files. "/Q" suppresses the display of some messages. :: "/E" means copy empty subdirectories. ECHO ON :: $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ :: $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ :: ********************** START OF SPECIFICATION OF FILES TO BE COPIED ********************** :: The XCOPYs and SETs below are what a user must modify to specify the files to be archived. :: See the note immediately above for some file name and XCOPY considerations. The following :: are samples of typical commands, showing some of the flexibility XCOPY provides. :: This is how you can specify a Windows user directory in a shortened way to lessen the :: path characters for the following XCOPYs. @SET PROF=%USERPROFILE% :: This XCOPY copies only files in DOCUMENTS, not those in its subdirectories, since the /S :: option is not used. It also shows the "to" directory name can be different than the "from" :: directory name. XCOPY "%PROF%\DOCUMENTS\*.*" "%TDIR%\DOCS\*.*" /H /Q >> %BUREPORT% 2>&1 :: This XCOPY copies the whole DOCUMENTS\WORK$$ directory tree, since the /S option is used. XCOPY "%PROF%\DOCUMENTS\WORK$$\*.*" "%TDIR%\DOCS\SAVEIT\*.*" /S /H /Q >> %BUREPORT% 2>&1 XCOPY "%PROF%\FINANCE\*.*" "%TDIR%\FINANCE\*.*" /S /H /Q >> %BUREPORT% 2>&1 XCOPY "%PROF%\NOTES\*.*" "%TDIR%\NOTES\*.*" /S /H /Q >> %BUREPORT% 2>&1 XCOPY "%PROF%\KMACROS\*.*" "%TDIR%\KMACROS\*.*" /S /H /Q >> %BUREPORT% 2>&1 XCOPY "%PROF%\FTP\*.*" "%TDIR%\FTP\*.*" /S /H /Q >> %BUREPORT% 2>&1 XCOPY "C:\MISCPROG\*.*" "%TDIR%\MISCPROG\*.*" /S /H /Q >> %BUREPORT% 2>&1 XCOPY "C:\SHORTCUTS\*.*" "%TDIR%\SHORTCUTS\*.*" /S /H /Q >> %BUREPORT% 2>&1 :: ====================================== FIREFOX =========================================== :: -------------------------------------------------------------> $$$$$$$$.$$$$$$$$ @SET FFDIR=%USERPROFILE%\AppData\Roaming\Mozilla\Firefox\Profiles\????????.???????? :: Each of these XCOPYs copies an individual file. Strictly speaking, /S is not meaningful :: for copying a single file, but specifying it does not cause a problem. Also, specifying :: /H to copy a non-hidden file is harmless. XCOPY "%FFDIR%\PLACES.SQLITE" "%TDIR%\MOZ_FF\*.*" /S /H /Q >> %BUREPORT% 2>&1 XCOPY "%FFDIR%\PREFS.JS" "%TDIR%\MOZ_FF\*.*" /S /H /Q >> %BUREPORT% 2>&1 XCOPY "%FFDIR%\CHROME\USERCHROME.CSS" "%TDIR%\MOZ_FF\*.*" /S /H /Q >> %BUREPORT% 2>&1 XCOPY "%FFDIR%\LOGINS.JSON" "%TDIR%\MOZ_FF\*.*" /S /H /Q >> %BUREPORT% 2>&1 XCOPY "%FFDIR%\KEY4.DB" "%TDIR%\MOZ_FF\*.*" /S /H /Q >> %BUREPORT% 2>&1 @ECHO "%FFDIR%" > "%TDIR%\FF_ProfileDir.txt" :: ==================================== THUNDERBIRD ========================================== :: ---------------------------------------------------------> $$$$$$$$.$$$$$$$ @SET TBDIR=%USERPROFILE%\AppData\Roaming\Thunderbird\Profiles\????????.??????? @ECHO. >> %BUREPORT% :: This XCOPY shows you can use /S and /E to copy a full directory tree, even including :: subdirectories that happen to be empty in the "from" tree. XCOPY "%TBDIR%\*.*" "%TDIR%\MOZ_TB\*.*" /E /S /H /Q >> %BUREPORT% 2>&1 @IF NOT %ERRORLEVEL% EQU 0 ( @SET TB=ERROR @ECHO ######## >> %BUREPORT% @ECHO ######## ERRORLEVEL=%ERRORLEVEL%: Probably Thunderbird is still open. >> %BUREPORT% @ECHO ######## If so, its files were *NOT* copied. >> %BUREPORT% @ECHO. >> %BUREPORT% ) @ECHO "%TBDIR%" > "%TDIR%\TB_ProfileDir.txt" :: ********************** END OF SPECIFICATION OF FILES TO BE COPIED ************************ :: $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ :: $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ @ECHO OFF ECHO ---------------------------------------------------------- %TIME% >> %BUREPORT% ECHO Target directory for zip file: %BUTARGET% Backup: #%BUCOUNT% >> %BUREPORT% ECHO. ECHO *ONLY IF* Windows indicates there is insufficient space on the target device, ECHO close this window to abort BUTOZIP. Then clean up the work directory, make ECHO more space on the target device, and retry BUTOZIP. ECHO. ECHO $$$$$$ Creating the temporary zip file in the work directory :: ========> TDIR = C:\BUTOZIP_TEMP\Jeff_#1537__2012-11-29 <======= example %ZIP% a -tzip "%TDIR%" -r "%TDIR%\" > "%BUWORK%\7ZIP_REPORT.TXT" :: The following uses the default ZipCrypto encryption. You could add the :: -mem=AES256 switch to get the stronger AES256 encryption, but then :: Windows could not handle later opening the file in the simple Windows :: "compression folder" mode or doing an "Extract All". Instead 7-Zip :: opening or extraction could be used on the AES256 file, but this would :: require more user knowledge about 7-Zip. :: If password was specified in command, encrypt zip file with password :: ------------------------------------------------------------------------ IF [%BUPWD%] NEQ [] ( CD %BUWORK% ECHO. ECHO ENCRYPTING the temporary zip file into a new file. >> %BUREPORT% ECHO @@@@@@ ENCRYPTING the temporary zip file into a new file. REM %ZIP% a -tzip ENCFILE -p%BUPWD% -mem=AES256 "%TDIR%.zip" > "%BUWORK%\7ZIP_ENC_REPORT.TXT" %ZIP% a -tzip ENCFILE -p%BUPWD% "%TDIR%.zip" > "%BUWORK%\7ZIP_ENC_REPORT.TXT" ECHO @@@@@@ Erasing the temporary zip file. ERASE "%TDIR%.zip" ECHO @@@@@@ Renaming the encrypted file to be the temporary zip file. RENAME "ENCFILE.zip" "%NODIR%.zip" ECHO. ) ECHO $$$$$$ Copying the temporary zip file to the target directory XCOPY "%TDIR%.zip" "%BUTARGET%\*.*" /Q ECHO. :: XCOPY will automatically pause here if there is insufficient space in the :: target directory (but provides no ERRORLEVEL code). The user is prompted :: to take action, which will normally be to abort the command by closing :: the command window, then do a manual cleanup of the work directory. If :: an ERRORLEVEL is set for any other cases, the following lines will provide :: an error report and command termination. IF %ERRORLEVEL% GTR 0 ( @COLOR C0 ECHO ######## !!!!!!! XCOPY error %ERRORLEVEL% when copying to target directory ECHO ######## !!!!!!! XCOPY error %ERRORLEVEL% when copying to target directory >> %BUREPORT% ECHO. >> %BUREPORT% PAUSE ) ELSE ( ECHO. >> %BUREPORT% ECHO ******* COPY TO TARGET DIRECTORY WAS SUCCESSFUL! ******* >> %BUREPORT% IF %TB% NEQ OK ECHO ######## !!!!!!! Except for Thunderbird files >> %BUREPORT% ECHO. >> %BUREPORT% ECHO %TDIR%.zip to %BUTARGET% >> %BUREPORT% ) :: If you uncommented the lines between the following ##### lines, a second copy of the zip :: file would be done, this time to a directory named BACKUPS_XPS8940 on the W: drive. :: W: could be a mapped network drive, i.e., one located on another computer. E.g., in :: Windows 10 to set up such a drive mapping, open "This PC" (aka "Computer" in prior :: systems), then "Computer", then "Map network drive" and complete the dialog. Add error :: checking after the XCOPY as appropriate for your environment. :: :: ########################################################################################## :: IF [%BUPWD%] NEQ [] GOTO :SKIP2ND :: ECHO $$$$$$ Copying the temporary zip file to the second target directory :: XCOPY "%TDIR%.zip" "W:\BACKUPS_XPS8940\*.*" /Q :: IF %ERRORLEVEL% GTR 0 ( :: @COLOR C0 :: ECHO ######## !!!!!!! XCOPY error %ERRORLEVEL% when copying to SECOND target directory :: ECHO ######## !!!!!!! XCOPY error %ERRORLEVEL% when copying to SECOND target directory >> %BUREPORT% :: ECHO. >> %BUREPORT% :: ) ELSE ( :: ECHO. >> %BUREPORT% :: ECHO. >> %BUREPORT% :: ECHO ******* COPY TO SECOND TARGET DIRECTORY WAS SUCCESSFUL! ******* >> %BUREPORT% :: IF %TB% NEQ OK ECHO ######## !!!!!!! Except for Thunderbird files >> %BUREPORT% :: ECHO. >> %BUREPORT% :: ECHO %TDIR%.zip to "W:\BACKUPS_XPS8940" >> %BUREPORT% :: ECHO. :: ) :: :SKIP2ND :: ########################################################################################## @ECHO. >> %BUREPORT% ECHO ---------------------------------------------------------- %TIME% >> %BUREPORT% :: Report size of zip file in both exact byte count and in rounded KBs. :: -------------------------------------------------------------------- @SET DIRCMD=DIR "%NODIR%.zip" @CD %BUWORK% :: Have to use NODIR (vs. TDIR) and must CD to BUWORK; otherwise DIR does not work properly. @FOR /F "TOKENS=4" %%G IN ('%DIRCMD% ^| FIND "%UNAME%"') DO @SET ZIPSIZE_C=%%G @SET ZIPSIZE=%ZIPSIZE_C:,=% @SET DIV=1024 @SET /A KBSIZE=(10*ZIPSIZE+5*DIV)/(10*DIV) @SET FRONT=%KBSIZE:~0,-3% @SET BACK=%KBSIZE:~-3% @SET KBSIZE=%FRONT%,%BACK% @ECHO Zip file size: %ZIPSIZE_C% ))))))) %KBSIZE% KB ((((((( >> %BUREPORT% ECHO $$$$$$ Erasing the temporary zip file ERASE "%TDIR%.zip" ECHO $$$$$$ Erasing the temporary directory in the work directory RMDIR /S /Q "%TDIR%" >> "%BUWORK%\7ZIP_REPORT.TXT" ECHO ---------------------------------------------------------- %TIME% >> %BUREPORT% :: Display the report file. IF %TB% NEQ OK COLOR E0 ECHO. ECHO. ECHO =========================== REPORT FILE =========================== ECHO. TYPE %BUREPORT% :: :: If you don't want the command window to stay open, put an EXIT here instead of GOTO :EOF. :: If you do that, be sure to look in the report file each time for any error messages. GOTO :EOF :ABORT @COLOR C0 @ECHO. @ECHO ERROR! ERROR! ERROR! @ECHO. @ECHO %ABORTMSG% @IF %REPORT_FILE_EXISTS%. EQU Y. ( @ECHO ######## >> %BUREPORT% @ECHO ######## %ABORTMSG% >> %BUREPORT% @ECHO ######## >> %BUREPORT% ) :: If you don't want the command window to stay open, put an EXIT below as the last line. :: If you do that, be sure to look in the report file each time for any error messages. :: However if the report file cannot be written to, the error messages can appear only in :: the command window.