@ECHO OFF :: Check Windows version IF NOT "%OS%"=="Windows_NT" GOTO Syntax :: Only /DEBUG is valid as optional third argument IF NOT "%~3"=="" IF /I NOT "%~3"=="/C" IF /I NOT "%~3"=="/DEBUG" GOTO Syntax :: Two command line arguments are mandatory IF "%~1"=="" GOTO Syntax IF "%~2"=="" GOTO Syntax :: If the first argument is not a folder, it should end with \*.ext" IF NOT "%~x1"=="" ( ECHO "%~1"| FINDSTR /R /E /I /C:"\\\*\%~x1." >NUL || GOTO Syntax ) :: Initial check if (files and) folders exist IF NOT EXIST "%~1" GOTO Syntax IF NOT EXIST "%~2" GOTO Syntax SETLOCAL ENABLEDELAYEDEXPANSION :: Reset the variables we are going to use SET AllFiles1= SET AllFiles2= SET Dir1= SET Dir2= SET FileSpec1= SET FileSpec2= SET FileType=*.* SET NumFiles1=0 SET NumFiles2=0 SET TotalFiles1= SET TotalFiles2= SET TotalLine1= SET TotalLine2= SET TotalSize1= SET TotalSize2= SET Type= :: Check if FCIV is available, and if not, prompt to open its download page :: Code corrected in version 3.10, as the earlier versions failed to detect :: the absence of FCIV.EXE (thanks Ron Guggisberg for finding this bug) ECHO Checking availability of FCIV utility . . . SET Answer= FCIV.EXE -h >NUL 2>&1 IF ERRORLEVEL 1 ( ECHO This batch file requires Microsoft's File Checksum Integrity Verifier utility ECHO ^(FCIV.EXE^), available at http://support.microsoft.com/kb/841290 ECHO. SET Answer=N SET /P Answer=Do you want to open the download page now? [y/N] IF /I NOT "!Answer!"=="Y" GOTO Syntax CLS ECHO. ECHO You are about to open Microsoft's FCIV download page. ECHO Download and install FCIV.EXE and restart this batch file. ECHO. PAUSE START http://support.microsoft.com/kb/841290 ENDLOCAL GOTO:EOF ) IF NOT "%~nx1"=="" ( SET FileType=*%~x1 SET Type=-type *%~x1 ) :: Quick and dirty way to check if directories exist and handle trailing backslashes in one go PUSHD "%~dp1" IF ERRORLEVEL 1 ( ENDLOCAL GOTO Syntax ) ELSE ( CD | FIND "&" >NUL IF ERRORLEVEL 1 ( SET AllFiles1="!__CD__!*.*" SET Dir1="!CD!" SET FileSpec1="!__CD__!%FileType%" POPD ) ELSE ( POPD GOTO Syntax ) ) PUSHD "%~f2" IF ERRORLEVEL 1 ( ENDLOCAL GOTO Syntax ) ELSE ( CD | FIND "&" >NUL IF ERRORLEVEL 1 ( SET AllFiles2="!__CD__!*.*" SET Dir2="!CD!" SET FileSpec2="!__CD__!%FileType%" POPD ) ELSE ( POPD GOTO Syntax ) ) :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: Part I: just check the total file size :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: ECHO Checking number of files and total file size for both directories . . . :: Get number of matching files and total file size for first directory FOR /F %%A IN ('DIR "%~1" /S ^| FIND /C "("') DO SET /A TotalLine1 = %%A - 1 FOR /F "tokens=2,4" %%A IN ('DIR "%~1" /-C /S ^| FIND "(" ^| FIND /N "(" ^| FIND "[%TotalLine1%]"') DO ( SET TotalFiles1=%%A SET TotalSize1=%%B ) :: Get number of matching files and total file size for second directory FOR /F %%A IN ('DIR "%FileSpec2%" /S ^| FIND /C "("') DO SET /A TotalLine2 = %%A - 1 FOR /F "tokens=2,4" %%A IN ('DIR %FileSpec2% /-C /S ^| FIND "(" ^| FIND /N "(" ^| FIND "[%TotalLine2%]"') DO ( SET TotalFiles2=%%A SET TotalSize2=%%B ) :: Abort if the NUMBER of matching files does not match IF NOT %TotalFiles1% EQU %TotalFiles2% ( ECHO Number of files is different: ECHO %TotalFiles1% files in %Dir1% ECHO %TotalFiles2% files in %Dir2% ECHO. ECHO Aborting comparison . . . ECHO. ENDLOCAL EXIT /B 2 ) :: Warn if the TOTAL SIZE of the files does not match IF NOT %TotalSize1% EQU %TotalSize2% ( ECHO Total file size is different: ECHO %TotalSize1% bytes in %Dir1% ECHO %TotalSize2% bytes in %Dir2% ECHO. IF /I "%~3"=="/C" ( ECHO Continuing comparison . . . ECHO. ) ELSE ( ECHO Aborting comparison . . . ECHO. ENDLOCAL EXIT /B 2 ) ) :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: Part II: compare file timestamps :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: ECHO Comparing files' timestamps for both directories . . . :: XCOPY /D /Y /L just checks what is newer without actually copying anything FOR /F %%A IN ('XCOPY %FileSpec1% %AllFiles2% /S /D /H /R /Y /L 2^>NUL') DO SET NumFiles1=%%A FOR /F %%A IN ('XCOPY %FileSpec2% %AllFiles1% /S /D /H /R /Y /L 2^>NUL') DO SET NumFiles2=%%A IF %NumFiles1% EQU 0 IF %NumFiles2% EQU 0 ( REM Do nothing if all timestamps match ) ELSE ( IF %NumFiles2% GTR 0 ECHO %NumFiles2% files in %Dir1% are older IF %NumFiles1% GTR 0 ECHO %NumFiles1% files in %Dir2% are older ) :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: Part III: compare checksums per file :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: Go to the TEMP directory to create the required temporary files here PUSHD "%Temp%" :: Remove previous versions of the temporary files FOR %%A IN (~Dir1.md5 ~Dir1.tmp ~Dir2.md5 ~Dir2.tmp fciv.err) DO IF EXIST %%A DEL %%A ECHO Scanning %Dir1% and subdirectories . . . FCIV.EXE %Dir1% -md5 -r %Type% | FINDSTR /R /B /I /C:"[0-9a-f][0-9a-f][0-9a-f]* [a-z\\][:\\]" | SORT /+33 > ~Dir1.md5 ECHO Scanning %Dir2% and subdirectories . . . FCIV.EXE %Dir2% -md5 -r %Type% | FINDSTR /R /B /I /C:"[0-9a-f][0-9a-f][0-9a-f]* [a-z\\][:\\]" | SORT /+33 > ~Dir2.md5 :: Abort if no files were found in either directory (i.e. if either checksums list is 0 bytes) FOR %%A IN (~Dir1.tmp) DO SET Size1=%%~zA FOR %%A IN (~Dir2.tmp) DO SET Size2=%%~zA IF %Size1%0 NEQ 0 IF %Size2%0 NEQ 0 ( REM Do nothing if both files are larger than 0 bytes ) ELSE ( IF %Size1%0 EQU 0 ECHO No files found in %Dir1% IF %Size2%0 EQU 0 ECHO No files found in %Dir2% ENDLOCAL EXIT /B 3 ) TYPE NUL > ~Dir1.tmp TYPE NUL > ~Dir2.tmp IF /I "%~3"=="/DEBUG" ( SET Count=0 ECHO Removing specified path from ~Dir1.md5 ) FOR /F "tokens=*" %%A IN (~Dir1.md5) DO ( IF /I "%~3"=="/DEBUG" SET /A Count += 1 SET Line=%%A IF /I "%~3"=="/DEBUG" ECHO [!Count!]!Line! REM The following line of code would be vulnerable to a code insertion attack REM (http://www.thesecurityfactory.be/command-injection-windows.html) REM but we checked for ampersands earlier FOR %%B IN (%Dir1%) DO SET Line=!Line:%%~B\=! IF /I "%~3"=="/DEBUG" ECHO [!Count!]!Line! >> ~Dir1.tmp ECHO.!Line! ) IF /I "%~3"=="/DEBUG" ( SET Count=0 ECHO Removing specified path from ~Dir2.md5 ) FOR /F "tokens=*" %%A IN (~Dir2.md5) DO ( IF /I "%~3"=="/DEBUG" SET /A Count += 1 SET Line=%%A IF /I "%~3"=="/DEBUG" ECHO [!Count!]!Line! REM The following line of code would be vulnerable to a code insertion attack REM (http://www.thesecurityfactory.be/command-injection-windows.html) REM but we checked for ampersands earlier FOR %%B IN (%Dir2%) DO SET Line=!Line:%%~B\=! IF /I "%~3"=="/DEBUG" ECHO [!Count!]!Line! >> ~Dir2.tmp ECHO.!Line! ) ECHO Comparing checksums . . . SET Error=0 FC.EXE /C ~Dir1.tmp ~Dir2.tmp | MORE +1 || SET Error=2 :: Remove trash IF /I NOT "%~3"=="/DEBUG" ( DEL ~Dir1.md5 DEL ~Dir1.tmp DEL ~Dir2.md5 DEL ~Dir2.tmp DEL fciv.err ) POPD :: Exit with error level 2 in case of mismatch ENDLOCAL & EXIT /B %Error% :Syntax IF /I "%~3"=="/DEBUG" SET Dir1 IF /I "%~3"=="/DEBUG" SET Dir2 IF /I "%~3"=="/DEBUG" SET Type ECHO. ECHO DirComp.bat, Version 3.30 for Windows NT ECHO Compare the contents of 2 directories ECHO. ECHO Usage: DIRCOMP "d:\path\*.ext" "e:\otherfolder" [/C] ECHO or: DIRCOMP "d:\path\" "e:\otherfolder" [/C] ECHO. ECHO Where: /C Continues comparison even if total file size does not match ECHO. ECHO Notes: Note the trailing backslash if the first argument is a folder. ECHO Compares number of files, file size, timestamp and contents of files. ECHO Requires Microsoft's File Checksum Integrity Verifier utility (FCIV), ECHO available at http://support.microsoft.com/kb/841290 ECHO If FCIV is not available, you will be prompted to download it. ECHO Uses FC to compare FCIV's checksum listings; so if differences are ECHO found, the lines immediately preceeding and following a line that ECHO differs are displayed as well. ECHO Ampersands are not allowed in the folder paths. ECHO. ECHO Written by Rob van der Woude ECHO http://www.robvanderwoude.com IF "%OS%"=="Windows_NT" EXIT /B 1