Compare two folders' contents instead of two files contents' through batch file - batch-file

I'm writing backup batch file for a particular folder that is located in a shared network folder, to my personal Windows machine.
I want to keep track of changes made on this network folder, so I keep a lot of backup folders which have a datestamp+timestamp name like 20181224145231 which is the backup folder created on the 24th of December (12), 2018 at 14h52min31sec.
All of my backup folders of datestamp+timestamp are located in a separate folder.
To do this I came up with a script that grabs date and time from the system and checks if a particular file in the original folder is different than the one located in the last backup folder using fc and a for loop to grab the last backup folder created in the past.
Things have grown and I need to compare the content of the whole folder (with subfolders) and not just a file. And that's where I've hit a wall.
I've looked into comp and fc, but can't seem to find a way. Robocopy syncs folders, but I want to create a new folder each time changes have occured. One thing I'm thinking about is creating a comparison file in both folders like a 7-zip file and running fc on both of these, but it seems rather extreme.
So summing up my question is:
How to check if the most recent backup has the same files as with the network shared folder without third party-tools through batch file?

According to your requirements, specified in comments, you can try:
#echo off
rem Set variables for size count:
set total_size_backup=0
set total_size_origin=0
rem Find the most recent BACKUP folder:
for /F "delims=" %%A IN ('dir /b /AD /OD') do set "folder_to_search=%%~fA"
rem Find the size of all files inside the backup folder:
for /R "%folder_to_search%" %%B IN (*.*) do (
set /a "total_size_backup+=%%~zB"
)
rem Find the size of the original folder:
for /R "full_path_to_folder_with_original_files" %%C IN (*.*) do (
set /a "total_size_origin+=%%~zC"
)
rem Compare the two sizes from these two folders. If they are NOT the same include your code there.
if %total_size_backup% EQU %total_size_origin% (
echo Well Done! Your newest backup files and your original files are up-to-date!
pause>nul
exit /b 0
) else (
echo Ooops! Your newest backup files and your original files are out-of-date! Never worry! Running backup now, please wait...
start /min /wait your_backup_file.bat
echo Updated files successfully!
exit /b %errorlevel%
)

Related

Automate file replacement

I have a task to rename a file and place another file with same name in the same folder
Like for e.g. a folder C:/test I have multiple files .txt (suppose test.txt is the one needed rename and replace)
I want to rename test.txt to test_bkp%date% and place new file there.
Need help to start the logic.
#ECHO OFF
SET "sourcedir=C:\Users\test\new"
FOR /f "delims=" %%a IN (
'dir /b /a-d "%C:\Users\Test\new\%filenames%.txt" '
) DO (
SET "filename=%%a"
ECHO REN "%C:\Users\Test\new\%%a C:\Users\Test\new\%%a_bk_date.*%"
)
GOTO :EOF
Let me explain what I am trying to achieve. I get file with updated data often. I cannot just go ahead and replace the old file with new. I have to take a backup and place the new file in the folder.
This is my first try using batch scripting
As soon as you write a new version of a file into the same folder than the original (with the same name), it's already too late to rename the original - it doesn't exist anymore. You need two folders: one that receives new versions (new) and one where you keep your renamed files plus the new ones (old)
#ECHO OFF
setlocal
set "source=C:\Users\test\new"
set "destin=C:\Users\test\old"
set "files=*.txt"
REM for every matching file in the source folder:
for %%A in ("%source%\%files%") do (
REM if there is such a file in the destination folder, rename it:
if exist "%destin%\%%~nxA" ren "%destin%\%%~nxA" "%%~nA-%date%%%~xA"
REM only then copy the file:
copy "%%~fA" "%destin%\"
)
This will fail if you run it more than once per day. (More code needed to handle that; for example, adding time too)
It will also fail if your %date% contains characters that are not allowed in file names (my %date% looks like 29.01.2019). (More code needed to handle that; for example %date:/=-%)

Batch Script Move file to directory based on its current directory

