How do I get all of the VersionInfo strings from a .exe file from the Windows command prompt

1

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.

versioninfo after applying VersInfoEx

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.

Joshua

Posted 2018-08-15T23:50:30.527

Reputation: 619

FWIW, you mis-spelled "executablename" incorrectly in your code above. You spelled it as "execautablename" – Patrick McMahon – 2019-09-09T16:13:27.583

@PatrickMcMahon: The edit link is there. Help yourself for easy rep. – Joshua – 2019-09-09T16:14:22.940

Answers

4

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.

$versioninfostate = 0
(Get-Content "hello.exe" -Encoding Unicode) -split {$_ -lt " "} | % { if ($versioninfostate -eq 1) { write-host $_ } if ($versioninfostate -gt 0) { $versioninfostate = $versioninfostate - 1} if ($_ -match "ProductHash$") { $versioninfostate = 2 }}

Development of the Final Solution Path

  1. "The last command can get only some version strings but not others I know are there"
    • Use Select * to get additional properties not shown with just Format-List

  2. "Get all of the VersionInfo strings from a .exe file"
    • Pipe the exe over to % {$_.VersionInfo} to use Foreach-Object rather than Where-Object with $_.VersionInfo zeroing in on just its properties in one list/record set

  3. "Cannot resolve arbitrary property names"
    • Actually using the #1 & #2 as listed above you can (see below) enter image description here

  4. "As per your latest update showing you installed a third party utility recommended by someone to you in a comment; that software seems to be from 2010 and designed specifically for Windows 7. In any case, it seems to add an additional property named ProductHash as per your latest update screen shot."
    • Use Get-FileHash and then explicitly get the hash value of the exe that way


Below is some PowerShell logic that. . .

  • Uses% instead of ? to put the executable through Foreach-Object rather than Where-Object
  • Uses Select * instead of Format-List to ensure the variable object is of a System.Object BaseType rather than a System.Array as Format-List creates
  • Sets a variable with the explicit property value as you specify from the VersionInfo list
  • Uses Get-FileHash to get the exe hash value

PowerShell

$t = get-childitem ".\executablename" | % {$_.VersionInfo} | Select *
$Hash = (Get-FileHash $Exe).Hash
$t.<Property>, $Hash

Output Example

Coolest - www.CoolTool.com
30E14E358DD76EC712CCC6B5FD1E79DDEAA653E682E968DA0229BE13BED2B991

VersionInfo List Object

PS C:\WINDOWS\system32> get-childitem ".\executablename" | % {$_.VersionInfo} | Select *


FileVersionRaw     : 1.80.0.0
ProductVersionRaw  : 1.80.0.0
Comments           : 
CompanyName        : Coolest - www.CoolTool.com
FileBuildPart      : 0
FileDescription    : Program - Cool memory analyzer
FileMajorPart      : 1
FileMinorPart      : 80
FileName           : C:\Users\User\Desktop\Coolio.exe
FilePrivatePart    : 0
FileVersion        : 1.80
InternalName       : TooCool
IsDebug            : False
IsPatched          : False
IsPrivateBuild     : False
IsPreRelease       : False
IsSpecialBuild     : False
Language           : English (United States)
LegalCopyright     : Copyright © 1985-2099 Michael Jordan
LegalTrademarks    : 
OriginalFilename   : Coolio
PrivateBuild       : 
ProductBuildPart   : 0
ProductMajorPart   : 1
ProductMinorPart   : 80
ProductName        : TooCool
ProductPrivatePart : 0
ProductVersion     : 1.80
SpecialBuild       : 

Search Binary String Content

Note: Just as the cygwin cli string, 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.

$Match = (Get-Content ".\executablename") -replace "`0", "" | % {if($_ -match "(ProductHash)") {$Matches[0]}}
$Line  = (Get-Content ".\executablename") -replace "`0", "" | % {if($_ -match "(ProductHash)") {$_}} | % {if($_ -match "(ProductHash).*$") {$Matches[0]}} 
$Line  = $Line -replace "[\W]", "`r`n" | % {if($_ -match "(ProductHash).*\s") {$Matches[0]}}
$MisMatch = $Line.Replace($Match, "")
Write-Output "$Match`: $MisMatch"

