Two-way folder sync with robocopy - batch-file

So I've been trying to write a batch file which will sync my local Google Drive folder with my flash drive when I run it. Since robocopy is a one-way process, I set up my code so it asks you whether you want to either sync TO Google Drive or FROM Google Drive. This is so that regardless of which of the two locations I make or edit something, I can always sync the newest version onto both locations.
Before anything happens, the code also verifies that it's plugged into my computer and not someone else's by checking its name.
This is what my code looks like right now:
#echo off
If "%computername%"=="JAKE-PC" (
color 02
set /P c=Sync TO or FROM Google Drive[T/F]?
:choice
if /I "%c%" EQU "T" goto :to
if /I "%c%" EQU "F" goto :from
goto :choice
:to
echo Syncing to Google Drive...
robocopy ".\Google Drive\ " "C:\Users\Jake\Google Drive\ " * /mir /xo
goto :done
:from
echo Syncing from Google Drive...
robocopy "C:\Users\Jake\Google Drive\ " ".\Google Drive\ " * /mir /xo
goto :done
:done
echo Sync Complete.
pause
)
If NOT "%computername%"=="JAKE-PC" (
color 04
echo Not Jake's PC!
pause
)
It seems to work okay. If I make a change on the flash drive, I run the batch file and type T which will sync my changes to Google Drive. If I make a change on Google Drive, I type F which will sync changes from Google Drive.
There's only one flaw however, and that's if each location has new content to sync. If I create "a.txt" on my flash drive and "b.txt" on Google Drive, and then if I:
-sync TO Google Drive, a.txt is copied to Google Drive from my flash drive but b.txt is gone from both.
-sync FROM Google Drive, b.txt is copied to my flash drive from Google Drive but a.txt is gone from both.
So this causes the problem of files being lost forever if there's new content on both locations. Is there any way to fix this? I just need a two-way method of syncing both locations without the possibility of losing files/folders from one of them. Maybe even without robocopy.

