After 11 years I thought it is time to update this topic with better batch file solution working for Windows XP and later Windows versions.
First, take a look on article about
comparing file times with batch code written by me on Stack Overflow if being interested in using date and time in batch files with lots of useful information.
Running in a command prompt window the command
wmic OS get /? displays what
WMIC: WMI command-line utility offers on operating system related data. Most interesting for this task is:
LocalDateTime.
Running in a command prompt window
WMIC OS GET LocalDateTime /format:value results in an output like this one:
Code: Select all
LocalDateTime=20160229084227.609000+060
It can be seen that the value is
YYYYMMDDHHmmss.
microsecond±UTC offset in minutes. The format of this value is independent on language of operating system and current region and languages settings. The year is always the first with always 4 digits, the month is always the second with always 2 digits, the day is always the third with 2 digits, and so on without language specific date/time separators.
Next we need to run in command prompt window
for /? and
set /? for help on command
FOR needed to get the output of
wmic loaded into an environment variable and for help on command
SET to reformat this date/time value into the format we want in file name.
So a simple batch file executed via a user tool for creating a backup of active file would be:
Code: Select all
@echo off
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS get LocalDateTime /format:value') do set "LocalDateTime=%%I"
set "LocalDateTime=%LocalDateTime:~0,4%-%LocalDateTime:~4,2%-%LocalDateTime:~6,2%_%LocalDateTime:~8,2%-%LocalDateTime:~10,2%-%LocalDateTime:~12,2%"
copy "%~1" "%~dpn1_%LocalDateTime%%~x1"
This batch file with just four lines works in general.
But does it work for every file backup operation?
What else should we take into account for writing the batch file?
- The batch file should do nothing if called without a parameter like when somebody double clicks on it.
- The batch file should do nothing if called with a string which contains the wildcard characters * or ? as the batch file is designed for creating a copy of a single file and not a set of files matching a wildcard pattern.
- The batch file should do nothing if called with a string which is not the name of an existing file.
- The batch file should work also for on Windows unusual file names, but common on *nix systems like .htaccess.
- The batch file should work also for a file with hidden or system attribute set opened in UltraEdit for editing which command COPY never copies (file not found).
- And last it would be perhaps also good to get informed about an error on copying because of no read access permission on file to copy or no write access permission on file to create.
So which batch file works really for all single file backup operations taking all requirements listed above also into account.
Code: Select all
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Note: Remove both /V for copying large files faster without verification.
rem Exit with error code 2 if batch file was called without a file name.
if "%~1" == "" exit /B 2
rem Exit with error code 3 if first parameter contains either * or ?
rem because a single named file should be copied and not a set of files.
for /F "delims=*?" %%I in ("#%~1#") do if not "%%I" == "#%~1#" exit /B 3
rem Exit with error code 4 if first parameter does not
rem specify name of an existing file (or directory).
if not exist "%~1" exit /B 4
rem Exit with error code 5 if first parameter is the name
rem of an existing directory instead of an existing file.
if exist "%~1\" exit /B 5
rem Get local date and time in region and language independent format YYYYMMDDHHmmss.
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS get LocalDateTime /format:value') do set "LocalDateTime=%%I"
rem Reformat the local date and time to format YYYY-MM-DD_HH-mm-ss.
set "LocalDateTime=%LocalDateTime:~0,4%-%LocalDateTime:~4,2%-%LocalDateTime:~6,2%_%LocalDateTime:~8,2%-%LocalDateTime:~10,2%-%LocalDateTime:~12,2%"
rem The Windows Command Processor interprets everything after last point
rem as file extension even if there is nothing left like on hidden files
rem on *nix systems starting with a point to be hidden like .htaccess
rem This must be taken into account for the file copying task.
if "%~n1" == "" (
set "FileNameWithPath=%~dpx1"
set "FileExtension="
) else (
set "FileNameWithPath=%~dpn1"
set "FileExtension=%~x1"
)
echo Copy "%~f1" to "%FileNameWithPath%_%LocalDateTime%%FileExtension%"
rem Try to copy the file with standard command COPY with verification.
copy /V /Y "%~f1" "%FileNameWithPath%_%LocalDateTime%%FileExtension%" >nul 2>&1
rem Copying failed if exit code of COPY is greater or equal 1.
if errorlevel 1 goto UseXcopy
echo Success
exit /B 0
rem Command COPY can't be used for copying files with either hidden or
rem system attribute set or if destination file exists already and has
rem read-only attribute set. Therefore must use the command XCOPY as this
rem command can copy also hidden and system files by using option /H,
rem with keeping the attributes of copied file by using option /K,
rem with overwriting also already existing file by using option /Y,
rem even if destination file is read-only by using option /R,
rem with verifying also successful copying of file by using option /V
rem and with automatic continuation on failure by using option /C.
rem But there is a real problem on using XCOPY for copying a single file:
rem It prompts the user if the destination is a file or a directory if the
rem destination file does not already exist. And this prompt depends on
rem language of operating system.
rem A hack is used to get the language dependent letter from prompt text
rem without really copying any file. Command XCOPY is used to start copying
rem the batch file itself to folder for temporary files with file extension
rem being TMP for destination file. This results in a prompt by XCOPY if
rem there is not already a file with that name in temporary files folder
rem which is very unlikely. The handler of device NULL is used as an input
rem handler for XCOPY resulting in breaking the copying process after the
rem prompt was output by XCOPY 2 times. This output is processed in a FOR
rem loop which is exited on first line starting with an opening parenthesis.
rem This is the line on which second character defines the letter to use
rem for specifying that destination is a file.
rem The lines from the line below label UseXcopy up to and including line
rem with label CopyFile can be removed completely if in line below label
rem CopyFile the string %PromptAnswer% is replaced by the letter selecting
rem file as answer on the machine on which this batch file is executed. On
rem English Windows this would be letter F for file and letter D for Datei
rem on German Windows.
:UseXcopy
del /F "%TEMP%\%~n0.tmp" 2>nul
for /F %%I in ('%SystemRoot%\System32\xcopy.exe "%~f0" "%TEMP%\%~n0.tmp" ^<nul') do (
set "PromptAnswer=%%I"
setlocal EnableDelayedExpansion
if "!PromptAnswer:~0,1!" == "(" set "PromptAnswer=!PromptAnswer:~1,1!" & goto CopyFile
endlocal
)
echo ERROR: Failed to determine letter for answering prompt of XCOPY.
exit /B 6
rem The next issue to solve is that XCOPY is not reliable on error codes.
rem For example if option /R would not be used and destination file has
rem read-only attribute set, the single file copy fails with error message
rem access denied written to STDERR stream, but the exit code of XCOPY is
rem nevertheless 0 like on a successful copy. On other errors the exit code
rem is correct like write access on existing destination file fails because
rem the destination file is opened currently by an application with blocking
rem shared access completely or allows just shared read for the file.
rem So instead of evaluating the exit code, XCOPY is executed within a FOR
rem loop to evaluate the number of copied files output on last line by XCOPY
rem to STDOUT stream. The number of copied files is 1 on successful copy of
rem the single file. Any other string (number 0) is interpreted as failed
rem copy of the specified file. Output of copied files is suppressed by
rem using option /Q of XCOPY.
:CopyFile
endlocal & set "PromptAnswer=%PromptAnswer%"
for /F %%I in ('echo %PromptAnswer% ^| %SystemRoot%\System32\xcopy.exe "%~f1" "%FileNameWithPath%_%LocalDateTime%%FileExtension%" /C /H /K /Q /R /V /Y') do set "FilesCopied=%%I"
if not "%FilesCopied%" == "1" (
echo ERROR: Creating the backup failed, see error message above.
exit /B 1
)
echo Success
This batch code was tested on German Windows XP SP3 x86 and English Windows 7 SP1 x64.