Example Output

ProductHash: Hello_World_abcdefgh2

Further Resources

Pimp Juice IT

Posted 2018-08-15T23:50:30.527

Reputation: 29 425

1

I just did this on an executable and I see the version info on the details tab. So, I am kind of loss about what you mean by this.

This PS approach is also documented here:

https://blogs.technet.microsoft.com/askpfeplat/2014/12/07/how-to-correctly-check-file-versions-with-powershell

On my Win10 client

 (Get-CimInstance -CimInstance Win32_OperatingSystem).Caption
Microsoft Windows 10 Pro

 $PSVersionTable

Name                           Value                                                                                                                                       
----                           -----                                                                                                                                       
PSVersion                      5.1.17134.228                                                                                                                               
PSEdition                      Desktop                                                                                                                                     
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0, 5.0, 5.1.17134.228}                                                                                                    
BuildVersion                   10.0.17134.228                                                                                                                              
CLRVersion                     4.0.30319.42000                                                                                                                             
WSManStackVersion              3.0                                                                                                                                         
PSRemotingProtocolVersion      2.3                                                                                                                                         
SerializationVersion           1.1.0.1                                                                                                                                     



 (Get-Item -Path 'F:\Downloads\WindowsAzureADRightsManagementAdministration_x64.exe').VersionInfo | Format-List -Force 


OriginalFilename  : setup.exe
FileDescription   : Software Installer
ProductName       : Windows Azure AD Rights Management Administration
Comments          : 
CompanyName       : Microsoft Corporation
FileName          : F:\Downloads\WindowsAzureADRightsManagementAdministration_x64.exe
FileVersion       : 1.0.594.1
ProductVersion    : 1.0.594.1
IsDebug           : False
IsPatched         : False
IsPreRelease      : False
IsPrivateBuild    : False
IsSpecialBuild    : False
Language          : English (United States)
LegalCopyright    : Copyright (c) Microsoft Corporation. All rights reserved.
LegalTrademarks   : Microsoft and Windows are either registered trademarks or trademarks of Microsoft Corporation in the U.S. and/or other countries.
PrivateBuild      : **************************************
SpecialBuild      : 
FileVersionRaw    : 1.0.594.1
ProductVersionRaw : 1.0.594.1

postanote

Posted 2018-08-15T23:50:30.527

Reputation: 1 783

That's the same (get-item .\execautablename | format-list -force) that I already said doesn't work. There are VersionInfo properties I can see in the Windows 7 GUI that aren't showing up. – Joshua – 2018-08-16T13:53:31.480

Well, I thing we all get that, but you have not stated what properties you are after that you are not getting. I have no legacy systems at my disposal, and have not had those in years. However, we can all see this stuff on legacy code site like, https://www.codeproject.com/articles/118909/windows-file-properties-version-tab-shell-extens. As noted, natively, this stuff is returned by the OS. If the OS does not provide it then it cannot be retrieved, without potentially going down that above link sample approach.

– postanote – 2018-08-16T16:56:54.120

Last sentence: " I have a binary with the string "ProductHash" " – Joshua – 2018-08-16T17:21:51.323

Well, that codeproject shell extension works on machines that have a full GUI installed (not server core). It does show all the properties. – Joshua – 2018-08-16T17:43:12.853

1OK, but your post said Win10, not server core. Now, I don't have server core anywhere in my labs at this time so no way to validate against, that, and no files like what you have to sanity check. With all that said, just use raw WMIC against the file name and see what you get back. If it is not there, then it's a catch22 on the current OS versions as far as I can validate thus far. example: wmic datafile where Name="D:\Temp\AADRMS.exe" list full – postanote – 2018-08-16T18:44:32.513

We are currently debating whether or not a GUI solution is good enough. The question didn't say server core but it did say command line. – Joshua – 2018-08-16T18:58:14.427