19

Binary files have a version embedded in them - easy to display in Windows Explorer.

alt text

How can I retrieve that file version, from a batch file?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Cheeso
  • 189,189
  • 101
  • 473
  • 713
  • See http://stackoverflow.com/questions/602802/command-line-tool-to-dump-windows-dll-version – Helen Nov 10 '09 at 10:25
  • Any hints here? [http://www.winvistatips.com/determine-version-exe-thru-batch-file-t284289.html](http://www.winvistatips.com/determine-version-exe-thru-batch-file-t284289.html) –  Nov 10 '09 at 10:18

7 Answers7

33

and three ways without external tools

1.WMIC

WMIC DATAFILE WHERE name="C:\\install.exe" get Version /format:Textvaluelist

Pay attention to the double slashes of file name.

Ready to use script:

@echo off
:wmicVersion pathToBinary [variableToSaveTo]
setlocal
set "item=%~1"
set "item=%item:\=\\%"


for /f "usebackq delims=" %%a in (`"WMIC DATAFILE WHERE name='%item%' get Version /format:Textvaluelist"`) do (
    for /f "delims=" %%# in ("%%a") do set "%%#"
)

if "%~2" neq "" (
    endlocal & (
        echo %version%
        set %~2=%version%
    )
) else (
    echo %version%
)

2.MAKECAB as the WMIC is not installed on home versions of windows here's a way with makecab that will run on every windows machine:

; @echo off
;;goto :end_help
;;setlocal DsiableDelayedExpansion
;;;
;;;
;;; fileinf /l list of full file paths separated with ;
;;; fileinf /f text file with a list of files to be processed ( one on each line )
;;; fileinf /? prints the help
;;;
;;:end_help

; REM Creating a Newline variable (the two blank lines are required!)
; set NLM=^


; set NL=^^^%NLM%%NLM%^%NLM%%NLM%
; if "%~1" equ "/?" type "%~f0" | find ";;;" | find /v "find" && exit /b 0
; if "%~2" equ "" type "%~f0" | find ";;;" | find /v "find" && exit /b 0
; setlocal enableDelayedExpansion
; if "%~1" equ "/l" (
;  set "_files=%~2"
;  echo !_files:;=%NL%!>"%TEMP%\file.paths"
;  set _process_file="%TEMP%\file.paths"
;  goto :get_info
; )

; if "%~1" equ "/f" if exist "%~2" (
;  set _process_file="%~2"
;  goto :get_info
; )

; echo incorect parameters & exit /b 1
; :get_info
; set "file_info="

; makecab /d InfFileName=%TEMP%\file.inf /d "DiskDirectory1=%TEMP%" /f "%~f0"  /f %_process_file% /v0>nul

; for /f "usebackq skip=4 delims=" %%f in ("%TEMP%\file.inf") do (
;  set "file_info=%%f"
;  echo !file_info:,=%nl%!
; )

; endlocal
;endlocal
; del /q /f %TEMP%\file.inf 2>nul
; del /q /f %TEMP%\file.path 2>nul
; exit /b 0

.set DoNotCopyFiles=on
.set DestinationDir=;
.set RptFileName=nul
.set InfFooter=;
.set InfHeader=;
.Set ChecksumWidth=8
.Set InfDiskLineFormat=;
.Set Cabinet=off
.Set Compress=off
.Set GenerateInf=ON
.Set InfDiskHeader=;
.Set InfFileHeader=;
.set InfCabinetHeader=;
.Set InfFileLineFormat=",file:*file*,date:*date*,size:*size*,csum:*csum*,time:*time*,vern:*ver*,vers:*vers*,lang:*lang*"

example output (it has a string version which is a small addition to wmic method :) ):

c:> fileinfo.bat /l C:\install.exe
    file:install.exe
    date:11/07/07
    size:562688
    csum:380ef239
    time:07:03:18a
    vern:9.0.21022.8
    vers:9.0.21022.8 built by: RTM
    lang:1033

3 Using shell.application and hybrid batch\jscript.Here's tooptipInfo.bat :

@if (@X)==(@Y) @end /* JScript comment
    @echo off

    rem :: the first argument is the script name as it will be used for proper help message
    cscript //E:JScript //nologo "%~f0" %*

    exit /b %errorlevel%

@if (@X)==(@Y) @end JScript comment */

////// 
FSOObj = new ActiveXObject("Scripting.FileSystemObject");
var ARGS = WScript.Arguments;
if (ARGS.Length < 1 ) {
 WScript.Echo("No file passed");
 WScript.Quit(1);
}
var filename=ARGS.Item(0);
var objShell=new ActiveXObject("Shell.Application");
/////


//fso
ExistsItem = function (path) {
    return FSOObj.FolderExists(path)||FSOObj.FileExists(path);
}

getFullPath = function (path) {
    return FSOObj.GetAbsolutePathName(path);
}
//

