How to get file version of a DLL or EXE to a variable using WMIC in a Windows batch file?

末鹿安然 提交于 2019-12-11 08:38:12

问题


I try to get the file version using a Windows batch file. This command successfully prints the version to console.

WMIC DATAFILE WHERE name="Z:\\bin\\My_project.dll" get Version /format:Textvaluelist

But when I try to get this output to a variable using the below method, Windows command processor outputs:

Z:\\bin\\My_project.dll - Invalid alias verb.

What is wrong on this command line?

for /f %%a in ('WMIC DATAFILE WHERE name="Z:\\bin\\My_project.dll" get Version /format:Textvaluelist') do set val=%%a

回答1:


This is how I'd attempt this task using WMIC:

For /F "Tokens=1* Delims==" %%A In (
    'WMIC DataFile Where "Name='Z:\\bin\\My_project.dll'" Get Version /Value 2^>Nul'
) Do For /F "Tokens=*" %%C In ("%%B") Do Set "val=%%C"

The second For loop is designed to overcome the unwanted output resulting from the unicode WMIC result.


Edit

If WMIC wasn't stipulated, you could utilise VBScript from your batch file:

Using Windows Scripting Host:

<!-- :
@Echo Off
For /F %%A In ('CScript //NoLogo "%~f0?.wsf"') Do Set "val=%%A"
Set val 2>Nul
Pause
Exit /B

-->
<Job><Script Language="VBScript">
  WScript.Echo CreateObject("Scripting.FileSystemObject").GetFileVersion("Z:\bin\My_project.dll")
</Script></Job>

Or via mshta.exe:

@Echo Off
For /F %%A In ('
    MsHTA VBScript:Execute("Set o=CreateObject(""Scripting.FileSystemObject""):o.GetStandardStream(1).Write(o.GetFileVersion(""Z:\bin\My_project.dll"")):Close"^)
') Do Set "val=%%A"
Set val 2>Nul
Pause



回答2:


The problem is the equal-to sign in your where clause, which is seen as a standard token separator by cmd, just like SPACE, TAB, ,, ;, the vertical tab (code 0x0B), the form-feed (code 0x0C) and the non-break space (code 0xFF).

The for /F command executes the command to be parsed in a separate cmd instance, but before doing that, every sequence of standard token separators becomes replaced by a single SPACE. So also the = becomes replaced, which leaves some odd syntax behind.

To literally keep the =-sign you need to escape it like ^=. An alternative way is to change quotation style so that the = appears in between "", by stating wmic DataFile where "Name='Z:\\bin\\My_project.dll'" get Version.

But this still does not deliver the expected result, because wmic returns Unicode output, which leaves some disturbing conversion artefacts like orphaned carriage-return characters behind. This can be avoided by nesting another for /F loop.

Additionally, because of your output chosen format, you would also get a Version= prefix, which is probably not what you want to be included. This can be changed by defining suitable tokens and delims options for for /F.

All these items lead to a code like the following:

for /F "usebackq delims=" %%a in (`
    wmic DataFile where "Name='Z:\\bin\\My_project.dll'" get Version /VALUE
`) do for /F "tokens=1* delims==" %%b in ("%%a") do set "val=%%c"

This would remove any leading =-signs from the returned version, if there were any.




回答3:


The simplest solution to get version of a DLL is using this command line in a batch file:

for /F "tokens=2 delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe DATAFILE WHERE name^="Z:\\bin\\My_project.dll" get Version /VALUE 2^>nul') do set "val=%%I"

Also possible is this slightly different command line in a batch file:

for /F "usebackq tokens=2 delims==" %%I in (`%SystemRoot%\System32\wbem\wmic.exe DATAFILE WHERE "name='Z:\\bin\\My_project.dll'" GET Version /VALUE 2^>nul`) do set "val=%%I"

FOR runs the command in round brackets in a separate command process started with cmd /C in background and captures all lines output to STDOUT of this command process. For that reason it must be taken into account how cmd.exe instance currently processing the batch file parses the entire command line and how FOR processes the argument strings within round bracket.

A redirection operator like > outside a double quoted string must be escaped with ^ to get it interpreted first as literal character when Windows command processor parses the command line before executing FOR.

And an equal sign = outside a double quoted string is interpreted by FOR as an argument separator like a space or a comma as it can be seen on running in a command prompt window for example:

for %I in ("space ' ' and comma ',' and equal sign '='" space,comma=equal_sign) do @echo %I

This command line outputs:

"space ' ' and comma ',' and equal sign '='"
space
comma
equal_sign

For that reason also = outside a double quoted string must be escaped with ^ to be interpreted first as literal character.

The second solution uses an alternate WMIC syntax to embed the equal sign in a double quoted string and a different FOR syntax using back quotes to be able to use ' in command line to execute by FOR.

WMIC outputs with option /VALUE or /FORMAT:Textvaluelist for example:

 
 
Version=1.0.0.11
 
 

So the WMIC output consists of two empty lines, the queried information Version with an equal sign and the version value, and two more empty lines.

The problem is that WMIC outputs always the queried data using UTF-16 Little Endian character encoding with byte order mark (BOM) and FOR has a bug on processing this Unicode output correct. FOR interprets the last two UTF-16 encoded empty lines as one line with carriage return + carriage return + line-feed. For details about this FOR bug see for example:

  • Batch: How to correct variable overwriting misbehavior when parsing output
  • cmd is somehow writing chinese text as output

This bug is worked around here by using option /VALUE to get the wanted information output by WMIC on one line in format Version=value and using FOR options tokens=2 delims==. Only the captured line with Version=value has two strings separated by an equal sign and so the command SET is executed only on this line with the value after the equal sign. The two empty lines after line with version information, wrong interpreted by FOR as one line with just a carriage return, does not result in executing command SET as there is no second string which could be assigned to loop variable I.

It is expected by this code that the version string does not contain itself one or more = which should be always the case for version of a DLL.

Note: The value of environment variable val is unmodified respectively this environment variable still is not defined if any error occurs like the DLL file is not found at all. The error message output by WMIC is suppressed by redirecting it with 2>nul (with escaping >) from STDERR to device NUL.



来源:https://stackoverflow.com/questions/51496634/how-to-get-file-version-of-a-dll-or-exe-to-a-variable-using-wmic-in-a-windows-ba

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!