批量验证MD5哈希值?

时间:2017-02-10 23:29:48

标签: batch-file md5

我正在编写批处理文件,我需要它来验证文件的MD5哈希值,然后再继续编写脚本。例如:

@echo off
if MD5 equ 79054025255fb1a26e4bc422aef54eb4 (
      echo MD5 identical!
) else (
      echo MD5 does not match.
)

谢谢!

2 个答案:

答案 0 :(得分:4)

标准Windows实用程序CERTUTIL可用于生成MD5(和其他)哈希值。

例如:

certutil -hashfile yourFile MD5

但是,输出(Windows 10之前的版本)不会被格式化为连续十六进制数字的单个字符串。

npocmaka在其批处理实用程序中使用CERTUTIL生成单个MD5字符串。

以类似的方式,我还使用了CERTUTIL和我的实用程序:HASHSUM.BAT - 一个unix实用程序的批处理文件模拟,如md5sum,shasum等。

HASHSUM.BAT不仅可以为单个文件计算MD5,还可以方便地使用它。

例如:

echo 79054025255fb1a26e4bc422aef54eb4  yourFileName | hashsum /c /ns
REM - There must be exactly two spaces between the MD5 hash and the filename

将产生类似

的输出
----------  <stdin>  ----------
OK: yourFileName

----------  <stdin>  ----------
*FAILED: yourFileName

或者您可以完全控制输出

echo 79054025255fb1a26e4bc422aef54eb4  yourFileName | hashsum /c /q && (
  echo MD5 identical!
) || (
  echo MD5 does not match.
)

或者,如果您真的想要,您可以捕获MD5值并自行进行比较:

for /f %%N in ('hashsum /a md5 yourFileName') do set "MD5=%%N"
if %MD5% equ 79054025255fb1a26e4bc422aef54eb4 (
  echo MD5 identical!
) else (
  echo MD5 does not match.
)

我发布了HASHSUM.BAT当前版本1.4的代码,但我不承诺保持此代码的最新状态。我建议您从DOSTIPS site where I originally posted it获取代码。在那里,您还可以看到有关所有HASHSUM.BAT功能的更全面的讨论,以及更多使用示例。

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment
@goto :Batch

::::HASHNUM.BAT history
::::
::::  v1.4 2016-12-26 - Convert /A value to upper case because some Windows
::::                    versions are case sensitive. Also improve JScript file
::::                    read performance by reading 1000000 bytes instead of 1.
::::  v1.3 2016-12-17 - Bug fixes: Eliminate unwanted \r\n from temp file by
::::                    reading stdin with JScript instead of FINDSTR.
::::                    Fix help to ignore history.
::::  v1.2 2016-12-07 - Bug fixes: Exclude FORFILES directories and
::::                    correct setlocal/endlocal management in :getOptions
::::  v1.1 2016-12-06 - New /V option, and minor bug fixes.
::::  v1.0 2016-12-05 - Original release
:::
:::HASHSUM  [/Option [Value]]... [File]...
:::
:::  Print or check file hashes using any of the following standard
:::  hash algorithms: MD5, SHA1, SHA256, SHA384, or SHA512.
:::
:::  HASHSUM always does a binary read - \r\n is never converted to \n.
:::
:::  In the absence of /C, HASHSUM computes the hash for each File, and writes
:::  a manifest of the results. Each line of output consists of the hash value,
:::  followed by a space and an asterisk, followed by the File name. The default
:::  hash alogrithm is sha256. File may include wildcards, but must not contain
:::  any path information.
:::
:::  If File is not given, then read from standard input and write the hash
:::  value only, without the trailing space, asterisk, or file name.
:::
:::  Options:
:::
:::    /? - Prints this help information to standard output.
:::
:::    /?? - Prints paged help using MORE.
:::
:::    /V - Prints the HASHNUM.BAT version.
:::
:::    /A Algorithm
:::
:::         Specifies one of the following hash algorithms:
:::         MD5, SHA1, SHA256, SHA384, SHA512
:::
:::    /P RootPath
:::
:::         Specifies the root path for operations.
:::         The default is the current directory.
:::
:::    /S - Recurse into all Subdirectories. The relative path from the root
:::         is included in the file name output.
:::         This option is ignored if used with /C.
:::
:::    /I - Include the RootPath in the file name output.
:::         This option is ignored if used with /C.
:::
:::    /T - Writes a space before each file name, rather than an
:::         asterisk. However, files are still read in binary mode.
:::         This option is ignored if used with /C.
:::
:::    /C - Read hash values and file names from File (the manifest), and verify
:::         that local files match. File may include path information with /C.
:::
:::         If File is not given, then read hash and file names from standard
:::         input. Each line of input must have a hash, followed by two spaces,
:::         or a space and an asterisk, followed by a file name.
:::
:::         If /A is not specified, then the algorithm is determined by the
:::         File extension. If the extension is not a valid algorithm, then
:::         the algorithm is derived based on the length of the first hash
:::         within File.
:::
:::         Returns ERRORLEVEL 1 if any manifest File is not found or is invalid,
:::         or if any local file is missing or does not match the hash value in
:::         the manifest. If all files are found and match, then returns 0.
:::
:::    /NE - (No Errors) Suppresses error messages when using /C.
:::
:::    /NM - (No Matches) Suppresses listing of matching files when using /C.
:::
:::    /NS - (No Summary) Suppresses summary information when using /C.
:::
:::    /Q  - (Quiet) Suppresses all output when using /C.
:::
:::HASHSUM.BAT version 1.4 was written by Dave Benham
:::maintained at http://www.dostips.com/forum/viewtopic.php?f=3&t=7592

