CMake get list of files to be signed - windows

I'm trying to make a .msi installation package using CMake, CPack, and Wix. The issue is I'm trying to sign the executables and DLLs that are going to be installed.
Currently I am trying to use a custom cmake script by setting CPACK_INSTALL_SCRIPTS
SET( CPACK_INSTALL_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/signcert.cmake")
And inside signcert.cmake is where I run into issue. I want to use signtool to sign:
execute_process(
COMMAND cmd /c signtool sign /debug /v /sm /fd sha256 /tr http://timestamp.comodoca.com /td sha256 /sha1 ${THUMBPRINT} "${CMAKE_INSTALL_PREFIX}applications/bin/*"
)
The signtool command execute properly when done in a VS Command Console (vcvarsall.bat), however the wild card does not expand properly in the execute_process, it says cannot find *.
How can I find a list of files in a particular directory and store it in a CMake variable? For example ${CMAKE_INSTALL_PREFIX}applications/bin/* ?

This issue is likely caused by the fact that your signcert.cmake script will not know the path for CMAKE_INSTALL_PREFIX. It is not forwarded from the main CMake invocation.
To get around this, you can make a script template signcert.cmake.in, and use configure_file to insert the CMAKE_INSTALL_PREFIX path into your script.
Within your script, one option to more safely obtain and pass a list of files is to use file(GLOB ...) to get a list of files in the directory, before calling execute_process. Here's what your script could look like (note the #CMAKE_INSTALL_PREFIX# marked for variable substitution):
file(GLOB MY_FILES_TO_SIGN
LIST_DIRECTORIES false
#CMAKE_INSTALL_PREFIX#applications/bin/*)
# Pass MY_FILES_TO_SIGN variable to execute_process.
execute_process(
COMMAND cmd /c signtool sign /debug /v /sm /fd sha256 /tr http://timestamp.comodoca.com /td sha256 /sha1 ${THUMBPRINT} ${MY_FILES_TO_SIGN}
)
In your main CMake project, configure this file using the following, which will generate signcert.cmake with the value of CMAKE_INSTALL_PREFIX substituted inside:
configure_file(signcert.cmake.in ${CMAKE_CURRENT_LIST_DIR}/signcert.cmake #ONLY)

Related

signtool: options interpreted as files on AppVeyor

I’m having this super weird behaviour on an AppVeyor build (Visual Studio 2019): In a shell script (cmd.exe), when signing my app with signtool, all the options are interpreted as files (signtool can sign multiple files at once).
The line "$WINDOWSKITBIN\\signtool.exe" sign /tr http://timestamp.digicert.com /td sha256 /fd SHA256 /n "Jan Gerner" /v /debug "build\\TypeWorld.exe" produces:
Successfully signed: build\TypeWorld.exe
Number of files successfully Signed: 1
Number of errors: 10
SignTool Error: File not found: C:/Program Files/Git/tr
SignTool Error: File not found: http://timestamp.digicert.com
SignTool Error: File not found: C:/Program Files/Git/td
SignTool Error: File not found: sha256
SignTool Error: File not found: C:/Program Files/Git/fd
SignTool Error: File not found: SHA256
SignTool Error: File not found: N:/
SignTool Error: File not found: Jan Gerner
SignTool Error: File not found: V:/
SignTool Error: File not found: C:/Program Files/Git/debug
The wanted file TypeWorld.exe is signed, just without all the options, and all the options are interpreted as files to sign which then aren’t found, obviously.
I've confirmed the escaped backslashes and folder variable to be correct.
This line echo "$WINDOWSKITBIN\\signtool.exe" sign /tr http://timestamp.digicert.com /td sha256 /fd SHA256 /n "Jan Gerner" /v /debug "build\\TypeWorld.exe"
produces the expected rendering: C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86\signtool.exe sign /tr http://timestamp.digicert.com /td sha256 /fd SHA256 /n Jan Gerner /v /debug build\TypeWorld.exe
I tried running the same in PowerShell, to same result.
None of what the AppVeyor staff recommended (also by email) helped.
What did help in the end is to not mix Windows and Linux (WSL) environments. In appveyor.yml I was calling the build script through sh (or later bash at the recommendation of AppVeyor staff):
build_script:
- cmd: C:\\msys64\\usr\\bin\\bash.exe wxPython/build/Windows/build-all.sh
Instead, for some commands it's better to keep things simple, so I converted the code signing part to a good old Windows batch file:
build_script:
- wxPython/build/Windows/build-sign.bat
Inside the batch file, the line
signtool.exe sign /tr http://timestamp.digicert.com /td sha256 /fd SHA256 /n "Jan Gerner" /v "build\\TypeWorld.exe" executes fine.

How to get chrome version using command prompt in windows

Is it possible to get version installed chrome version using command prompt in windows?
Tried,
"C:\Program Files\Google\Chrome\Application\chrome.exe" -version
"C:\Program Files\Google\Chrome\Application\chrome.exe" --version
"C:\Program Files\Google\Chrome\Application\chrome.exe" -product-version
"C:\Program Files\Google\Chrome\Application\chrome.exe" --product-version
When i do that, a browser instance is opening. What flag should I be using to get the version.
I am using Windows 7. Google Chrome version is 67.0.3396.87.
Thanks in advance
As of today user4851's is still working. I took a look at his linked bug report and the proposed work around did not work for me anymore.
Anways a new hkey is present in my directory which allows you to query the chrome version without being aware of the actual installation location:
reg query "HKEY_CURRENT_USER\Software\Google\Chrome\BLBeacon" /v version
There's a bug filed about this: https://bugs.chromium.org/p/chromium/issues/detail?id=158372
Original Answer (but see the update below)
What works for me is
wmic datafile where name="C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe" get Version /value
It prints
Version=67.0.3396.99
surrounded by some blank lines.
There are some other suggestions in the bug comments, like querying the registry.
Update
Someone from the Chromium team posted this "totally unsupported" batch file in the bug comment thread:
#ECHO OFF
:: Look for machine-wide Chrome installs (stable, Beta, and Dev).
:: Get the name, running version (if an update is pending relaunch), and
:: installed version of each.
FOR %%A IN (
{8A69D345-D564-463c-AFF1-A69D9E530F96},
{8237E44A-0054-442C-B6B6-EA0509993955},
{401C381F-E0DE-4B85-8BD8-3F3F14FBDA57}) DO (
reg query HKLM\Software\Google\Update\Clients\%%A /v name /reg:32 2> NUL
reg query HKLM\Software\Google\Update\Clients\%%A /v opv /reg:32 2> NUL
reg query HKLM\Software\Google\Update\Clients\%%A /v pv /reg:32 2> NUL
)
:: Look for Chrome installs in the current user's %LOCALAPPDATA% directory
:: (stable, Beta, Dev, and canary).
:: Get the name, running version (if an update is pending relaunch), and
:: installed version of each.
FOR %%A IN (
{8A69D345-D564-463c-AFF1-A69D9E530F96},
{8237E44A-0054-442C-B6B6-EA0509993955},
{401C381F-E0DE-4B85-8BD8-3F3F14FBDA57},
{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}) DO (
reg query HKCU\Software\Google\Update\Clients\%%A /v name /reg:32 2> NUL
reg query HKCU\Software\Google\Update\Clients\%%A /v opv /reg:32 2> NUL
reg query HKCU\Software\Google\Update\Clients\%%A /v pv /reg:32 2> NUL
)
That should probably be seen as the right way to go for the time being.
I tried Kilian's answer, however in my case, I was running it against a bunch of machines remotely via a service, so I don't think HKEY_CURRENT_USER was valid:
ERROR: The system was unable to find the specified registry key or value.
Assuming you know where the exe is, you can try a different approach and read the version property of the exe file:
# Powershell
# Older versions install to the 32-bit directory
(Get-Item "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe").VersionInfo
# Newer versions use the 64-bit directory
(Get-Item "C:\Program Files\Google\Chrome\Application\chrome.exe").VersionInfo
ProductVersion FileVersion FileName
-------------- ----------- --------
76.0.3809.100 76.0.3809.100 C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
To using it in cmd.exe or via any subprocess calls (python, go os/exec, etc.) you can do,
powershell -command "&{(Get-Item 'Absolute\path\to\chrome.exe').VersionInfo.ProductVersion}"
Using only commandline utils
dir /B/AD "C:\Program Files (x86)\Google\Chrome\Application\"|findstr /R /C:"^[0-9].*\..*[0-9]$"
78.0.3904.97
List only directories /AD within the Chrome application folder in short form /B.
findstr /R /C:"..." applies the following regex to the list of directories. The regex matches every foldername starting with a digit ^[0-9] and ending with ad digit [0-9]$.
Between the first and last digit there are any characters .* allowed but at least one dot should appear \.
user1425134's solution worked for me, but if you are allowed to assume that Chrome is part of %PATH% (if you can open Command Prompt and type chrome to start the browser), then it can be greatly simplified.
From Powershell you can type (Get-Command "chrome").Version.ToString()
Or from cmd.exe you can type powershell -c "(Get-Command "chrome").Version.ToString()"
(same for Chromium, just replace the command name)
I was able to use the rust kitty's solution without having chrome on my path, as:
from PowerShell:
(Get-Command C:\Program Files (x86)\Google\Chrome\Application\chrome.exe').Version.ToString()
from cmd:
powershell -command "(Get-Command C:\Program Files (x86)\Google\Chrome\Application\chrome.exe').Version.ToString()"
Via Powershell the command is -
Get-WmiObject -Class Win32_Product | ? {$_.name -eq 'Google Chrome'} |select Name,Version

the installation package could not be open batch file

I've been working on a batch file all day, that I can't get to work open through GPO (another day, another question). So I decided to do it manually with every computer. I have two exe's and one MSI. The exe's work perfectly fine. They get installed, and it all works out. The MSI, however, doesn't. It gives me the error: the installation package could not be opened. Verify that the package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer package.
Now when I go to the network share and use it from there, it works perfectly fine. So there must be an issue with my code.
Here's the code:
#echo off
IF NOT EXIST "C:\Program Files (x86)\Citrix\ICA Client\" (
pushd "\\KOPI-DC01\ACCURO Cloudwerx\ACCURO\1\"
.\CitrixReceiver-4.4.1000.exe /silent
)
IF NOT EXIST "C:\Program Files (x86)\triCerat\Simplify Printing\ScrewDrivers Client v4\" (
pushd "\\KOPI-DC01\ACCURO Cloudwerx\ACCURO\2\"
msiexec.exe /i ".\Screwdriver.msi"
)
IF NOT EXIST "C:\Program Files\Cloudwerx\CloudwerxPlugin\" (
pushd "\\KOPI-DC01\ACCURO Cloudwerx\ACCURO\3\"
.\cloudwerx-setup.exe /silent
)
pause
Any help would be greatly appreciated, thanks.
I am guessing that your problem is the distinction in powershell between the current location (set by the pushd command) and the working directory (unaffected by the pushd command). You can see the working directory of the powershell process using the [Environment]::CurrentDirectory property:
# C:\> [Environment]::CurrentDirectory = "c:\"
# C:\> [Environment]::CurrentDirectory
c:\
# C:\> pushd C:\Temp
# C:\Temp> [Environment]::CurrentDirectory
c:\
# C:\Temp> Get-Location
Path
----
C:\Temp
WHat is probably happening is that msiexec.exe is using the working directory (i.e. [Environment]::CurrentDirectory) and not the current powershell location at invocation. I would just specify the full path to msiexec:
msiexec.exe /i "\\KOPI-DC01\ACCURO Cloudwerx\ACCURO\2\\Screwdriver.msi"
MSI installation packages build with an older WIX utility would throw the error whenever installation was attempted from a batch script that was accessed on a shared drive using UNC path instead of a mapped drive letter. On the other hand whenever the batch file was executed with a mapped drive letter the installation would work normally.
I'm not blaming WIX here because I'm not certain whether they are responsible. I'm just describing symptoms here. It might just be the result of invoking plain vanilla Windows batch script that in turn executes msiexec with a bunch of command line parameters.

Windows signtool.exe sign command /s option

When using the signtool to digitally sign a catalog file (*.cat), what does the /s option actually do?
Example:
signtool sign /s SomeStore c:/someCAT.cat
What does the SomeStore parameter for the /s option do? How does one confirm that this parameter is correct?
I have checked the Microsoft signtool documentation here: https://msdn.microsoft.com/en-us/library/8s9b9yaz(v=vs.110).aspx#sign, but it does not seem to provide this information.
The /s option refers to the Certificate Store from which the signtool will be obtaining the data (credentials) necessary to sign the catalog file. See the following:
Digital Certificates: https://msdn.microsoft.com/en-us/library/windows/desktop/aa381975(v=vs.85).aspx
Certificate Stores: https://msdn.microsoft.com/en-us/library/windows/desktop/aa386971(v=vs.85).aspx
Running the signtool with the verify command provides feed back on whether the store specified with the /s option was valid.
Example:
signtool verify /pa /v c:\someCAT.cat
where the /pa and /v are described here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387764(v=vs.85).aspx

The UAC prompt shows a temporary random Program Name for msi, can the correct name be displayed?

I'm building an MSI installer for windows and sign the installer using signtool. When I run the .msi to test it, the UAC (User Account Control) prompt shows up to ask me if I want to allow the installation to proceed. That's fine, but the prompt shows a number of fields, and for the Program Name field it displays something like "403b3.msi". This is not the name of the msi I'm running.
How can I get the correct Program Name to be displayed?
Use the /d command line argument with the required program name when executing signtool to sign the msi.
It appears that the windows installer creates a temporary copy of the msi file and assigns it a generated name before running it. If you don't use /d with signtool, you get to see the temporary filename which isn't very useful for your users.
this is an applied version of #Scott-langham's comment.
this was directly from the PostBuildEvent of a visual studio installer project - VDPROJ file
set signtool="C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\signtool.exe"
set timestampurl=http://timestamp.digicert.com
set certpath="$(ProjectDir)CodeSigningCert.pfx"
:: Setup in your user environment variables
:: using something with low sort order to force off screen ZZCODECERTPASSWORD
if []==[%ZZCODECERTPASSWORD%] (
echo must set code signing certificate in ZZCODECERTPASSWORD environment variable. stopping build.
exit /b 2
)
:: need the filename with extension that is being generated
FOR /f %%i IN ("$(BuiltOuputPath)") DO (
SET outputfilename=%%~nxi
)
%signtool% sign /t %timestampurl% /f %certpath% /p %CODECERTPW% /d %outputfilename% "$(BuiltOuputPath)"
IF ERRORLEVEL 1 (
echo failed to sign MSI
exit /b 3
)
%signtool% sign /t %timestampurl% /f %certpath% /p %CODECERTPW% "$(ProjectDir)$(Configuration)\Setup.exe"
IF ERRORLEVEL 1 (
echo failed to sign boostrap setup EXE
exit /b 4
)

Resources