Как получить все строки VersionInfo из файла .exe из командной строки Windows

875
Joshua

До Windows 10 можно было получить все VersionInfoстроки, щелкнув правой кнопкой мыши по файлу и выполнив свойства. Это больше не работает. Как будто кто-то решил показать только те, которые приобрели стандартное значение за десятилетия. Но GUI не имеет значения, за исключением того, что он не работает, поэтому вызовы COM на страницу свойств не помогут. В любом случае мы хотим узнать, как из командной строки.

Пытался:

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 

Третья команда может получить только некоторые строки версии, но не те, которые, как я знаю, есть.

Это похоже на то, как теперь все способы знают «стандартный» список (есть два или три представления о том, что такое стандартный список), и никто из них не знает, как перечислить все строки VersionInfo. У меня есть двоичный файл со строкой «ProductHash», которая является хешем git commit соответствующего исходного кода, используемого для его компиляции.

Я продолжаю получать ответы, предлагаемые с участием {$_.VersionInfo}. Этот путь никогда не сработает, потому что VersionInfoверит в фиксированный список свойств versioninfo для извлечения. rcКомпилятор и VERSIONINFOструктура PE думает иначе. И wmic имеет другой фиксированный список, который он получает.

versioninfo after applying VersInfoEx

Это собственность. Он появился только после применения расширения оболочки VersInfoEx от Fish, связанного с помощью postanote .

Фрагмент исходного кода ( ресурс Windows ):

#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 

Мне удалось получить по-настоящему ужасный и неудовлетворительный ответ, который ничего не знает о VERSIONINFO и читает в мегабайтах файла и зависит от слишком большого количества устанавливаемых файлов.

cmd> c:\cygwin64\bin\tr -d \0 < filename.exe | c:\cygwin64\bin\strings | c:\cygwin64\bin\grep ^^ProductHash. | c:\cygwin64\bin\sed s/ProductHash// 

Это работает при условии, что искомое имя строки VERSIONINFO не находится где-то еще в двоичном файле. Я надеюсь, что плохого ответа достаточно, чтобы лучше объяснить вопрос.

Попытка сделать то же самое с PowerShell, как это было предложено Pimp Juice IT, не сработала:

PS> Get-Content ".\executablename.exe" | % { if($_ -match "ProductHash") { write-host $_}} PS> 

Это было достаточно близко к рабочей идее, и я смог определить, почему она не дала результатов. Я засунул Cygwin trобратно в конвейер, и выполнение команды заняло так много времени, что я подумал, что оно зависло, но в итоге я получил некоторый вывод.

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> 

Я сделал минимальный двоичный файл hello.zip (1313 байт, распаковывает до 4096 байт). Ключ информации о версии "ProductHash" имеет значение "Hello_World_abcdefgh".

Не обманывайтесь. ProductHash не является хешем двоичного файла. Это хэш-ключ в хранилище исходного кода, чтобы найти исходный код, из которого был скомпилирован бинарный файл. Идея в том, что если кто-то получит какую-то странную версию, мы можем отследить ее и точно определить, какой код у них есть. Вместо того чтобы заказчик отправлял нам большой файл, мы бы отправили ему небольшую команду, чтобы извлечь из него значение.

1

2 ответа на вопрос

3
Pimp Juice IT

Конечная рабочая логика решения

Этот сценарий учитывает фактическое расположение структуры versioninfo и работает с одним дополнительным параметром (1 или 2 в конце) для проверки четности входной строки.

$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 }} 

Разработка пути окончательного решения

  1. «Последняя команда может получить только некоторые строки версии, но не те, которые я знаю, там есть»
    • Используйте, Select *чтобы получить дополнительные свойства, не показанные толькоFormat-List

  2. «Получить все строки VersionInfo из файла .exe»
    • Труба ехе к % {$_.VersionInfo}использовать, Foreach-Objectа не Where-Objectс $_.VersionInfo нацеливал на только его свойства в одном списке / комплект запись

  3. «Не удается разрешить произвольные имена свойств»
    • На самом деле, используя # 1 & # 2, как указано выше, вы можете (см. Ниже) enter image description here

  4. «В соответствии с вашим последним обновлением показывая вы установили утилиту сторонней рекомендованную кто - то к вам в комментариях, то программное обеспечение, кажется, с 2010 года и разработано специально для Windows 7. В любом случае, это, кажется, добавить дополнительное свойство с именем ProductHashв соответствии с ваш последний скриншот обновления. "
    • Используйте Get-FileHash и затем явно получите хеш-значение exe таким образом


