0

I'm trying to replace a certain .jar file if the MD5 hash of the file changes. I've written a small PowerShell script to do the hashing of the file and the .ps1 script is run through a batch file.

After PowerShell prints the hash into 1.txt I want the batch script to check the text file for the correct hash and if the hash is different it will overwrite the file with the old version. The replacing of the file is not yet implemented but will be once the findstr issue is resolved.

@echo off
setlocal EnableDelayedExpansion

:a
powershell.exe -ExecutionPolicy ByPass -file powershellmd5.ps1

findstr /c:"ff b1 b9 2d b1 03 db 59 3f 9e ca 51 f0 14 67 62 ca a8 d7 7d" "1.txt"
echo !errorlevel!
timeout /t 10 /NOBREAK
goto a

Here is the content of 1.txt when the hashing is complete:

SHA1 hash of file license.jar:
ff b1 b9 2d b1 03 db 59 3f 9e ca 51 f0 14 67 62 ca a8 d7 7d
CertUtil: -hashfile command completed successfully.

The errorlevel is always 1, even though the string is identical to the one in the text file. Maybe I am using the arguments wrong?

I'm using Out-File in powershellmd5.ps1 to write the result:

certutil -hashfile license.txt | Out-File 1.txt
Ansgar Wiechers
  • 175,025
  • 22
  • 204
  • 278
xnstad
  • 3
  • 2
  • It works from the command line, findstr syntax is correct and would return 0 for the file sample you provided. If the path was wrong you would see an error message. Try inserting `pause` after the powershell call, wait a few seconds then see if findstr works – Alex K. Feb 10 '16 at 12:30
  • Is there any possibility that the separators of numbers in "1.txt" file _not_ be spaces (Ascii 32 chars)? – Aacini Feb 10 '16 at 13:09
  • @Aacini I'll look into that, this might be the case – xnstad Feb 10 '16 at 13:22
  • @Aacini Update: It works now, I created a new file that is identical to the one powershell gives me. Then I used filecompare and the /W to suppress white spaces and FC tells me the files are identical. This gives me the correct errorlevel and makes everything work the way I wanted it to. Thank you! – xnstad Feb 10 '16 at 13:32
  • @AlexK. The pause may have also contributed to solving this because I did try the /w switch in an earlier version of the script and got the same wrong result. – xnstad Feb 10 '16 at 13:34
  • Could you avoid using powershell to generate the hash file? If the involved process is just a `certutil -hashfile` command, then it can be done in the same Batch file. I think this solve your problem in an easier way (and your Batch file would run faster). – Aacini Feb 10 '16 at 14:06
  • @aacini I didn't know certutil worked in batch but I didn't check and I should have done that. Yes that will make things easier, I'll give it a try. – xnstad Feb 10 '16 at 14:11
  • @aacini certutil works but I'm using out-file to write the result and that is powershell only when i use the DOS way of writing " > 1.txt" FC can't read the file. [certutil -hashfile license.txt | Out-File 1.txt] This is the powershell part, it works so i'm not going to bother with it. – xnstad Feb 10 '16 at 14:18
  • See my new answer below... – Aacini Feb 10 '16 at 19:24

3 Answers3

3

Apparently you're using Out-File for creating 1.txt. The cmdlet uses Unicode (little endian UTF-16) as the default encoding, which findstr doesn't support. The command processes the file as ASCII¹ text and thus can't find a match.

There are two ways of approaching this problem:

  • Write 1.txt using ASCII encoding, either by calling Out-File with the -Encoding parameter:

    certutil -hashfile license.txt | Out-File 1.txt -Encoding Ascii
    

    or by calling Set-Content (which defaults to ASCII encoding):

    certutil -hashfile license.txt | Set-Content 1.txt
    
  • Use the find command (which supports Unicode) instead of findstr:

    find "ff b1 b9 2d b1 03 db 59 3f 9e ca 51 f0 14 67 62 ca a8 d7 7d" 1.txt
    

¹ Yes, I know, it's actually an ANSI encoding, but the parameter argument is named Ascii, so let's stick with that name for now to avoid confusion.

Ansgar Wiechers
  • 175,025
  • 22
  • 204
  • 278
  • While it wouldn't be sensible in this case, note that you can handle ASCII-text in UTF-16 files with `findstr` by using regular-expression mode and putting a dot between each character: `findstr /R /c:"f.f. .b.1.` and so on. (Of course this allows false positives if the text isn't ASCII. But it is sometimes useful.) – Harry Johnston Feb 10 '16 at 21:16
1

Accordingly to the comments posted in this question I think there are some misconceptions on this topic, that I try to clear.

All command-line based applications included with Windows are primarily designed to work with cmd.exe and Batch files. As a matter of fact, one of the features of PowerShell is that it "can use command-line applications in the same way as cmd.exe do". There is not a single command-line based application designed to work with PowerShell, but not with cmd.exe/Batch file.

In my humble opinion the use of PowerShell in this topic is not just unnecessary, but it is also the cause of the original problem. The pure Batch-file code below should run as originally intended, with no problems:

@echo off
setlocal EnableDelayedExpansion

:a
certutil -hashfile license.jar > "1.txt"

findstr /c:"ff b1 b9 2d b1 03 db 59 3f 9e ca 51 f0 14 67 62 ca a8 d7 7d" "1.txt"
echo !errorlevel!
timeout /t 10 /NOBREAK
goto a

As an additional point, the time required to run this pure Batch file is much lesser than the required to run the PowerShell-based one.

Aacini
  • 59,374
  • 12
  • 63
  • 94
  • Excuse me. Did you tested this solution? I am very interested in the result because, in my opinion, this is a very clear example of an error introduced by PowerShell in a code that otherwise would correctly run as a pure Batch file. – Aacini Feb 15 '16 at 23:59
  • Yes, I think the same... This means that you should not try to replace a Batch file solution by a "similar" PowerShell one if you are not aware about all the PoSh intricacies, that are more complex than the Batch file ones! – Aacini Feb 17 '16 at 01:29
0

Instead of using findstr I used FC (filecompare). I let powershell create 1.txt and then I copied the content over to 2.txt and saved it as unicode.

The white spaces in the file generated by powershell seems to not be regular spaces and use of the /W to suppress white spaces and /U for parsing the files as Unicode is necessary to make it work.

The code is now as following:

@echo off
setlocal EnableDelayedExpansion

:a

powershell.exe -ExecutionPolicy ByPass -file powershellmd5.ps1
timeout /t 3 /NOBREAK

fc /U /W /lb3 1.txt 2.txt

IF NOT ERRORLEVEL 1 ( 
    echo Indentical.
) else (
    echo Different.
)
pause


del /q 1.txt

timeout /t 10 /NOBREAK

goto a

The script now successfully compares both files, returns error code 0 and prints Identical"

xnstad
  • 3
  • 2