I'm attempting to sort a lot of files based on the current location of the file e.g.:
File 1 is located at C:\Work\Movies\Subs\Subtitle.txt
File 2 is located at C:\Work\Movies\Subs\Special\Subtitle.txt
File 3 is located at C:\Work\MoviesSpanish\Subs\Subtitle.txt
I'm trying to move the files like so:
File 1 to C:\Work\InProgress\Movies\Subs\Subtitle.txt
File 2 to C:\Work\InProgress\Movies\Subs\Special\Subtitle.txt
File 3 to C:\Work\InProgress\MoviesSpanish\Subs\Subtitle.txt
The Batch Script is to be located in C:\Work\MoveFile.bat
There are away more files then I listed above. Just for an estimate I would say around 300-500 per folder and there's a lot more subdirectories (e.g. .\Subs\01\ all the way up to .\Subs\300\ and they each contain a bunch of text files). I need to move all of the .txt files from their current locations to a new folder in C:\Work\ while retaining the rest of the directory location. So they get moved to C:\Work\[New Folder]\[Rest of Original Location]
I want to do this in batch but I'm not sure where to start. I already have the following code, which deletes files that don't contain a specific string:
for /r %%Z in (*.txt) do (
SET "count="
for /F "usebackq delims=," %%A in ("%%Z") do (
if /i "%%A"=="LN" set count=1
)
if not defined count echo del "%%Z"
if not defined count del "%%Z"
if defined count move "%%Z"
echo %count%
echo %%Z
)
But I'm not sure how to obtain the correct directory to move them into. I was thinking about for loop that reads the directory string of the file in question and uses delims=/ but it kept reading the text file rather then the path (and when I didn't use quotes on %%Z, it decided it couldn't find the file).
This is untested - it uses robocopy to move the *.txt files into a new location which is outside the source folder (because of cyclic copy restrictions) and then moves them back to the new "C:\Work\InProgress" folder.
If %temp% and c:\work are on the same drive then it should be swift.
Change c:\work in both places to a test folder with a few copies of your files and test it.
#echo off
robocopy "C:\Work" "%temp%\temporarymoviefolder" *.txt /s /mov
robocopy "%temp%\temporarymoviefolder" "C:\Work\InProgress" *.txt /s /mov
pause

Add error handling to existing Windows batch script-> to copy the newest file from a directory

I found a good post here that queries for the latest sql server backup, and then copies it over to the remote server in preparation for a restore. It's a batch file that is executed using cmd via sql agent step inside the sql restore job. I'm looking for help in adding extra logic to the existing script below:
:Variables
SET DatabaseBackupPath=\\virtualserver1\Database Backups
echo.
echo Restore WebServer Database
FOR /F "delims=|" %%I IN ('DIR "%DatabaseBackupPath%\WebServer\*.bak" /B /O:D') DO SET NewestFile=%%I
copy "%DatabaseBackupPath%\WebServer\%NewestFile%" "D:\"
What I'd like to add are two extra pieces. First add some error handling to the existing script where it would first check the latest backup, but ensure its within the last 24 hours. If it is continue to run. If older than 24 hours, to generate an notification alert (i.e. separate batch file) if backup file is older than 24 hours. Second to generate similar notification, if there was an issue such as not being able to reach the remote share that holds the backup.
Appreciate replies.
It is not easy to check if a file was created or last modified within 24 hours. Date/time calculation is not a trivial task without conversion of the date/time strings to seconds since epoch which would make it possible to use a simple integer comparison.
There are solutions for file date comparison, see
Batch script to check when the newest file in a directory was created/modified
forfiles - Delete all files older than 1 day / 24hours using creation date?
You may use one of those solutions.
Much easier is to check if copy process worked:
copy /V "%DatabaseBackupPath%\WebServer\%NewestFile%" "D:\"
if errorlevel 1 goto CopyFail
goto :EOF
:CopyFail
echo.
echo Copying file "%DatabaseBackupPath%\WebServer\%NewestFile%" failed!
pause
Solution using WinRAR
My solution below is based on usage of Rar.exe, the console version of WinRAR as this compression tool has the feature to compress only files based on file dates. Therefore this solution is only helpful for you if you have installed WinRAR and bought a license of it.
The path of the program files folder of WinRAR must be set at top of the following batch file.
#echo off
SET DatabaseBackupPath=\\virtualserver1\Database Backups
SET WinRarFolder=C:\Program Files\WinRAR
cls
echo.
echo Restore WebServer Database
echo.
rem Find newest *.bak file in backup directory on server.
FOR /F "delims=" %%I IN ('DIR /B /O-D "%DatabaseBackupPath%\WebServer\*.bak"') DO (
SET NewestFile=%%I
goto BackupFound
)
cls
echo.
echo Restore WebServer Database
echo.
echo There is no *.bak file in "%DatabaseBackupPath%\WebServer\"
echo or the backup directory on server cannot be reached at all.
goto EndBatch
:BackupFound
echo Newest backup in "%DatabaseBackupPath%\WebServer"
echo is the file "%NewestFile%".
echo.
if exist "%TEMP%\ServerBackup.rar" del "%TEMP%\ServerBackup.rar"
"%WinRarFolder%\Rar.exe" a -cfg- -ep -inul -m0 -tn24h -y "%TEMP%\ServerBackup.rar" "%DatabaseBackupPath%\WebServer\%NewestFile%"
if errorlevel 1 goto OldBackup
"%WinRarFolder%\Rar.exe" e -cfg- -inul -y "%TEMP%\ServerBackup.rar" F:\Temp
if errorlevel 1 goto ExtractFailed
del "%TEMP%\ServerBackup.rar"
echo File "%NewestFile%" copied to D:\
goto EndBatch
:ExtractFailed
del "%TEMP%\ServerBackup.rar"
echo "Copying file "%NewestFile%" to D:\ failed.
goto EndBatch
:OldBackup
echo File "%NewestFile%" is older than 24 hours.
:EndBatch
set WinRarFolder=
SET DatabaseBackupPath=
SET NewestFile=
echo.
pause
Explanation:
The batch file first uses command DIR to get a list of *.bak files in the specified directory sorted according to last modification file date from newest to oldest.
With the FOR loop the name of the file name at top of the list (= newest file) is assigned to environment variable NewestFile.
The batch file outputs an error message if no *.bak file can be found in the specified directory, for example if the server cannot be reached at all at the moment with the permissions of the used user account.
But on success on finding a *.bak file in specified directory, the batch file informs the batch file user which file was found in which directory.
After making sure that the RAR archive to create next does not already exist in directory for temporary files, Rar.exe is used to create a RAR archive in directory for temporary files into which only the found file is stored without compression, but only if this file has a last modification date within 24 hours because of switch -tn24h.
For details on the switches used on Rar.exe see text file Rar.txt in program files directory of WinRAR.
Rar.exe exits with an return value greater 0 if there is any problem on creating the RAR archive. In this case the reason is most likely that the specified file is older than 24 hours which results now in an appropriate message written into the console window.
Rar.exe is on success on creating the RAR archive without compression used once more to extract the file to target directory.
An appropriate error mesage is shown in unlikely case that this fails. Otherwise the batch file outputs a success message and finishes with cleaning up environment table (not really needed if command prompt window closed next).
The temporarily used RAR archive is deleted in any case.