============= :Batch portion ===========
@echo off
setlocal disableDelayedExpansion

:: Define options
set "options= /A:"" /C: /I: /P:"" /S: /T: /?: /??: /NE: /NM: /NS: /Q: /V: "

:: Set default option values
for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B"
set "/?="

:getOptions
if not "%~1"=="" (
  set "test=%~1"
  setlocal enableDelayedExpansion
  if "!test:~0,1!" neq "/" endlocal & goto :endOptions
  set "test=!options:*%~1:=! "
  if "!test!"=="!options! " (
      endlocal
      >&2 echo Invalid option %~1
      exit /b 1
  ) else if "!test:~0,1!"==" " (
      endlocal
      set "%~1=1"
  ) else (
      endlocal
      set "%~1=%~2"
      shift /1
  )
  shift /1
  goto :getOptions
)
:endOptions

:: Display paged help
if defined /?? (
  (for /f "delims=: tokens=*" %%A in ('findstr "^:::[^:] ^:::$" "%~f0"') do @echo(%%A)|more /e
  exit /b 0
) 2>nul

:: Display help
if defined /? (
  for /f "delims=: tokens=*" %%A in ('findstr "^:::[^:] ^:::$" "%~f0"') do echo(%%A
  exit /b 0
)

:: Display version
if defined /v (
  for /f "delims=: tokens=*" %%A in ('findstr /ric:"^:::%~nx0 version" "%~f0"') do echo(%%A
  exit /b 0
)

:: If no file specified, then read stdin and write to a temp file
set "tempFile="
if "%~1" equ "" set "tempFile=%~nx0.%time::=_%.%random%.tmp"
if defined tempFile cscript //nologo //E:JScript "%~f0" "%temp%\%tempFile%"

if defined /P cd /d "%/P%" || exit /b 1
if defined /C goto :check

:generate
if defined tempFile cd /d "%temp%"
if not defined /A set "/A=sha256"
if defined /S set "/S=/s"
if defined /T (set "/T= ") else set "/T=*"
call :defineEmpty
if not defined /P goto :generateLoop
if not defined /I goto :generateLoop
if "%/P:~-1%" equ "\" (set "/I=%/P:\=/%") else set "/I=%/P:\=/%/"
set "rtn=0"

:generateLoop
(
  for /f "delims=" %%F in (
    'forfiles %/s% /m "%tempFile%%~1" /c "cmd /c if @isdir==FALSE echo @relpath" 2^>nul'
  ) do for /f "delims=" %%A in (
    'certutil.exe -hashfile %%F %/A% ^| find /v ":" ^|^| if %%~zF gtr 0 (echo X^) else echo %empty%'
  ) do (
    set "file=%%~F"
    set "hash=%%A"
    setlocal enableDelayedExpansion
    set "file=!file:~2!"
    if defined tempFile (
      if !hash! equ X (
        set "rtn=1"
        echo ERROR
      ) else echo !hash: =!
    ) else (
      if !hash! equ X (
        set "rtn=1"
        echo ERROR: !/I!!file!
      ) else echo !hash: =! !/T!!/I!!file:\=/!
    )
    endlocal
  )
) || (
  set "rtn=1"
  echo MISSING: %/T%%1
)
shift /1
if "%~1" neq "" goto :generateLoop
if defined tempFile del "%tempFile%"
exit /b %rtn%

:check
if defined /Q for %%V in (/NE /NM /NS) do set "%%V=1"
set /a manifestCnt=missingManifestCnt=invalidCnt=missingCnt=failCnt=okCnt=0
:checkLoop
set "alogorithm=%/A%"
if defined tempFile set "tempFile=%temp%\%tempFile%"
for %%F in ("%tempFile%%~1") do call :checkFile "%%~F"
if defined tempFile del "%tempFile%"
shift /1
if "%~1" neq "" goto :checkLoop

if not defined /NS (
  echo ==========  SUMMARY  ==========
  echo Total manifests   = %manifestCnt%
  echo Matched files     = %okCnt%
  echo(
  if %missingManifestCnt% gtr 0 echo Missing manifests = %missingManifestCnt%
  if %invalidCnt% gtr 0         echo Invalid manifests = %invalidCnt%
  if %missingCnt% gtr 0         echo Missing files     = %missingCnt%
  if %failCnt% gtr 0            echo Failed files      = %failCnt%
)
set /a "1/(missingManifestCnt+invalidCnt+missingCnt+failCnt)" 2>nul && (
  echo(
  exit /b 1
)
exit /b 0

:checkFile
set /a manifestCnt+=1
if not defined /Q if defined tempfile (echo ----------  ^<stdin^>  ----------) else echo ----------  %1  ----------
if not defined algorithm set "/A="
set "src=%~1"
if not defined /A echo *.md5*.sha1*.sha256*.sha384*.sha512*|find /i "*%~x1*" >nul && for /f "delims=." %%A in ("%~x1") do set "/A=%%A"
findstr /virc:"^[0123456789abcdef][0123456789abcdef]* [ *][^ *?|<>]" %1 >nul 2>nul && (
  if not defined /NE if defined tempFile (echo *INVALID: ^<stdin^>) else echo *INVALID: %1
  set /a invalidCnt+=1
  exit /b
)
(
  for /f "usebackq tokens=1* delims=* " %%A in (%1) do (
    set "hash0=%%A"
    set "file=%%B"
    if defined /A (call :defineEmpty) else call :determineFormat
    setlocal enableDelayedExpansion
    set "file=!file:/=\!"
    for /f "tokens=1* delims=" %%C in (
      'certutil.exe -hashfile "!file!" !/A! ^| find /v ":" ^|^| if exist "!file!" (echo !empty!^) else echo X'
    ) do set "hash=%%C"
    if /i "!hash0!" equ "!hash: =!" (
      if not defined /NM echo OK: !file!
      endlocal
      set /a okCnt+=1
    ) else if !hash! equ X (
      if not defined /NE echo *MISSING: !file!
      endlocal
      set /a missingCnt+=1
    ) else (
      if not defined /NE echo *FAILED: !file!
      endlocal
      set /a failCnt+=1
    )
  )
) 2>nul || (
  if not defined /NE echo *MISSING: %1
  set /a missingManifestCnt+=1
)
exit /b

:determineFormat
if "%hash0:~127%" neq "" (
  set "/A=SHA512"
) else if "%hash0:~95%" neq "" (
  set "/A=SHA384"
) else if "%hash0:~63%" neq "" (
  set "/A=SHA256"
) else if "%hash0:~39%" neq "" (
  set "/A=SHA1"
) else set "/A=MD5"

:defineEmpty
if /i "%/A%"=="md5" (
  set "empty=d41d8cd98f00b204e9800998ecf8427e"
  set "/A=MD5"
) else if /i "%/A%"=="sha1" (
  set "empty=da39a3ee5e6b4b0d3255bfef95601890afd80709"
  set "/A=SHA1"
) else if /i "%/A%"=="sha256" (
  set "empty=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
  set "/A=SHA256"
) else if /i "%/A%"=="sha384" (
  set "empty=38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"
  set "/A=SHA384"
) else if /i "%/A%"=="sha512" (
  set "empty=cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
  set "/A=SHA512"
) else (
  echo ERROR: Invalid /A algorithm>&2
  (goto) 2>nul&exit /b 1
)
exit /b


************* JScript portion **********/
var fso = new ActiveXObject("Scripting.FileSystemObject");
var out = fso.OpenTextFile(WScript.Arguments(0),2,true);
var chr;
while( !WScript.StdIn.AtEndOfStream ) {
  chr=WScript.StdIn.Read(1000000);
  out.Write(chr);
}

答案 1 :(得分:1)

尝试使用MD5.BAT

set "file=c:\myfile.ext"
call md5.bat "%file%" md5

if "%md5%" equ "79054025255fb1a26e4bc422aef54eb4" (
      echo MD5 identical!
) else (
      echo MD5 does not match.
)