Before Windows 10, one could get all of the VersionInfo
strings by right clicking on a file and doing properties. That doesn't work anymore. It's like somebody only decided to show the ones that acquired a standard meaning over the decades. But the GUI doesn't matter except for noting it doesn't work so COM calls to the property page won't help. We want to know how from the command line anyway.
Tried:
PS> get-childitem .\execautablename | FormatList VersionInfo
PS> (get-item .\execautablename | format-list -force)
PS> get-childitem .\execautablename | ? {$_.VersionInfo.Xyz}
cmd> wmic datafile where Name="C:\\Full\\Path\\to\\executablename.exe" list full
The third command can get only some version strings but not others I know are there.
Its like all of the ways now know a "standard" list (there's two or three ideas of what the standard list is) and none of them know how to enumerate all the VersionInfo strings anymore. I have a binary with the string "ProductHash" which is the git commit hash of the corresponding source code used to compile it.
I keep on getting answers suggested involving {$_.VersionInfo}
. That path is never going to work because VersionInfo
believes in a fixed list of versioninfo properties to retrieve. The rc
compiler and the VERSIONINFO
PE structure believe differently. And wmic has a different fixed list that it retrieves.
This is the property. It only showed up at all after applying Fish's VersInfoEx shell extension linked by postanote.
Source snippit (windows resource):
#include <windows.h>
1 VERSIONINFO
FILEVERSION 10, 0, 0, 0
PRODUCTVERSION 10, 0, 0, 0
FILEFLAGSMASK 0
FILEFLAGS 0
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "FileDescription", "Hello RC"
VALUE "FileVersion", "10.0.0.0"
VALUE "LegalCopyright", "Copyright (C) Cedaron Medical, Inc. 2018"
VALUE "InternalName", "hellorc"
VALUE "ProductHash", "Hello_World_abcdefgh" /* this is the value I'm after */
VALUE "ProductName", "Hello RC"
VALUE "ProductVersion", "10.0.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
I managed to get a truly horrible and unsatisfying answer that doesn't know anything about VERSIONINFO and reads in megabytes of file and depends on way too much being installed.
cmd> c:\cygwin64\bin\tr -d \0 < filename.exe | c:\cygwin64\bin\strings | c:\cygwin64\bin\grep ^^ProductHash. | c:\cygwin64\bin\sed s/ProductHash//
This works provided the VERSIONINFO string name being searched for isn't also somewhere else in the binary. I'm hoping a bad answer suffices to explain the question better.
Trying to do the same thing with powershell as suggested by Pimp Juice IT didn't quite work:
PS> Get-Content ".\executablename.exe" | % { if($_ -match "ProductHash") { write-host $_}}
PS>
It was close enough to a working idea that I was able to determine why it yielded no output. I stuck cygwin's tr
back into the pipeline and the command took so long to run I thought it had hung but I eventually got some output.
PS> Get-Content ".\executablename.exe" | c:\cygwin64\bin\tr.exe -d \0 | % { if($_ -match "ProductHash") { write-host $_}}
InternalNameexecutablenameh$ProductNameMyProductPProductVersion10.0.591.927r)ProductHash50acd7cedb99dddab69c5de9b2f021ef72d64ca0DVarFileInfo$Translation ????<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
PS>
I have made a minimal binary hello.zip (1313 bytes, decompresses to 4096 bytes). The versioninfo key "ProductHash" has the value "Hello_World_abcdefgh".
Do not be deceived. ProductHash isn't a hash of the binary. It's a hash key into the source code repository to find the source code the binary was compiled from. The idea is if someone ends up with some strange version, we can track it down and determine exactly what code they have. Rather than have the the customer send us a large file, we would rather send them a small command to get the value out of it.
Best Answer
Final Working Solution Logic
This script takes into account the actual layout of the versioninfo structure, and works with one extra parameter (the 1 or 2 near the end) for the parity of the input string.
Development of the Final Solution Path
Below is some PowerShell logic that. . .
%
instead of?
to put the executable through Foreach-Object rather thanWhere-Object
Select *
instead ofFormat-List
to ensure the variable object is of aSystem.Object
BaseType rather than aSystem.Array
asFormat-List
createsVersionInfo
listPowerShell
Output Example
VersionInfo List Object
Search Binary String Content
Note: Just as the
cygwin
clistring
,grep
, and other commands search the binary of the file to match the string"ProductHash"
, you can read this from similar PowerShell commands as well.Further Resources