Batch script to delete older backup files in a folder created by date with the exception of the newest 5 files

I have a program that creates a backup every 30 minutes, but does not delete older files. I am looking to make a script that will run on task scheduler that will look in the folder that is created by the program. It creates folder by date as follows /year/month/day/*name of file.zip. I have done a little research and come up with
#ECHO OFF
for /f "usebackq delims== tokens= 2" %%i in ( WMIC OS GET localdatetime /format:value ) do set localTime=%%i
set "YYYY=%localTime:~0,4%"
set "M=%localTime:~4,1%"
set "MM=%localTime:~5,1%"
set "D=%localTime:~6,1%"
set "DD=%localTime:~7,1%"
if %M%==0 set M=
if %D%==0 set D=
cd /d "~%~dp0"
FOR /F "tokens=*" %%X IN ('dir .\%YYYY%\%M%%MM%\%D%%DD%\Backup-serversave-%YYYY%-%M%%MM%-%D%%DD%--*.zip /b /o:-d') DO set FILENAME=%%~X
rem FILENAME now contains the last element
if "%FILENAME%" neq "" DEL "%FILENAME%"
pause
This script looks in the folder by todays date and than should delete the file that is oldest in the folder. But every time I run it, all I get is a "cannot find file" and it tells me the exact file that it says it can't find. So I need a little help to make it work. It would be also great if there is any way to make it only delete after five files are in the folder. If anyone can help me that would be amazing.
Update. Got a good answer but need a little more help. If anyone out there can find a way to make it delete yesterdays folder at the change of the day that would be amazing I am looking all over and so far have found nothing.
You did already a quite good job on writing the batch file, but made some small mistakes.
Using in first line ECHO ON helped to find those mistakes.
The following lines with some corrections for the batch file work.
#ECHO OFF
for /f "usebackq delims== tokens=2" %%i in ( `WMIC OS GET localdatetime /format:value` ) do set localTime=%%i
set "YYYY=%localTime:~0,4%"
set "M=%localTime:~4,1%"
set "MM=%localTime:~5,1%"
set "D=%localTime:~6,1%"
set "DD=%localTime:~7,1%"
if %M%==0 set M=
if %D%==0 set D=
cd /d "%~dp0"
for /F "usebackq tokens=* skip=5" %%X in ( `dir .\%YYYY%\%M%%MM%\%D%%DD%\Backup-serversave-%YYYY%-%M%%MM%-%D%%DD%--*.zip /b /o:-d` ) do del .\%YYYY%\%M%%MM%\%D%%DD%\%%X
pause
No file was not deleted ever because you used command dir to find the ZIP files in a subdirectory. The name of a found file was referenced with %%X, but without the path to this file. As the batch file did not change into the directory on which dir searched for the ZIP files, command DEL could not find the file to delete in the current working directory.
The first 5 lines returned by command dir containing the 5 newest files according to last modification date are ignored by using skip=5. Therefore only files with todays date in name and older than the first 5 files in directory listing are deleted and the newest 5 files are kept.
There was also a mistake in line with command cd and some other small mistakes all found by using ECHO ON in first line.
Deleting the previous day folders is difficult if the batch file should find out automatically which folders should be deleted and which folders should be kept.
Here is a solution which makes this task simple and which can be appended to the other lines in my other answer for deleting the older backup files.
if exist .\%YYYY%\%M%%MM%\%D%%DD%\Backup-serversave-%YYYY%-%M%%MM%-%D%%DD%--*.zip (
md TempBackup
copy /V .\%YYYY%\%M%%MM%\%D%%DD%\*.zip TempBackup >nul
for /F "usebackq" %%D in ( `dir /AD /B 20*` ) do rd /S /Q %%D
md %YYYY%\%M%%MM%\%D%%DD%
copy /V TempBackup\*.zip %YYYY%\%M%%MM%\%D%%DD% >nul
rd /S /Q TempBackup
)
First, a check is made if there are already ZIP files today stored to prevent deleting older backups if not at least one backup is created today.
Next a directory with name TempBackup is created into which are copied the currently existing backup files created today.
Then a dir command is executed which lists only the names of the directories starting with 20. Currently this is just the directory 2014, but on 2015-01-01 it will be additionally 2015. All those directories are recursively and silently deleted.
Next the directory tree for today is recreated and the ZIP files are copied back into this directory.
Finally the temporary backup directory for the ZIP files is deleted, too.
I'm wondering now why using a directory with current year as name containing a directory with current month as name containing a directory with current day of month as name if the ZIP files itself contain also year, month and day in name, and all ZIP files except the last 5 ZIP files saved today should be deleted?
It would be perhaps easier to manage to create all ZIP files in same directory and delete all ZIP files except the last 5 according to last modification date.
On the other hand the management with directories make it possible to keep backups from several days like one month and just delete the backup of previous month from time to time either manually or automatically for example on 15th of every month.

Batch move files in folders to newly created folders

I want to move all files in some folders to a newly created folder in that same folder. For easier understanding, see the example below (the input is shown left, output is shown right):
C:\1\A\file1.tif C:\1\A\Named\file1.tif
file2.tif file2.tif
file3.tif ==> file3.tif
C:\1\B\file1.tif C:\1\B\Named\file1.tif
file2.tif file2.tif
file3.tif file3.tif
In the example above, I have only shown the first three files in every folder, but the total number may vary (usually there are 1000 files per folder). Also, I have only shown two folders (A and B), but the total number of folders may vary as well (usually about 10 folders). Finally, I have only shown the folder '1', but the number of these kind of folders may also vary (usually '1' through '10'). So I was looking to a script that could do these actions independent of the number of files or folders, and independent of the names of the folders/files (I chose '1', 'A' and 'file1.tif' only as examples).
The idea is that, now, I have to manually create empty folders (called 'Named' in the example above) in each folder ('A' and 'B' in the example above) where the files are. Then I have to manually move all the files into that newly created folder 'Named'. I have to do this for all folders (about 100). I can do this entire process manually if I had to do it only once, but the thing is that I have to do this process many times :-). So automating this would save a lot of time.
Does anyone know a script that can do this? Thanks a lot!
tested a little, this might work, in a command file
make a cmd file with these lines
for /r %%a in (*.*) do call :singlecopy %%a
goto :eof
:singlecopy
set src=%~p1
set dst=%~p1NAMED
set file=%~n1%~x1
rem replace NAMED in src with nothing
set srctst=%src:NAMED=%
rem if src and srctst are still the same, copy
if %srctst%==%src% robocopy %src% %dst% %file% /move /create
goto :eof
After thorough testing, this works great. However, as it is a lot of files, you may want to set up a little test environment, like in your example, to use this on first, before you use it on your actual data.
setlocal enabledelayedexpansion
cd C:\rootfolder
for /f "tokens=*" %%a in ('dir /s /b /a:d') do (
attrib "%%a\*.*" | find "File not found"
if !errorlevel!==1 (
if not exist "%%a\Named" md "%%a\Named"
xcopy "%%a\*.*" "%%a\Named"
del "%%a\*.*" /f /q
)
)

Resources