Ниже приведена некоторая логика PowerShell., ,

  • Использует %вместо того, ?чтобы поместить исполняемый файл через Foreach-Object, а неWhere-Object
  • Используется Select *вместо того, Format-Listчтобы гарантировать, что объект переменной имеет System.Object тип BaseType, а не System.Arrayкак Format-Listсоздает
  • Устанавливает переменную с явным значением свойства, указанным в VersionInfoсписке
  • Использует Get-FileHash, чтобы получить значение хеша exe

PowerShell

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

Пример вывода

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 :  

Поиск двоичного содержимого строки

Примечание. Подобно тому, как команды cygwincli string, grepи другие выполняют поиск в двоичном файле, чтобы найти совпадение со строкой "ProductHash", вы также можете прочитать это из аналогичных команд PowerShell.

$Match = (Get-Content ".\executablename") -replace "`0", "" | % } $Line = (Get-Content ".\executablename") -replace "`0", "" | % } | % }  $Line = $Line -replace "[\W]", "`r`n" | % } $MisMatch = $Line.Replace($Match, "") Write-Output "$Match`: $MisMatch" 

Пример вывода

ProductHash: Hello_World_abcdefgh2 

Дополнительные ресурсы

1
postanote

Я только что сделал это на исполняемом файле, и я вижу информацию о версии на вкладке сведений. Итак, я немного расстроен тем, что вы имеете в виду под этим.

Этот подход PS также задокументирован здесь:

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

На моем клиенте Win10

 (Get-CimInstance -CimInstance Win32_OperatingSystem).Caption Microsoft Windows 10 Pro  $PSVersionTable  Name Value  ---- -----  PSVersion 5.1.17134.228  PSEdition Desktop  PSCompatibleVersions  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 
Это то же самое (get-item. \ Execautablename | format-list -force), которое, как я уже сказал, не работает. Есть свойства VersionInfo, которые я вижу в графическом интерфейсе Windows 7, которые не отображаются. Joshua 6 лет назад 0
Ну, я думаю, мы все это получаем, но вы не указали, какие свойства вы после этого не получаете. В моем распоряжении нет устаревших систем, и у меня их не было уже много лет. Тем не менее, мы все можем увидеть этот материал на устаревшем кодовом сайте, например, https://www.codeproject.com/articles/118909/windows-file-properties-version-tab-shell-extens. Как уже отмечалось, изначально этот материал возвращается ОС. Если операционная система не предоставляет ее, то ее нельзя получить, не приведя к возможному подходу, описанному выше. postanote 6 лет назад 0
Последнее предложение: «У меня есть двоичный файл со строкой« ProductHash »» Joshua 6 лет назад 0
Что ж, это расширение оболочки codeproject работает на машинах, на которых установлен полный графический интерфейс (не на ядре сервера). Это действительно показывает все свойства. Joshua 6 лет назад 0
Хорошо, но ваш пост сказал Win10, а не ядро ​​сервера. Сейчас у меня нет ни одного серверного ядра в моих лабораториях, поэтому нет никакого способа проверить это, и нет таких файлов, как то, что вы должны проверить. С учетом всего сказанного, просто используйте необработанный WMIC против имени файла и посмотрите, что вы получите. Если его там нет, то это уловка 22 для текущих версий ОС, насколько я могу проверить до сих пор. пример: wmic datafile где Name = "D: \\ Temp \\ AADRMS.exe" полный список postanote 6 лет назад 1
В настоящее время мы обсуждаем, является ли решение с графическим интерфейсом достаточно хорошим. Вопрос не говорил о ядре сервера, но о командной строке. Joshua 6 лет назад 0