The code of certutil-hash.cmd:
@echo off
certutil -hashfile "%~dpnx0" md5
pause>nul
I want to save the whole second line with the hash value in a variable. CMD-Output:
MD5 hash from C:\Users\ZerTerO\Desktop\certutil-hash.cmd:
9913d66d0b741494962e94ff540a8147
CertUtil: -hashfile command executed successfully.
The only solution would look like this to me:
@echo off
cls
call:hashfile
set "md5=%md5: =%"
echo.%md5%
pause>nul
exit
:hashfile
for /f "skip=1 tokens=1 delims=" %%a in ('certutil -hashfile "%~dpnx0" md5') do (set "md5=%%a" & goto:eof)
Is there a more elegant solution?
I only have to do this because Windows 7 and Windows 8 write spaces between the values:
set "md5=%md5: =%"
Thanks in advance...
ZerTerO
For the CertUtil
versions which do work with a HashAlgorithm
argument, (please see my comment), you can better deal with the loop, like this:
Set "md5="
For /F Delims^= %%G In ('CertUtil -HashFile "%~f0" MD5^|FindStr /VRC:"[^a-f 0-9]"')Do Set "md5=%%G"
Or more robustly like this:
Set "md5="
For /F Delims^= %%G In ('^""%__APPDIR__%certutil.exe" -HashFile "%~f0" MD5^|"%__APPDIR__%findstr.exe" /VRC:"[^a-f 0-9]"^"')Do @Set "md5=%%G"
Using findstr to exclude any lines which contain a character which is not an alphabetic character a
, b
, c
, d
, e
, or f
; a numeric character 0
, 1
, 2
, 3
, 4
, 5
, 6
, 7
, 8
, or 9
; or a space character, is in my opinion, more elegant than skipping the first line and then breaking out of the loop after the second line is processed.
As for your resulting variable, I'm not sure, in this case, whether I'd bother using set "md5=%md5: =%"
to specifically remove possible spaces, I'd just use echo.%md5: =%
. However if I was to be using the resulting variable often enough in my remaining script, I'd perform that task, within the labelled section:
@Echo Off
SetLocal EnableExtensions
ClS
Set "algo=MD5"
Call :HashFile "%~f0" %algo%
Echo(%hash%
Pause 1> NUL
GoTo :EOF
:HashFile
Set "hash="
For /F Delims^= %%G In ('^""%__APPDIR__%certutil.exe" -HashFile %1 %2 2^> NUL ^
^| "%__APPDIR__%findstr.exe" /V /R /C:"[^a-f 0-9]"^"') Do Set "hash=%%G"
If Not "%hash: =%" == "%hash%" Set "hash=%hash: =%"
Exit /B
Line 5
should ideally be part of a routine which determines if the version of certutil on the OS supports two arguments. If it doesn't that line would read Set "algo="
. You'll also notice that I have moved your hardcoded filename out of the loop, and used it as the first input argument to the Call
command. This should make your script more modular, and IMO elegant. I also think that it's more elegant to check if the %hash%
contains spaces, before asking to replace them with nothing. Elegance and efficiency are not necessarily the same.