As per ROBOCOPY /? (or ROBOCOPY.exe doc), /MIR option forces implicite /PURGE:
/MIR : MIRror a directory tree - equivalent to /PURGE plus all subfolders (/E)
/PURGE : Delete destination files/folders that no longer exist in source.
/XO : eXclude Older - if destination file exists and is the same date or newer
than the source - don’t bother to overwrite it.
/E : Copy Subfolders, including Empty Subfolders.
Use /E instead of /MIR option and perform copy in both ways unattended:
#echo off
If "%computername%"=="JAKE-PC" goto :sync
color 04
echo Not Jake's PC!
goto :done
:sync
color 02
:to
echo Syncing to Google Drive...
robocopy ".\Google Drive\\" "C:\Users\Jake\Google Drive\\" * /E /XO
:from
echo Syncing from Google Drive...
robocopy "C:\Users\Jake\Google Drive\\" ".\Google Drive\\" * /E /XO
echo Sync Complete.
:done
pause
Or something similar to next code snippet (keeping set /P user's interpelation):
#echo off
SETLOCAL EnableExtensions
If "%computername%"=="JAKE-PC" goto :sync
color 04
echo Not Jake's PC!
goto :done
:to
echo Syncing to Google Drive...
robocopy ".\Google Drive\\" "C:\Users\Jake\Google Drive\\" * /E /XO
goto :eof
:from
echo Syncing from Google Drive...
robocopy "C:\Users\Jake\Google Drive\\" ".\Google Drive\\" * /E /XO
goto :eof
:sync
color 02
set /P c=Sync TO or FROM Google Drive or BOTH or NOTHING [T/F/B/N]?
if /I "%c%" EQU "T" ( call :to
goto :done
)
if /I "%c%" EQU "F" ( call :from
goto :done
)
if /I "%c%" EQU "B" (
call :to
call :from
goto :done
)
if /I not "%c%" EQU "N" goto :sync
echo No Sync
:done
echo Sync Complete.
pause
Note that if Command Extensions are disabled GOTO will no longer recognise the :EOF label (use exit /B instead of goto :EOF in the case). Although Command Extensions are enabled by default, we can't presume in it. That's why I use SETLOCAL EnableExtensions as a matter of general principle.
If Command Extensions are enabled GOTO changes as follows:
GOTO command now accepts a target label of :EOF which transfers
control to the end of the current batch script file. This is an easy
way to exit a batch script file without defining a label.
Type CALL /? for a description of extensions to the CALL command
that make this feature useful.
Also note that Using GOTO within parentheses - including FOR and IF commands - will break their context.

/XX switch to eXclude eXtra files and directories should do what you need as per this answer:
An "extra" file is present in destination but not source; excluding extras will prevent any deletions from the destination.

Related

Version backups and restoring latest backup with robocopy

I am trying to write a batch file and use the robocopy command to backup a directory. However, I need multiple backups to be kept. Let's say I have a directory "A" in "C:\Source Path" and a backup location "C:\Backup Path".
I need the following to happen:
During the backup, If "C:\Backup Path\A Dir" already exists then the copy result should make "C:\Backup Path\A Dir2"; or a similar numbering system.
During the restore, the highest-numbered backup directory in "C:\Backup Path" should replace "C:\Original Path\A Dir"
My current script does not do any versioning and looks like below:
#echo off
set originalPath="C:\Original Path\A"
set backupPath="C:\Backup Path\A"
:L1
echo 1. Backup save files
echo 2. Restore save files
echo 3. Exit
set /p choice=Select an option:
if %choice% equ 1 goto :BACKUP
if %choice% equ 2 goto :RESTORE
if %choice% equ 3 goto :EOF
goto :L1
:BACKUP
robocopy %originalPath% %backupPath% /E
goto :L1
:RESTORE
robocopy %backupPath% %originalPath% /E
goto :L1
:EOF
Is such an operation possible using robocopy alone?

How to rename a folder on flash drive using a batch file

I am trying to make a batch file that will back up the contents of a folder onto my flash drive and rename the previous folder on the flash drive. Here is the code.
#echo off
echo Are you sure you want to erase the previous backup file? (Y,N)
set /p ans=
if %ans%==Y goto Backup
goto Exit
:Backup
rd "E:\Batch\BFiles Backup" /s
ren "E:\Batch\BFiles" "BFiles Backup"
:Copy
mkdir E:\Batch\BFiles
xcopy C:\Users\Habib\Documents\BFiles /E /Y E:\Batch\BFiles
echo Files have successfully been copied!
pause
:Exit
exit
When I run the batch file, it copies the files but doesn't rename the already existing folder because "Access is denied". I have tried running it in the administrator version of Cmd, but it still didn't work. My user is an administrator also, so i don't know why access has been denied.
First thing, remove your #ECHO OFF until you are done debugging your code..
Add PAUSE statements so you can stop and see what is going on..
Let's re-format your code a bit..
ECHO Are you sure you want to erase the previous backup file? (Y,N)
set /p ans=
if %ans%==Y goto Backup
PAUSE
goto Exit
:Backup
PAUSE
IF EXIST "E:\Batch\BFiles Backup\." rd "E:\Batch\BFiles Backup" /s
PAUSE
IF NOT EXIST "E:\Batch\BFiles Backup\." ren "E:\Batch\BFiles" "BFiles Backup"
PAUSE
:Copy
IF NOT EXIST "E:\Batch\BFiles\." mkdir E:\Batch\BFiles
PAUSE
xcopy C:\Users\Habib\Documents\BFiles /E /Y E:\Batch\BFiles
IF errorlevel 0 echo Files have successfully been copied!
pause
:Exit
exit
Then, when things start looking correct, remove the PAUSE statements one by one...
Hope this helps!

Two For Loops Using %1 - Delayed Expansion?

My working batch file scans a long list of remote servers, copies anything there to a local server, checks the log file for a keyword, and if the keyword is found sends an email. I noticed it is always sending emails, even with a blank log file.
I discovered both FOR loops are using the %1 variable for their output - as seen in ECHO %1 and each line of the called :servermove. For lack of a better explanation it is not resetting %1 to null between loops.
I reviewed almost a dozen SO posts and am somewhat confident using SETLOCAL ENABLEDELAYEDEXPANSION would resolve this. That is where my understanding ends and I am unsuccessful thus far.
Here is the relevant code:
SET DATE=%date:~4,2%-%date:~7,2%-%date:~10,4%
SET HH=%time:~0,2%
SET MN=%time:~3,2%
SET TSTAMP=Time Run is %HH%%MN%
SET DATETIME=%DATE% at %HH%%MN%
SET LOGFILE="\\nt980a3\CreditFileImagesTransmission\LogFiles\%DATETIME%-File Move Log.txt"
SET MailDst=
SET MailSrc=
SET MailSrcName=Center to LDSD File Mover
SET OKMailSub=A Branch Has Sent You Some Files
ECHO %DATETIME% > %LOGFILE%
ECHO. >> %LOGFILE%
FOR /F "tokens=1" %%A IN (%~dp0SourceServers.txt) DO CALL :ServerMove %%A
:cleanuplogs
PUSHD "\\nt980a3\CreditFileImagesTransmission\LogFiles" &&(
FORFILES /S /M *.txt /D -45 /C "CMD /C DEL /Q #path"
) & POPD
:mailtest
FOR /F "tokens=*" %%A IN (%LOGFILE%) DO CALL :searchlog "%%A"
:searchlog
ECHO %1 | find "\\nt">NUL
IF NOT ERRORLEVEL 1 GOTO successmail
GOTO exit
:successmail
IF EXIST %temp%\to.txt DEL %temp%\to.txt
FOR %%a IN (%MailDst%) DO ECHO %%a>>%temp%\to.txt
"%~dp0sendmail.exe" /TO=%temp%\to.txt /FROM=%MailSrcName% ^<%MailSrc%^> /REF=%OKMailSub% /MESSAGE=%LOGFILE% /HOST=
:exit
EXIT
:ServerMove
DIR /S /B \\%1\CreditFileImagesTransmission\*.* >> %LOGFILE%
XCOPY /E /C /I /Y "\\%1\CreditFileImagesTransmission\*.*" "\\nt980a3\CreditFileImagesTransmission\%DATE%\%HH%%MN%\"
FOR /D %%P IN ("\\%1\CreditFileImagesTransmission\*.*") DO RMDIR "%%P" /Q /S
DEL /Q /S "\\%1\CreditFileImagesTransmission\*.*"
I tried changing :mailtest to use %%B in both instances but that also fails. Placing SETLOCAL ENABLEDELAYEDEXPANSION and its counterpart ENDLOCAL before one or the other loop and changing the %%A to !A! does not work either.
Would someone kindly point out the error in my ways and offer suggestions or resources that will help me resolve this?
%1 is the first parameter provided to the procedure - either from the command-line (in the main procedure) or the parameter following the procedure name in call :procedurename parameter1.
In your case, %1 to :servermove is an entry from SourceServers.txt and %1 to :searchlog is each line from %LOGFILE%.
Since you've censored your batch, what you've posted makes little sense. For instance, the :searchlogs routine will take the first line from %LOGFILE% and go to successmail or cleanlogs depending on whether that first line contains the target string \\nt. What it does from there, we can't tell.
We're faced with an XY problem - trying to fix a solution, not a problem.
First problem: Don't use date as a user-variable. It's a "magic variable" which contains the date but it's overridden by a specific set statement.
Having run :servermove for each entry in SourceServers.txt, you are
- accumulating a directory list from \CreditFileImagesTransmission\*.* on that server.
- copying those files to server nt980a3 with a date/timestamp but not including the source-servername so any duplicate name anywhere will overwrite an earlier version. I suggest you include %1 into your destination-name.
- deleting subdirectories
- deleting files.
I'd suggest you simply remove the directory \\%1\CreditFileImagesTransmission\, then re-create it.
I'd also suggest that you add an extra line
goto :eof
after the del /q /s... line. This will cause execution to be transferred to the end-of-file (the colon in :eof is required) and may seem superfluous, but it ensures that the routine has a defined endpoint - if you add a further routine, there is no way the :servermove routine will continue into your new code.
After each server has been processed, you proceed to the :cleanuplogs routine, which I presume deletes logs older than 45 days.
Your next statement is a real problem. What it will do is grab the very first line of the logfile (which contains "%DATE% at %HH%%MN%" with the date resolved as you've set at the start and it then processes this line in :searchlog; there is no \\nt in this line, so errorlevel is set to 1, and the batch proceeds to :EXIT (not a good label in my view, since it's a keyword); executes an exitand should terminate the batch.
This appears not to be what it is actually doing, and I'm at a loss to explain why.
I'd suggest changing
:mailtest
FOR /F "tokens=*" %%A IN (%LOGFILE%) DO CALL :searchlog "%%A"
:searchlog
ECHO %1 | find "\\nt">NUL
IF NOT ERRORLEVEL 1 GOTO successmail
GOTO exit
to
:mailtest
find "\\nt" %LOGFILE%>NUL
IF NOT ERRORLEVEL 1 GOTO successmail
:failmail
echo "\\nt" was found in the log
pause
GOTO exit
but I can't test that...
:mailtest
FOR /F "tokens=*" %%A IN (%LOGFILE%) DO CALL :searchlog "%%A"
You are missing a GOTO :EOF or similar goto here because it will drop through to the routine below once the above is finished.
:searchlog
ECHO %1 | find "\\nt">NUL
IF NOT ERRORLEVEL 1 GOTO successmail
GOTO exit
I feel you can not carry the %1 of first for loop to others. Try to transfer that to another variable like below.
:ServerMove
set servername=%1
DIR /S /B \\%servername%\CreditFileImagesTransmission\*.* >> %LOGFILE%
XCOPY /E /C /I /Y "\\%servername%\CreditFileImagesTransmission\*.*" "\\nt980a3\CreditFileImagesTransmission\%DATE%\%HH%%MN%\"
FOR /D %%P IN ("\\%servername%\CreditFileImagesTransmission\*.*") DO RMDIR "%%P" /Q /S
DEL /Q /S "\\%servername%\CreditFileImagesTransmission\*.*"
Cheers, G

Tracking history using a batch file

How could i make a batch file that would track and keep internet history (from google chrome) and after i run CCleaner and cleared history through google chrome, the batch file would have already created a text file and have the history still on it? I need this to be a batch file that would create and update a text file about this.
Batch code begins here:
#echo off
echo Welcome to the history tracker!
echo Turn on? [1]-Yes [2]-No
set /P variable=Enter choice:
IF "%variable%"=="1" (GOTO start)
IF "%variable%"=="2" (GOTO end)
:end
echo.
:start
REM I don't know what else to do
#echo off
:top
for /f "delims=: tokens=2" %%i in ('ipconfig /displaydns^|find "Record Name"') do (find "%%i" /i history.txt >nul 2>&1|| echo %%i >>history.txt)
timeout /nobreak 5 >nul 2>&1
sort history.txt /o history.txt
goto top
this will give you a list of all the SITES visited. not the individual pages on the sites, but the sites.

How to rename a folder with a number (ie Folder1, Folder2, etc....)

I'm messing around with dos and batch files for the first time and I am trying to make a "program" to backup my Minecraft saves (lol). I want the program to rename the current save (in my MinecraftSaves folder) as "Backup#" before the next one is copied into the MinecraftSaves folder. Its simple enough to rename it, but I want it to save multiple folders, each incrementing a number at the end of the folder name (ie Backup1, Backup2, Backup3). Any help? I've looked all over but I couldn't find something exactly to fit my needs.
#Echo off
title Minecraft Backup
echo.
echo.
echo.
echo Do you want to backup you're Single Player World?
echo.
SET /P ANSWER=Do you want to continue (Y/N)?
if /i {%ANSWER%}=={y} (goto :yes)
if /i {%ANSWER%}=={yes} (goto :yes)
if /i {%ANSWER%}=={n} (goto :no)
if /i {%ANSWER%}=={no} (goto :no)
:no
PING 1.1.1.1 -n 1 -w 1000 >NUL
exit
:yes
ren C:\Users\Josh\Desktop\MinecraftSaves\SinglePlayer Backup
xcopy C:\Users\Josh\AppData\Roaming\.minecraft\saves C:\Users\Josh\Desktop\MinecraftSaves /-y /e /h
Thats what I have so far. I want to change the following to rename the SinglePlayer folder as backup1, and the next time I run it have it rename the new SinglePlayer folder as backup2. I'm trying to explain this as best I can. Maybe theres a simpler way to do this. I just need it to make backups with numbers on the backup folders. Hope thats clear enough.
Excuse me. I think I did not really understood your question. However, the following Batch file take an existent folder named CurrentSave and rename it to Backup-# adding 1 to the last Backup-# existent folder. The dash in the folder name make things easier.
#echo off
for /D %%d in (Backup-*) do set lastfolder=%%d
for /F "tokens=2 delims=-" %%n in ("%lastfolder%") do set /A nextnumber=%%n+1
move CurrentSave Backup-%nextnumber%
If this is not what you want, give us more details so we may help you.
EDIT
OK. The code I posted above works right, just a couple details are needed. Below is the code you must insert from :yes label on:
:yes
set lastfolder=Backup-0
for /D %%d in (C:\Users\Josh\Desktop\MinecraftSaves\Backup-*) do set lastfolder=%%~Nd
for /F "tokens=2 delims=-" %%n in ("%lastfolder%") do set /A nextnumber=%%n+1
ren C:\Users\Josh\Desktop\MinecraftSaves\SinglePlayer Backup-%nextnumber%
xcopy C:\Users\Josh\AppData\Roaming\.minecraft\saves C:\Users\Josh\Desktop\MinecraftSaves /-y /e /h
May I suggest you another modification?
SET /P ANSWER=Do you want to continue (Y/N)?
for %%a in (y yes) do if /i "%ANSWER%"=="%%a" goto yes
:no
Please let me know if you solved your problem.

Resources