View difference between Paste ID: uW1PcfH1 and ZJUxnHFj
SHOW: | | - or go back to the newest paste.
1-
:: Purpose:         Rotating differential backup using 7-Zip for compression.
1+
:: Purpose:       Rotating differential backup using 7-Zip for compression.
2-
:: Requirements:    - forfiles.exe from Microsoft
2+
:: Requirements:  - forfiles.exe from Microsoft
3-
::                  - 7-Zip
3+
::                - 7-Zip
4-
:: Author:          vocatus on reddit.com/r/usefulscripts
4+
:: Author:        vocatus on reddit.com/r/usefulscripts
5-
:: Version:         1.4.6 + Added two additional "help" flags: "-h" and "--help"
5+
:: Version:       1.4.7 - Removed some redundant %TIME% stamps in the logs, under the Cleanup section
6-
::                  1.4.5 + Added better instructions for what variables can be set to
6+
::                1.4.6 + Added two additional "help" flags: "-h" and "--help"
7-
::                  1.4.4 + Added quotes around variables that could contain spaces in a few places
7+
::                1.4.5 + Added better instructions for what variables can be set to
8-
::                        * Some comment cleanup, and some logging formatting cleanup.
8+
::                1.4.4 + Added quotes around variables that could contain spaces in a few places
9-
::                  1.4.3 / Tweaked logging to only display exclamation point if there was an error
9+
::                    * Some comment cleanup, and some logging formatting cleanup.
10-
::                        / Tweaked logging to display time correctly (no extra spaces)
10+
::                1.4.3 / Tweaked logging to only display exclamation point if there was an error
11-
::                  1.4.2 / Some logging tweaks
11+
::                    / Tweaked logging to display time correctly (no extra spaces)
12-
::                  1.4.1 / Some logging tweaks
12+
::                1.4.2 / Some logging tweaks
13-
::                  1.4   + Added quotes around SOURCE variable that were missing in a couple places
13+
::                1.4.1 / Some logging tweaks
14-
::                  1.3   * Fixed backup archiving - wasn't rotating properly on network paths. We use pushd to get around this
14+
::                1.4   + Added quotes around SOURCE variable that were missing in a couple places
15-
::                        - Added "-s" option to show job options that the script WOULD execute with
15+
::                1.3   * Fixed backup archiving - wasn't rotating properly on network paths. We use pushd to get around this
16-
::                        - Major overhaul of code order and logic. Stuff should break less now.
16+
::                      - Added "-s" option to show job options that the script WOULD execute with
17-
::                        - Many fixes to exclusions file checking
17+
::                      - Major overhaul of code order and logic. Stuff should break less now.
18-
::                  1.2   - Fixed problem with cleaning backups. Now cleans staging area and long-term destination area. 
18+
::                      - Many fixes to exclusions file checking
19-
::                          Normally an archive (-a) switch cleans the staging area, but now the -c switch does as well, just in case.
19+
::                1.2   - Fixed problem with cleaning backups. Now cleans staging area and long-term destination area. 
20-
::                        - Also fixed issue with forfiles.exe not being able to read UNC paths. We use pushd to get around this.
20+
::                        Normally an archive (-a) switch cleans the staging area, but now the -c switch does as well, just in case.
21-
::                          Pushd auto-assigns the next available drive letter to a UNC path, then discards it when we use popd.
21+
::                      - Also fixed issue with forfiles.exe not being able to read UNC paths. We use pushd to get around this.
22-
::                  1.1   - Added option to use an exclude file to specify files/folders to exclude from the backup
22+
::                        Pushd auto-assigns the next available drive letter to a UNC path, then discards it when we use popd.
23-
::                  1.0b    Some tweaks to logging
23+
::                1.1   - Added option to use an exclude file to specify files/folders to exclude from the backup
24-
::                  1.0     Initial write
24+
::                1.0b    Some tweaks to logging
25
::                1.0     Initial write
26-
:: Notes:           My intention for this script was to keep the logic controlling schedules, backup type, etc out of the script and
26+
27-
::                  let an invoking program handle it (e.g. Task Scheduler). You simply run this script with a flag to perform an action.
27+
:: Notes:         My intention for this script was to keep the logic controlling schedules, backup type, etc out of the script and
28-
::                  If you want to schedule monthly backups, purge old files, etc, just set up task scheduler jobs for those tasks, 
28+
::                let an invoking program handle it (e.g. Task Scheduler). You simply run this script with a flag to perform an action.
29-
::                  where each job calls the script with a different flag.
29+
::                If you want to schedule monthly backups, purge old files, etc, just set up task scheduler jobs for those tasks, 
30
::                where each job calls the script with a different flag.
31-
:: Usage:           Run this script without any flags for a list of possible actions. Run it with a flag to perform that action.
31+
32-
::                  Flags:
32+
:: Usage:         Run this script without any flags for a list of possible actions. Run it with a flag to perform that action.
33-
::                   -f   create full backup
33+
::                Flags:
34-
::                   -d   create differential backup (full backup must already exist)
34+
::                 -f   create full backup
35-
::                   -r   restore from a backup (extracts to your staging area)
35+
::                 -d   create differential backup (full backup must already exist)
36-
::                   -a   archive (close out/rotate) the current backup set. This:
36+
::                 -r   restore from a backup (extracts to your staging area)
37-
::                        1. moves all .7z files in the %DESTINATION% into a folder named with the current date
37+
::                 -a   archive (close out/rotate) the current backup set. This:
38-
::                        2. deletes all .7z files from the staging area
38+
::                      1. moves all .7z files in the %DESTINATION% into a folder named with the current date
39-
::                   -c   clean up (delete) old backup sets from staging and destination. If you specify a number 
39+
::                      2. deletes all .7z files from the staging area
40-
::                        of days after the command it will run automatically without any confirmation. Be careful with this!
40+
::                 -c   clean up (delete) old backup sets from staging and destination. If you specify a number 
41-
::                   -s   show job options (show what the variables are set to)
41+
::                      of days after the command it will run automatically without any confirmation. Be careful with this!
42
::                 -s   show job options (show what the variables are set to)
43-
:: Important:       If you want to set this script up in Windows Task Scheduler, be aware that Task Scheduler
43+
44-
::                  can't use mapped network drives (X:\, Z:\, etc) when it is set to "Run even if user isn't logged on."
44+
:: Important:     If you want to set this script up in Windows Task Scheduler, be aware that Task Scheduler
45-
::                  The task will simply fail to do anything (because Scheduler can't see the drives). To work around this use
45+
::                can't use mapped network drives (X:\, Z:\, etc) when it is set to "Run even if user isn't logged on."
46-
::                  UNC paths instead (\\server\backup_folder etc) for your source, destination, and staging areas.
46+
::                The task will simply fail to do anything (because Scheduler can't see the drives). To work around this use
47
::                UNC paths instead (\\server\backup_folder etc) for your source, destination, and staging areas.
48
49-
::					1. Add md5sum checksum file in the backup directory (md5sum each full and diff and store in a file)
49+
50
::                1. Add md5sum checksum file in the backup directory (md5sum each full and diff and store in a file)
51
52
53
:: Prep
54
@echo off
55-
set VERSION=1.4.6
55+
56
set VERSION=1.4.7
57
set SCRIPT_NAME=%0%
58
59
:::::::::::::::
60
:: VARIABLES ::
61
:::::::::::::::
62
:: Rules for variables:
63
::  * NO quotes!                       (bad:  "c:\directory\path"       )
64
::  * NO trailing slashes on the path! (bad:   c:\directory\            )
65
::  * Spaces are okay                  (okay:  c:\my folder\with spaces )
66-
::                                     (okay:  \\172.16.1.5\share name  )
66+
67
::                                     (       \\172.16.1.5\share name  )
68
69
:: Specify the folder you want to back up here.
70
set SOURCE=C:\Users\vocatus\SuperImportantDocuments
71
72
:: Work area where everything is stored while compressing. Should be a fast drive or something that can handle a lot of writes
73
:: Recommend not using a network share unless it's Gigabit or faster.
74
set STAGING=P:\backup_staging
75
76-
set DESTINATION=\\CoolServerName\backup_vocatus\folder with spaces\SuperImportantDocuments
76+
77
set DESTINATION=\\CoolServerName\backups\folder with spaces\SuperImportantDocuments
78
79
:: If you want to customize the prefix of the backup files, do so here. Don't use any special characters (like underscores)
80
:: The script automatically suffixes an underscore to this name. Recommend not changing this unless you really need to.
81
::  * Spaces are NOT OKAY to use here!
82
set BACKUP_PREFIX=backup
83
84
:: OPTIONAL: If you want to exclude some files or folders, you can specify your exclude file here. The exclude file is a list of 
85
:: files or folders (wildcards in the form of * are allowed and recommended) to exclude.
86
:: If you specify a file here and the script can't find it, it will abort.
87-
set EXCLUSIONS_FILE=C:\Users\vocatus\root\Scripts\sysadmin\backup_differential_excludes.txt
87+
88
set EXCLUSIONS_FILE=C:\Users\vocatus\Scripts\backup_differential_excludes.txt
89
90
:: Log settings. Max size is how big (in bytes) the log can be before it is archived. 1048576 bytes is one megabyte
91
set LOGPATH=%SystemDrive%\Logs
92-
set LOG_MAX_SIZE=2097152
92+
93
set LOG_MAX_SIZE=104857600
94
95
:: Location of 7-Zip and forfiles.exe
96
set SEVENZIP="C:\Program Files\7-Zip\7z.exe"
97
set FORFILES=%WINDIR%\system32\forfiles.exe
98
99
:: Don't touch anything below this line. If you do, you will break something.
100
set CUR_DATE=%DATE:~-4%-%DATE:~4,2%-%DATE:~7,2%
101
set JOB_TYPE=%1
102
set JOB_ERROR=0
103
set DAYS=%2
104
set RESTORE_TYPE=NUL
105
106
107
::::::::::::::::::::::::::::
108
:: JOB TYPE DETERMINATION ::
109
::::::::::::::::::::::::::::
110
:job_type_determination
111
if '%JOB_TYPE%'=='' set JOB_TYPE=help
112
if '%JOB_TYPE%'=='/?' set JOB_TYPE=help
113
if '%JOB_TYPE%'=='-?' set JOB_TYPE=help
114
if '%JOB_TYPE%'=='-h' set JOB_TYPE=help
115
if '%JOB_TYPE%'=='--help' set JOB_TYPE=help
116
if /i '%1'=='/f' set JOB_TYPE=full
117
if /i '%1'=='-f' set JOB_TYPE=full
118
if /i '%1'=='/d' set JOB_TYPE=differential
119
if /i '%1'=='-d' set JOB_TYPE=differential
120
if /i '%1'=='/r' set JOB_TYPE=restore
121
if /i '%1'=='-r' set JOB_TYPE=restore
122
if /i '%1'=='/a' set JOB_TYPE=archive_backup_set
123
if /i '%1'=='-a' set JOB_TYPE=archive_backup_set
124
if /i '%1'=='/c' set JOB_TYPE=cleanup_archives
125
if /i '%1'=='-c' set JOB_TYPE=cleanup_archives
126
if /i '%1'=='/s' goto show_options
127
if /i '%1'=='-s' goto show_options
128
:: If none of the above were specified then show the help screen
129
if %JOB_TYPE%==help (
130
	echo. 
131
	echo   %SCRIPT_NAME% v%VERSION%
132
	echo.
133
	echo   Usage: %SCRIPT_NAME% ^< -f ^| -d ^| -r ^| -a ^| -c ^[days^] ^>
134
	echo.
135
	echo   Flags:
136
	echo    -f:  create a full backup
137
	echo    -d:  create a differential backup ^(requires an existing full backup^)
138
	echo    -r:  restore from a backup ^(extracts to %STAGING%\%BACKUP_PREFIX%_restore^)
139
	echo    -a:  archive the current backup set. This will:
140
	echo           1. move all .7z files located in:
141
	echo              %DESTINATION% 
142
	echo              into a dated archive folder.
143
	echo           2. purge ^(delete^) all copies in the staging area ^(%STAGING%^)
144
	echo    -c:  clean ^(AKA delete^) archived backup sets from staging and long-term storage.
145
	echo         Optionally specify number of days to run automatically. Be careful with this!
146
	echo         Note that this requires a previously-archived backup set ^(-a option^)
147
	echo    -s:  show job options ^(show what parameters the script WOULD execute with^)
148
	echo.
149
	echo   Edit this script before running it to specify your source, destination, and work directories.
150
	goto end
151
	)
152
153
154
:::::::::::::::::::::::
155
:: LOG FILE HANDLING ::
156
:::::::::::::::::::::::
157
:log
158
:: Make the logfile if it doesn't exist
159
if not exist %LOGPATH% mkdir %LOGPATH%
160
if not exist %LOGPATH%\%LOGFILE% echo. > %LOGPATH%\%LOGFILE%
161
162
:: Check log size. If it's less than our max, then go ahead and get started
163
for %%R in (%LOGPATH%\%LOGFILE%) do if %%~zR LSS %LOG_MAX_SIZE% goto required_files_check
164
165
:: If the log was too big, go ahead and rotate it.
166
pushd %LOGPATH% 2>&1
167
del /F %LOGFILE%.ancient 2>NUL
168
rename %LOGFILE%.oldest %LOGFILE%.ancient 2>NUL
169
rename %LOGFILE%.older %LOGFILE%.oldest 2>NUL
170
rename %LOGFILE%.old %LOGFILE%.older 2>NUL
171
rename %LOGFILE% %LOGFILE%.old 2>NUL
172
popd
173
174
175
::::::::::::::::::::::::::
176
:: REQUIRED FILES CHECK ::
177
::::::::::::::::::::::::::
178
:required_files_check
179
:: Make sure we can find 7-Zip
180
IF NOT EXIST %SEVENZIP% (
181
		echo %TIME%   ERROR: Couldn't find 7z.exe when script was invoked.>> %LOGPATH%\%LOGFILE%
182
		cls
183
		color 0c
184
		echo.
185
		echo  ERROR:
186
		echo.
187
		echo  Cannot find 7z.exe. You must edit this script
188
		echo  and specify the location of 7-Zip before continuing.
189
		echo.
190
		echo  Script tried to find it here:
191
		echo  %SEVENZIP%
192
		echo.
193
		pause
194
		color
195
		cls
196
		goto end 
197
		)
198
:: Make sure we can find forfiles.exe
199
IF NOT EXIST %FORFILES% (
200
		echo %TIME%   ERROR: Couldn't find forfiles.exe when script was invoked.>> %LOGPATH%\%LOGFILE%
201
		cls
202
		color 0c
203
		echo.
204
		echo  ERROR:
205
		echo.
206
		echo  Cannot find forfiles.exe. You must edit this script
207
		echo  and specify the location of forfiles.exe before continuing.
208
		echo.
209
		echo  Script tried to find it here:
210
		echo  %FORFILES%
211
		echo.
212
		pause
213
		color
214
		cls
215
		goto end
216
		)
217
218
219
::::::::::::::::::::
220
:: DECISION POINT ::
221
::::::::::::::::::::
222
:decision_point
223
if '%JOB_TYPE%'=='full' goto %JOB_TYPE%
224
if '%JOB_TYPE%'=='differential' goto %JOB_TYPE%
225
if '%JOB_TYPE%'=='restore' goto %JOB_TYPE%
226
if '%JOB_TYPE%'=='archive_backup_set' goto %JOB_TYPE%
227
if '%JOB_TYPE%'=='cleanup_archives' goto %JOB_TYPE%
228
goto end
229
230
231
::::::::::::::::::::::
232
:: SHOW JOB OPTIONS ::
233
::::::::::::::::::::::
234
:show_options
235
echo.
236
echo  Current configuration:
237
echo.
238
echo   Script Version:       %VERSION%
239
echo   Source:               %SOURCE%
240
echo   Destination:          %DESTINATION%
241
echo   Staging area:         %STAGING%
242
echo   Exclusions file:      %EXCLUSIONS_FILE%
243
echo   Backup prefix:        %BACKUP_PREFIX%
244
echo   Restores unpacked to: %STAGING%\%BACKUP_PREFIX%_restore
245
echo   Log file:             %LOGPATH%\%LOGFILE%
246
echo   Log max size:         %LOG_MAX_SIZE% bytes
247
echo.
248
echo  Edit this script with a text editor to customize these options.
249
echo.
250
goto end
251
252
253
::::::::::::::::::::::::
254
:: CREATE FULL BACKUP ::
255
::::::::::::::::::::::::
256
:full
257
:: Check for an exclude file and make sure it exists.
258
if '%EXCLUSIONS_FILE%'=='' goto full_go
259
IF NOT EXIST %EXCLUSIONS_FILE% (
260
		echo.
261
		echo %TIME%   ERROR: An exclusions file was specified but couldn't be found:>> %LOGPATH%\%LOGFILE%
262
		echo                %EXCLUSIONS_FILE%>> %LOGPATH%\%LOGFILE%
263
		echo %TIME%   ERROR: An exclusions file was specified but couldn't be found:
264
		echo                %EXCLUSIONS_FILE%
265
		goto end
266
		)
267
:full_go
268
echo.
269
echo.>> %LOGPATH%\%LOGFILE%
270
echo --------------------------------------------------------------------------------------------------->> %LOGPATH%\%LOGFILE%
271
echo  Differential Backup Script v%VERSION% - initialized %CUR_DATE% at%TIME% by %USERDOMAIN%\%USERNAME%>> %LOGPATH%\%LOGFILE%
272
echo.>> %LOGPATH%\%LOGFILE%
273
echo  Script location:  %~dp0\%SCRIPT_NAME%>> %LOGPATH%\%LOGFILE%
274
echo.>> %LOGPATH%\%LOGFILE%
275
echo  Job Options>> %LOGPATH%\%LOGFILE%
276
echo   Job type:        Full backup>> %LOGPATH%\%LOGFILE%
277
echo   Source:          %SOURCE%>> %LOGPATH%\%LOGFILE%
278
echo   Destination:     %DESTINATION%>> %LOGPATH%\%LOGFILE%
279
echo   Staging area:    %STAGING%>> %LOGPATH%\%LOGFILE%
280
echo   Exclusions file: %EXCLUSIONS_FILE%>> %LOGPATH%\%LOGFILE%
281
echo   Backup prefix:   %BACKUP_PREFIX%>> %LOGPATH%\%LOGFILE%
282
echo   Log location:    %LOGPATH%\%LOGFILE%>> %LOGPATH%\%LOGFILE%
283
echo   Log max size:    %LOG_MAX_SIZE% bytes>> %LOGPATH%\%LOGFILE%
284
echo --------------------------------------------------------------------------------------------------->> %LOGPATH%\%LOGFILE%
285
echo.>> %LOGPATH%\%LOGFILE%
286
echo %TIME%   Performing full backup of %SOURCE%...>> %LOGPATH%\%LOGFILE%
287
echo %TIME%   Performing full backup of %SOURCE%...
288
289
:: Build archive
290
echo.
291
echo %TIME%   Building archive in staging area %STAGING%...>> %LOGPATH%\%LOGFILE%
292
echo %TIME%   Building archive in staging area %STAGING%...
293-
echo [Beginning of 7zip output]>> %LOGPATH%\%LOGFILE% 2>&1
293+
294
echo ------- [ Beginning of 7zip output ] ------->> %LOGPATH%\%LOGFILE% 2>&1
295
if not '%EXCLUSIONS_FILE%'=='' %SEVENZIP% a "%STAGING%\%BACKUP_PREFIX%_full.7z" "%SOURCE%" -xr@"%EXCLUSIONS_FILE%" >> %LOGPATH%\%LOGFILE%
296-
echo [End of 7zip output]>> %LOGPATH%\%LOGFILE% 2>&1
296+
297
echo ------- [    End of 7zip output    ] ------->> %LOGPATH%\%LOGFILE% 2>&1
298
echo.>> %LOGPATH%\%LOGFILE%
299
echo.
300
301
:: Report on the build
302
if %ERRORLEVEL%==0 (
303
		echo %TIME%   Archive built successfully.>> %LOGPATH%\%LOGFILE%
304
		echo %TIME%   Archive built successfully.
305
		)
306
if not %ERRORLEVEL%==0 (
307
		set JOB_ERROR=1
308
		echo %TIME% ! Archive built with errors.>> %LOGPATH%\%LOGFILE%
309
		echo %TIME% ! Archive built with errors.
310
		)
311
:: Upload to destination
312
echo.
313
echo %TIME%   Uploading %BACKUP_PREFIX%_full.7z to %DESTINATION%...>> %LOGPATH%\%LOGFILE%
314
echo %TIME%   Uploading %BACKUP_PREFIX%_full.7z to %DESTINATION%...
315
echo.
316
echo.>> %LOGPATH%\%LOGFILE%
317
xcopy "%STAGING%\%BACKUP_PREFIX%_full.7z" "%DESTINATION%\" /Q /J /Y /Z >> %LOGPATH%\%LOGFILE%
318
echo.>> %LOGPATH%\%LOGFILE%
319
320
:: Report on the upload
321-
		echo %TIME%   Uploaded full backup to %DESTINATION% successfully.>> %LOGPATH%\%LOGFILE%
321+
322-
		echo %TIME%   Uploaded full backup to %DESTINATION% successfully.
322+
		echo %TIME%   Uploaded full backup to '%DESTINATION%' successfully.>> %LOGPATH%\%LOGFILE%
323
		echo %TIME%   Uploaded full backup to '%DESTINATION%' successfully.
324
		) ELSE (
325-
		echo %TIME% ! Upload of full backup to %DESTINATION% failed.>> %LOGPATH%\%LOGFILE%
325+
326-
		echo %TIME% ! Upload of full backup to %DESTINATION% failed.
326+
		echo %TIME% ! Upload of full backup to '%DESTINATION%' failed.>> %LOGPATH%\%LOGFILE%
327
		echo %TIME% ! Upload of full backup to '%DESTINATION%' failed.
328
		)
329
330
goto done
331
332
333
::::::::::::::::::::::::::::::::
334
:: CREATE DIFFERENTIAL BACKUP ::
335
::::::::::::::::::::::::::::::::
336
:differential
337
:: Check for an exclude file and make sure it exists.
338
if '%EXCLUSIONS_FILE%'=='' goto differential_go
339
IF NOT EXIST %EXCLUSIONS_FILE% (
340
		echo %TIME%   An exclusions file was specified but couldn't be found. Aborting.>> %LOGPATH%\%LOGFILE%
341
		echo           Looked here: %EXCLUSIONS_FILE%>> %LOGPATH%\%LOGFILE%
342
		echo %TIME%   An exclusions file was specified but couldn't be found. Aborting.
343
		echo           Looked here: %EXCLUSIONS_FILE%
344
		goto end
345
		)
346
:differential_go
347
echo.>> %LOGPATH%\%LOGFILE%
348
echo --------------------------------------------------------------------------------------------------->> %LOGPATH%\%LOGFILE%
349
echo  Differential Backup Script v%VERSION% - initialized %CUR_DATE% at%TIME% by %USERDOMAIN%\%USERNAME%>> %LOGPATH%\%LOGFILE%
350
echo.>> %LOGPATH%\%LOGFILE%
351
echo  Script location:  %SCRIPT_NAME%>> %LOGPATH%\%LOGFILE%
352
echo.>> %LOGPATH%\%LOGFILE%
353
echo  Job Options>> %LOGPATH%\%LOGFILE%
354
echo   Job type:        Differential backup>> %LOGPATH%\%LOGFILE%
355
echo   Source:          %SOURCE%>> %LOGPATH%\%LOGFILE%
356
echo   Destination:     %DESTINATION%>> %LOGPATH%\%LOGFILE%
357
echo   Staging area:    %STAGING%>> %LOGPATH%\%LOGFILE%
358
echo   Exclusions file: %EXCLUSIONS_FILE%>> %LOGPATH%\%LOGFILE%
359
echo   Backup prefix:   %BACKUP_PREFIX%>> %LOGPATH%\%LOGFILE%
360
echo   Log location:    %LOGPATH%\%LOGFILE%>> %LOGPATH%\%LOGFILE%
361
echo   Log max size:    %LOG_MAX_SIZE% bytes>> %LOGPATH%\%LOGFILE%
362
echo --------------------------------------------------------------------------------------------------->> %LOGPATH%\%LOGFILE%
363
echo.>> %LOGPATH%\%LOGFILE%
364
echo.
365
:: Check for full backup existence
366
if not exist "%STAGING%\%BACKUP_PREFIX%_full.7z" (
367
		set JOB_ERROR=1
368
		echo %TIME% ! ERROR: Couldn't find full backup file ^(%BACKUP_PREFIX%_full.7z^). You must create a full backup before a differential can be created.>> %LOGPATH%\%LOGFILE%
369
		echo %TIME% ! ERROR: Couldn't find full backup file ^(%BACKUP_PREFIX%_full.7z^). You must create a full backup before a differential can be created.
370
		goto end
371
		) ELSE (
372
		:: Backup existed, so go ahead
373
		echo %TIME%   Performing differential backup of %SOURCE%...>> %LOGPATH%\%LOGFILE%
374
		echo %TIME%   Performing differential backup of %SOURCE%...
375
		)
376
		
377
:: Build archive
378
:differential_build
379
echo.
380
echo %TIME%   Building archive in staging area %STAGING%...>> %LOGPATH%\%LOGFILE%
381
echo %TIME%   Building archive in staging area %STAGING%...
382-
echo [Beginning of 7zip output]>> %LOGPATH%\%LOGFILE% 2>&1
382+
383
echo ------- [ Beginning of 7zip output ] ------->> %LOGPATH%\%LOGFILE% 2>&1
384
if not '%EXCLUSIONS_FILE%'=='' %SEVENZIP% u "%STAGING%\%BACKUP_PREFIX%_full.7z" "%SOURCE%" -ms=off -mx=9 -xr@"%EXCLUSIONS_FILE%" -t7z -u- -up0q3r2x2y2z0w2!"%STAGING%\%BACKUP_PREFIX%_differential_%CUR_DATE%.7z" >> %LOGPATH%\%LOGFILE% 2>&1
385-
echo [End of 7zip output]>> %LOGPATH%\%LOGFILE% 2>&1
385+
386
echo ------- [    End of 7zip output    ] ------->> %LOGPATH%\%LOGFILE% 2>&1
387
echo.>> %LOGPATH%\%LOGFILE%
388
echo.
389
:: Report on the build
390
if %ERRORLEVEL%==0 (
391
		echo %TIME%   Archive built successfully.>> %LOGPATH%\%LOGFILE%
392
		echo %TIME%   Archive built successfully.
393
		)
394
if not %ERRORLEVEL%==0 (
395
		set JOB_ERROR=1
396
		echo %TIME% ! Archive built with errors.>> %LOGPATH%\%LOGFILE%
397
		echo %TIME% ! Archive built with errors.
398
		)
399
400
401
:: Upload to destination
402
echo.
403
echo %TIME%   Uploading %BACKUP_PREFIX%_differential_%CUR_DATE%.7z to %DESTINATION%... >> %LOGPATH%\%LOGFILE%
404
echo %TIME%   Uploading %BACKUP_PREFIX%_differential_%CUR_DATE%.7z to %DESTINATION%...
405
echo.>> %LOGPATH%\%LOGFILE%
406
xcopy "%STAGING%\%BACKUP_PREFIX%_differential_%CUR_DATE%.7z" "%DESTINATION%\" /Q /J /Y /Z >> %LOGPATH%\%LOGFILE%
407
echo.>> %LOGPATH%\%LOGFILE%
408
:: Report on the upload
409
if %ERRORLEVEL%==0 (
410
		echo %TIME%   Uploaded differential file successfully.>> %LOGPATH%\%LOGFILE%
411
		echo %TIME%   Uploaded differential file successfully.
412
		)
413
414
if not %ERRORLEVEL%==0 (
415
		set JOB_ERROR=1
416
		echo %TIME% ! Upload of differential file failed.>> %LOGPATH%\%LOGFILE%
417
		echo %TIME% ! Upload of differential file failed.
418
		)
419
420
goto done
421
422
423
:::::::::::::::::::::::::::
424
:: RESTORE FROM A BACKUP ::
425
:::::::::::::::::::::::::::
426
:restore
427
echo.
428
echo  Restoring from a backup set.
429
echo.
430
echo   These backups are available:
431
echo.
432
dir /B /A:-D "%STAGING%" 2>NUL
433
echo.
434
echo  Enter the filename to restore from exactly as it appears above.
435
echo  ^(Note: archived backup sets are not shown^)
436
echo.
437
:restore_menu
438
set BACKUP_FILE=
439
set /p BACKUP_FILE=Filename: 
440
if %BACKUP_FILE%==exit goto end
441
echo.
442
:: Make sure user didn't fat-finger the file name
443
if not exist "%STAGING%\%BACKUP_FILE%" (
444
		echo  ! ERROR: That file wasn^'t found. Check your typing and try again. && echo. && goto restore_menu
445
		goto restore_menu
446
		)
447
448
set CHOICE=y
449
echo  ! Selected file '%BACKUP_FILE%' 
450
echo.
451
set /p CHOICE=Is this correct [y]?: 
452
	if not %CHOICE%==y echo  Going back to menu... && goto restore_menu
453
echo.
454
echo  Great. Press any key to get started.
455
pause >NUL
456
echo  ! Starting restoration at%TIME% on %CUR_DATE%
457
echo    This might take a while, be patient...
458
459
:: Test if we're doing a full or differential restore.
460
if %BACKUP_FILE%==%BACKUP_PREFIX%_full.7z set RESTORE_TYPE=full
461
if not %BACKUP_FILE%==%BACKUP_PREFIX%_full.7z set RESTORE_TYPE=differential
462
463
464
:restore_go
465
echo.>> %LOGPATH%\%LOGFILE%
466
echo --------------------------------------------------------------------------------------------------->> %LOGPATH%\%LOGFILE%
467
echo  Differential Backup Script v%VERSION% - initialized %CUR_DATE% at%TIME% by %USERDOMAIN%\%USERNAME%>> %LOGPATH%\%LOGFILE%
468
echo.>> %LOGPATH%\%LOGFILE%
469
echo  Script location:  %SCRIPT_NAME%>> %LOGPATH%\%LOGFILE%
470
echo.>> %LOGPATH%\%LOGFILE%
471
echo  Job Options>> %LOGPATH%\%LOGFILE%
472
echo   Job type:        %RESTORE_TYPE% restore>> %LOGPATH%\%LOGFILE%
473
echo   Source:          %STAGING%\%BACKUP_PREFIX%_full.7z>> %LOGPATH%\%LOGFILE%
474
echo   Destination:     %STAGING%\%BACKUP_PREFIX%\>> %LOGPATH%\%LOGFILE%
475
echo   Staging area:    %STAGING%>> %LOGPATH%\%LOGFILE%
476
echo   Exclusions file: %EXCLUSIONS_FILE%>> %LOGPATH%\%LOGFILE%
477
echo   Backup prefix:   %BACKUP_PREFIX%>> %LOGPATH%\%LOGFILE%
478
echo   Log location:    %LOGPATH%\%LOGFILE%>> %LOGPATH%\%LOGFILE%
479
echo   Log max size:    %LOG_MAX_SIZE% bytes>> %LOGPATH%\%LOGFILE%
480
echo --------------------------------------------------------------------------------------------------->> %LOGPATH%\%LOGFILE%
481
echo.
482
:: Detect our backup type and inform the user
483
if %RESTORE_TYPE%==differential (
484
		echo %TIME%   Restoring from differential backup. Will unpack full backup then differential.>> %LOGPATH%\%LOGFILE%
485
		echo %TIME%   Restoring from differential backup. Will unpack full backup then differential.
486
		)
487
if %RESTORE_TYPE%==full (
488
		echo %TIME%   Restoring from full backup.>> %LOGPATH%\%LOGFILE%
489
		echo %TIME%   Restoring from full backup.
490
		echo %TIME%   Unpacking full backup...>> %LOGPATH%\%LOGFILE%
491
		echo %TIME%   Unpacking full backup...
492
		)
493
494
:: Start the restoration
495
echo.>> %LOGPATH%\%LOGFILE%
496-
echo [Beginning of 7zip output]>> %LOGPATH%\%LOGFILE% 2>&1
496+
497
echo ------- [ Beginning of 7zip output ] ------->> %LOGPATH%\%LOGFILE% 2>&1
498-
echo [End of 7zip output]>> %LOGPATH%\%LOGFILE% 2>&1
498+
499
echo ------- [    End of 7zip output    ] ------->> %LOGPATH%\%LOGFILE% 2>&1
500
:: Report on the unpack
501
if %ERRORLEVEL%==0 (
502
		echo %TIME%   Full backup unpacked successfully.>> %LOGPATH%\%LOGFILE%
503
		echo %TIME%   Full backup unpacked successfully.
504
		)
505
if not %ERRORLEVEL%==0 (
506
		set JOB_ERROR=1
507
		echo %TIME% ! Full backup unpacked with errors.>> %LOGPATH%\%LOGFILE%
508
		echo %TIME% ! Full backup unpacked with errors.
509
		)
510
:: If we're just doing a full restore (no differential), then go to the end
511
if %RESTORE_TYPE%==full goto done
512
		
513
:: Now we unpack our differential file
514
echo.
515
echo %TIME%   Unpacking differential file %BACKUP_FILE%...>> %LOGPATH%\%LOGFILE%
516
echo %TIME%   Unpacking differential file %BACKUP_FILE%...
517-
echo [Beginning of 7zip output]>> %LOGPATH%\%LOGFILE% 2>&1
517+
518
echo ------- [ Beginning of 7zip output ] ------->> %LOGPATH%\%LOGFILE% 2>&1
519-
echo [End of 7zip output]>> %LOGPATH%\%LOGFILE% 2>&1
519+
520
echo ------- [    End of 7zip output    ] ------->> %LOGPATH%\%LOGFILE% 2>&1
521
echo.
522
:: Report on the unpack
523
if %ERRORLEVEL%==0 (
524
		echo %TIME%   Differential file unpacked successfully.>> %LOGPATH%\%LOGFILE%
525
		echo %TIME%   Differential file unpacked successfully.
526
		) ELSE (
527
		:: Something broke!
528
		set JOB_ERROR=1
529
		echo %TIME% ! Differential file unpacked with errors.>> %LOGPATH%\%LOGFILE%
530
		echo %TIME% ! Differential file unpacked with errors.
531
		)
532
goto done
533
534
535
::::::::::::::::::::::::
536
:: ARCHIVE BACKUP SET :: aka rotate backups
537
::::::::::::::::::::::::
538
:archive_backup_set
539
echo.>> %LOGPATH%\%LOGFILE%
540
echo --------------------------------------------------------------------------------------------------->> %LOGPATH%\%LOGFILE%
541
echo  Differential Backup Script v%VERSION% - initialized %CUR_DATE% at%TIME% by %USERDOMAIN%\%USERNAME%>> %LOGPATH%\%LOGFILE%
542
echo.>> %LOGPATH%\%LOGFILE%
543
echo  Script location:  %SCRIPT_NAME%>> %LOGPATH%\%LOGFILE%
544
echo.>> %LOGPATH%\%LOGFILE%
545
echo  Job Options>> %LOGPATH%\%LOGFILE%
546
echo   Job type:        Archive/rotate backup set>> %LOGPATH%\%LOGFILE%
547
echo   Source:          %SOURCE%>> %LOGPATH%\%LOGFILE%
548
echo   Destination:     %DESTINATION%>> %LOGPATH%\%LOGFILE%
549
echo   Staging area:    %STAGING%>> %LOGPATH%\%LOGFILE%
550
echo   Exclusions file: %EXCLUSIONS_FILE%>> %LOGPATH%\%LOGFILE%
551
echo   Backup prefix:   %BACKUP_PREFIX%>> %LOGPATH%\%LOGFILE%
552
echo   Log location:    %LOGPATH%\%LOGFILE%>> %LOGPATH%\%LOGFILE%
553
echo   Log max size:    %LOG_MAX_SIZE% bytes>> %LOGPATH%\%LOGFILE%
554
echo --------------------------------------------------------------------------------------------------->> %LOGPATH%\%LOGFILE%
555
echo.>> %LOGPATH%\%LOGFILE%
556
echo %TIME%   Archiving current backup set to %DESTINATION%\%CUR_DATE%_%BACKUP_PREFIX%_set.>> %LOGPATH%\%LOGFILE%
557
echo %TIME%   Archiving current backup set to %DESTINATION%\%CUR_DATE%_%BACKUP_PREFIX%_set.
558
:: Final destination: Make directory, move files
559
pushd "%DESTINATION%"
560
mkdir %CUR_DATE%_%BACKUP_PREFIX%_set >> %LOGPATH%\%LOGFILE%
561
move /Y *.* %CUR_DATE%_%BACKUP_PREFIX%_set >> %LOGPATH%\%LOGFILE%
562
popd
563
echo.
564
echo %TIME%   Deleting all copies in the staging area...>> %LOGPATH%\%LOGFILE%
565
echo %TIME%   Deleting all copies in the staging area...
566
:: Staging area: Delete old files
567
del /Q /F "%STAGING%\*.7z">> %LOGPATH%\%LOGFILE%
568
echo.>> %LOGPATH%\%LOGFILE%
569
echo.
570
571
:: Report
572
echo.>> %LOGPATH%\%LOGFILE%
573
echo %TIME%   Backup set archived. All unarchived files in staging area were deleted.>> %LOGPATH%\%LOGFILE%
574
echo %TIME%   Backup set archived. All unarchived files in staging area were deleted.
575
echo.>> %LOGPATH%\%LOGFILE%
576
goto done
577
578
579
:::::::::::::::::::::::::::::::::::
580
:: CLEAN UP ARCHIVED BACKUP SETS :: aka delete old sets
581
:::::::::::::::::::::::::::::::::::
582
:cleanup_archives
583
IF NOT '%DAYS%'=='' goto cleanup_archives_go
584
585
:: List the backup sets
586
:cleanup_archives_list
587
echo.
588
echo CURRENT BACKUP SETS:
589
echo.
590
echo IN STAGING          : ^(%STAGING%^)
591
echo ---------------------
592
dir /B /A:D "%STAGING%" 2>&1
593
echo.
594
echo.
595
echo IN LONG-TERM STORAGE: ^(%DESTINATION%^)
596
echo ---------------------
597
dir /B /A:D "%DESTINATION%" 2>&1
598
echo.
599
:cleanup_archives_list2
600
echo.
601
set DAYS=180
602
echo Delete backup sets older than how many days? ^(you will be prompted for confirmation^)
603
set /p DAYS=[%DAYS%]?: 
604
if %DAYS%==exit goto end
605
echo.
606
:: Tell user what will happen
607
echo THESE BACKUP SETS WILL BE DELETED:
608
echo ----------------------------------
609
:: List files that would match. 
610
:: We have to use PushD to get around forfiles.exe not using UNC paths. pushd automatically assigns the next free drive letter
611
echo From staging:
612
pushd "%STAGING%"
613
FORFILES /D -%DAYS% /C "cmd /c IF @isdir == TRUE echo @path" 2>NUL
614
popd
615
echo.
616
echo From long-term storage:
617
pushd "%DESTINATION%"
618
FORFILES /D -%DAYS% /C "cmd /c IF @isdir == TRUE echo @path" 2>NUL
619
popd
620
echo.
621
set HMMM=n
622
set /p HMMM=Is this okay [%HMMM%]?: 
623
if /i %HMMM%==n echo. && echo Canceled. Returning to menu. && goto cleanup_archives_list2
624
if %DAYS%==exit goto end
625
echo.
626
set CHOICE=n
627
set /p CHOICE=Are you absolutely sure [%CHOICE%]?: 
628
if not %CHOICE%==y echo. && echo Canceled. Returning to menu. && goto cleanup_archives_list2
629
echo.
630
echo  Okay, starting deletion.
631
632
:: Go ahead and do the cleanup. 
633
:cleanup_archives_go
634
echo --------------------------------------------------------------------------------------------------->> %LOGPATH%\%LOGFILE%
635
echo  Differential Backup Script v%VERSION% - initialized %CUR_DATE% at%TIME% by %USERDOMAIN%\%USERNAME%>> %LOGPATH%\%LOGFILE%
636
echo.>> %LOGPATH%\%LOGFILE%
637
echo  Script location:  %SCRIPT_NAME%>> %LOGPATH%\%LOGFILE%
638
echo.>> %LOGPATH%\%LOGFILE%
639
echo   Job type:        Delete archived backup sets older than %DAYS% days.>> %LOGPATH%\%LOGFILE%
640
echo   Source:          %SOURCE%>> %LOGPATH%\%LOGFILE%
641
echo   Destination:     %DESTINATION%>> %LOGPATH%\%LOGFILE%
642
echo   Staging area:    %STAGING%>> %LOGPATH%\%LOGFILE%
643
echo   Exclusions file: %EXCLUSIONS_FILE%>> %LOGPATH%\%LOGFILE%
644
echo   Backup prefix:   %BACKUP_PREFIX%>> %LOGPATH%\%LOGFILE%
645
echo   Log location:    %LOGPATH%\%LOGFILE%>> %LOGPATH%\%LOGFILE%
646
echo   Log max size:    %LOG_MAX_SIZE% bytes>> %LOGPATH%\%LOGFILE%
647
echo --------------------------------------------------------------------------------------------------->> %LOGPATH%\%LOGFILE%
648
echo.>> %LOGPATH%\%LOGFILE%
649
echo.
650
echo %TIME%   Deleting backup sets that are older than %DAYS% days...>> %LOGPATH%\%LOGFILE%
651
echo %TIME%   Deleting backup sets that are older than %DAYS% days...
652
653
:: This cleans out the staging area.
654
:: First FORFILES command tells the logfile what will get deleted. Second command actually deletes.
655
pushd "%STAGING%"
656
FORFILES /D -%DAYS% /C "cmd /c IF @isdir == TRUE echo @path" >> %LOGPATH%\%LOGFILE%
657
FORFILES /S /D -%DAYS% /C "cmd /c IF @isdir == TRUE rmdir /S /Q @path"
658
popd
659
660
:: This cleans out the destination / long-term storage area.
661
:: First FORFILES command tells the logfile what will get deleted. Second command actually deletes.
662
pushd "%DESTINATION%"
663
FORFILES /D -%DAYS% /C "cmd /c IF @isdir == TRUE echo @path" >> %LOGPATH%\%LOGFILE%
664
FORFILES /S /D -%DAYS% /C "cmd /c IF @isdir == TRUE rmdir /S /Q @path"
665
popd
666
667
echo.
668
:: Report on the cleanup
669
if %ERRORLEVEL%==0 (
670
		echo %TIME%   Cleanup completed successfully.>> %LOGPATH%\%LOGFILE%
671
		echo %TIME%   Cleanup completed successfully.
672
		)
673
if not %ERRORLEVEL%==0 (
674
		set JOB_ERROR=1
675
		echo %TIME% ! Cleanup completed with errors.>> %LOGPATH%\%LOGFILE%
676
		echo %TIME% ! Cleanup completed with errors.
677
		)
678
goto done
679
680
681
:::::::::::::::::::::::
682
:: COMPLETION REPORT ::
683
:::::::::::::::::::::::
684
:done
685
:: One of these displays if the operation was a restore operation
686
if %RESTORE_TYPE%==full (
687
		echo %TIME%   Restored full backup to %STAGING%\%BACKUP_PREFIX%>> %LOGPATH%\%LOGFILE%
688
		echo %TIME%   Restored full backup to %STAGING%\%BACKUP_PREFIX%
689
		)
690
691
if %RESTORE_TYPE%==differential (
692
		echo.
693
		echo %TIME%   Restored full and differential backup to %STAGING%\%BACKUP_PREFIX%>> %LOGPATH%\%LOGFILE%
694
		echo %TIME%   Restored full and differential backup to %STAGING%\%BACKUP_PREFIX%
695
		)
696
697-
echo %TIME%   %SCRIPT_NAME% complete on %CUR_DATE% at%TIME%.>> %LOGPATH%\%LOGFILE%
697+
698-
echo %TIME%   %SCRIPT_NAME% complete on %CUR_DATE% at%TIME%.
698+
echo %TIME%   %SCRIPT_NAME% complete.>> %LOGPATH%\%LOGFILE%
699
echo %TIME%   %SCRIPT_NAME% complete.
700
if '%JOB_ERROR%'=='1' echo. && echo %TIME% ! Note: Script exited with errors.>> %LOGPATH%\%LOGFILE%
701
if '%JOB_ERROR%'=='1' echo. && echo %TIME% ! Note: Script exited with errors. Maybe check the log.
702
703
:end
704
:: Clean up our temp exclude file
705
if exist %TEMP%\DEATH_BY_HAMSTERS.txt del /F /Q %TEMP%\DEATH_BY_HAMSTERS.txt
706
ENDLOCAL