Search code examples
inno-setupchecksuminno-setup-v6

Automate obtaining the SHA256 for a file to download with Inno Setup 6.1?


The documentation for DownloadTemporaryFile says this about the RequiredSHA256OfFile parameter:

If RequiredSHA256OfFile is set it will compare this to the SHA-256 of the downloaded file and raise an exception if the hashes don't match.

An exception will be raised if there was an error. Otherwise, returns the number of bytes downloaded. Returns 0 if RequiredSHA256OfFile is set and the file was already downloaded.

From the answer here I have determined that the correct commandline method to obtain the checksum is:

CertUtil -hashfile MSAHelpDocumentationSetup.exe SHA256

This is how I add adding this particular file to my script:

AddFileForDownload('{#HelpDocSetupURL}', 'HelpDocSetup.exe');

Which expands to:

procedure AddFileForDownload(Url, FileName: string);
begin
    DownloadPage.Add(Url, FileName, '');
    FilesToDownload := FilesToDownload + '      ' + ExtractFileName(FileName) + #13#10;
    Log('File to download: ' + Url);
end;

Is there way to automate:

  1. Obtaining the checksum for my file.
  2. Caching that checksum into a string.
  3. Using that checksum value when building the script.

By automating this task it will provide two benefits:

  • Minimize user error in copy /pasting the checksum value.
  • Keep the checksum update to date without user interaction.

Is this feasible in Inno Setup with Pascal Script?


Solution

  • Pascal Script won't help you. You need the value at the compile time. So using a preprocessor. You can indeed execute the certutil. But imo, in this case, it's easier to use PowerShell and its Get-FileHash cmdlet:

    #define GetSHA256OfFile(FileName) \
      Local[0] = AddBackslash(GetEnv("TEMP")) + "sha256.txt", \
      Local[1] = \
        "-ExecutionPolicy Unrestricted -Command """ + \
        "Set-Content -Path '" + Local[0] + "' -NoNewline -Value " + \
        "(Get-FileHash('" + FileName + "')).Hash" + \
        """", \
      Exec("powershell.exe", Local[1], SourcePath, , SW_HIDE), \
      Local[2] = FileOpen(Local[0]), \
      Local[3] = FileRead(Local[2]), \
      FileClose(Local[2]), \
      DeleteFileNow(Local[0]), \
      LowerCase(Local[3])
    

    And then you can use it like:

    AddFileForDownload(
      '{#HelpDocSetupURL}', 'HelpDocSetup.exe', '{#GetSHA256OfFile("HelpDocSetup.exe")}');
    

    You of course need to add the third parameter to your AddFileForDownload function and pass it to TDownloadWizardPage.Add. You also may need to add a path to the file, so that the preprocessor can find it.