//paths
getParent = function(path){
    var splitted=path.split("\\");
    var result="";
    for (var s=0;s<splitted.length-1;s++){
        if (s==0) {
            result=splitted[s];
        } else {
            result=result+"\\"+splitted[s];
        }
    }
    return result;
}


getName = function(path){
    var splitted=path.split("\\");
    return splitted[splitted.length-1];
}
//

function main(){
    if (!ExistsItem(filename)) {
        WScript.Echo(filename + " does not exist");
        WScript.Quit(2);
    }
    var fullFilename=getFullPath(filename);
    var namespace=getParent(fullFilename);
    var name=getName(fullFilename);
    var objFolder=objShell.NameSpace(namespace);
    var objItem=objFolder.ParseName(name);
    //https://msdn.microsoft.com/en-us/library/windows/desktop/bb787870(v=vs.85).aspx
    WScript.Echo(fullFilename + " : ");
    WScript.Echo(objFolder.GetDetailsOf(objItem,-1));

}

main();

used against cmd.exe :

C:\Windows\System32\cmd.exe :
File description: Windows Command Processor
Company: Microsoft Corporation
File version: 6.3.9600.16384
Date created: ?22-?Aug-?13 ??13:03
Size: 347 KB
npocmaka
  • 55,367
  • 18
  • 148
  • 187
  • 1
    wmic works well. I've tried it on win server 2012 and windows 8. – max Nov 11 '14 at 05:03
  • If anyone's still reading this thread - I'm trying to use the WMIC method in a CMD file, redirecting the WMIC output to a file and then parsing the output using FOR. However this completely fails because the output file is UCS-2 LE BOM (according to Notepad++). If I convert it to ASCII manually it works fine. I also tried parsing the command output directly without using a file, but that fails too, presumably for the same reason. Anyone any ideas? – Dave Jan 27 '17 at 17:50
  • @Dave - [check this](http://www.dostips.com/forum/viewtopic.php?t=4266) Tomorrow I'll update the answer. – npocmaka Jan 27 '17 at 23:43
  • Thanks npocmaka, I need to study that in detail but I don't think my problem is to do with an extra CR. I am using WMIC to get a file version: (WMIC DATAFILE WHERE name="blahblah" get Version /format:Textvaluelist) and parsing with 'delims=='. The output from WMIC is 'Version=7.0.0.1' but I get nothing back from the FOR at all. Also, I looked for your update but the latest post on the dostips forum you linked to was 14 Apr 2014 and I couldn't find your name at all. Am I missing something?? – Dave Jan 29 '17 at 16:23
  • In the WMIC example, it doesn't seem to set %version% anywhere – Evvo Dec 01 '17 at 20:13
  • 1
    @Evvo - It is set in this line `for /f "delims=" %%# in ("%%a") do set "%%#"` . Version=something is part of the processed string. – npocmaka Dec 02 '17 at 02:05
22

The file version could be simply read without external tools by PowerShell like this:

(Get-Item myFile.exe).VersionInfo.FileVersion

and if you want to read it from an Batch file use:

powershell -NoLogo -NoProfile -Command (Get-Item myFile.exe).VersionInfo.FileVersion

and to save the file version to a variable use:

FOR /F "USEBACKQ" %%F IN (`powershell -NoLogo -NoProfile -Command ^(Get-Item "myFile.exe"^).VersionInfo.FileVersion`) DO (SET fileVersion=%%F)
echo File version: %fileVersion%

I've taken a realtive path here, you could also define it absolutely, like: C:\myFile.dll

More information about the file is shown if you omit .FileVersion

Coden
  • 2,579
  • 1
  • 18
  • 25
  • 1
    I suppose powershell isn't installed by default on Windows vista – jeb Sep 10 '18 at 08:36
  • 1
    Great answer, it works like charm. – Martin Braun Mar 28 '22 at 23:14
  • Thanks, but note that if there are parenthesis in path, for instance in `C:\Program Files (x86)\something\something.exe`, you should put it inside single quotes, not double quotes, with same example: `(Get-Item 'C:\Program Files (x86)\something\something.exe').VersionInfo.FileVersion` with double quote you'll have an error like `x86 : The term 'x86' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.`. – gluttony Oct 04 '22 at 14:21
7

Check out sigcheck.exe from Sysinternals Suite. This is a command-line utility that shows file version number, timestamp information, and digital signature details.

kenorb
  • 155,785
  • 88
  • 678
  • 743
Lars Corneliussen
  • 2,513
  • 2
  • 26
  • 36
3

Here is a solution in PowerShell using FileVersionInfo.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
devio
  • 36,858
  • 7
  • 80
  • 143
3

I think filever is what you need. It can get the file version for multiple items at the same time and locate files (e.g. EXE, DLL) that differ in size or version number.

2

Here is my try using WMIC to get file version of all *.exe and *.dll inside the directory of Skype as example :

@echo off
Mode 75,3 & color 9E
Title Get File Version of any Program from file list using WMIC by Hackoo
Set "RootFolder=%ProgramFiles%\Skype"
@for %%a in (%RootFolder%) do set "FolderName=%%~na"
Set "File_Version_List=%~dp0%FolderName%_File_Version_List.txt"
Set "ErrorFile=%~dp0%FolderName%_Error.txt
Set Extensions="*.exe" "*.dll"
If exist "%ErrorFile%" Del "%ErrorFile%"
If exist "%File_Version_List%" Del "%File_Version_List%"
echo(
echo          Please wait a while ... Process to get file version ...
set "BuildLineWith=call :BuildLine "
setlocal enabledelayedexpansion
CD /D "%RootFolder%"
@for /f "delims=" %%F in ('Dir /b /s %Extensions%') do (
    set "Version="
    Call :Get_AppName "%%F" AppName
    Call :Add_backSlash "%%F"
    Call :GetVersion !Application! Version
    Call :Remove_backSlash !Application!
    If defined Version (
        (
            echo !Application!
            echo !AppName! ==^> !Version!
            %BuildLineWith%*
        )>> "%File_Version_List%"
    ) else (
        (
            echo Version is not defined in !Application!
            %BuildLineWith%#
        )>> "%ErrorFile%"
    )
)
If Exist "%ErrorFile%" Start "" "%ErrorFile%"
If Exist "%File_Version_List%" Start "" /MAX "%File_Version_List%" & Exit
::*******************************************************************
:GetVersion <ApplicationPath> <Version>
Rem The argument %~1 represente the full path of the application
Rem without the double quotes
Rem The argument %2 represente the variable to be set (in our case %2=Version)  
FOR /F "tokens=2 delims==" %%I IN (
  'wmic datafile where "name='%~1'" get version /format:Textvaluelist 2^>^nul'
) DO FOR /F "delims=" %%A IN ("%%I") DO SET "%2=%%A"
Exit /b
::*******************************************************************
:Add_backSlash <String>
Rem Subroutine to replace the simple "\" by a double "\\" into a String
Set "Application=%1"
Set "String=\"
Set "NewString=\\"
Call Set "Application=%%Application:%String%=%NewString%%%"
Exit /b
::*******************************************************************
:Remove_backSlash <String>
Rem Subroutine to replace the double "\\" by a simple "\" into a String
Set "Application=%1"
Set "String=\\"
Set "NewString=\"
Call Set "Application=%%Application:%String%=%NewString%%%"
Exit /b
::*******************************************************************
:Get_AppName <FullPath> <AppName>
Rem %1 = FullPath
Rem %2 = AppName
for %%i in (%1) do set "%2=%%~nxi"
exit /b
::*******************************************************************
:BuildLine
set "LineChar=%1"
if "%LineChar%"=="" set "LineChar=_"
for /f "tokens=2 skip=4" %%A in ('mode con: /status') do set "WindowColumns=%%A" & goto :GotColumnCount
:GotColumnCount
set "CharLine="
setlocal EnableDelayedExpansion
for /L %%A in (1,1,%WindowColumns%) do set "CharLine=!CharLine!!LineChar:~0,1!"
setlocal DisableDelayedExpansion
endlocal
echo %CharLine%
goto :eof
::*******************************************************************
Hackoo
  • 18,337
  • 3
  • 40
  • 70
0

I've found this code from Rob Vanderwoude's site:

@ECHO OFF
IF [%1]==[] GOTO Syntax
IF NOT [%2]==[] GOTO Syntax
ECHO.%1 | FIND "?" >NUL
IF NOT ERRORLEVEL 1 GOTO Syntax
IF NOT EXIST %1 GOTO Syntax
IF NOT "%OS%"=="Windows_NT" GOTO Syntax

SETLOCAL
SET FileVer=
FOR /F "tokens=1 delims=[]" %%A IN ('STRINGS %1 ^| FIND /N /V "" ^| FIND /I "FileVersion"') DO SET LineNum=%%A
SET /A LineNum += 1
FOR /F "tokens=1* delims=[]" %%A IN ('STRINGS %1 ^| FIND /N /V "" ^| FIND "[%LineNum%]"') DO SET FileVer=%%B
SET FileVer
ENDLOCAL
GOTO:EOF

:Syntax
ECHO.
ECHO FileVer.bat,  Version 1.00 for NT 4 / 2000 / XP
ECHO Display the specified file's version number
ECHO.
ECHO Usage:  FILEVER  progfile
ECHO.
ECHO Where:  "progfile" is the name of a Windows executable, DLL, or system file
ECHO.
ECHO Uses SysInternal's STRINGS.EXE, avalable at http://www.sysinternals.com
ECHO.
ECHO Written by Rob van der Woude
ECHO http://www.robvanderwoude.com

Looks interesting as it uses STRINGS from SysInternals.

kenorb
  • 155,785
  • 88
  • 678
  • 743
Leptonator
  • 3,379
  • 2
  • 38
  • 51