Reputation: 24766
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
Upvotes: 1
Views: 3770
Reputation: 49086
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 the round brackets using a separate command process started with %ComSpec% /c
in the 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 the round brackets.
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 a byte sequence with the hexadecimal values 0D 00 0A 00
being UTF-16 LE encoded the line ending carriage return + line-feed as 0D 0D 0A
. So there is an erroneous carriage return at end of the real line ending removed by FOR before processing further the remaining string.
For details about this FOR bug see for example:
This bug is worked around here partly 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 before and the two empty lines after line with version information, wrong interpreted by FOR as lines with just a carriage return, do 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 1: The value of environment variable val
is unmodified respectively this environment variable is still 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.
Note 2: The version string assigned to the environment variable val
has as last character the erroneous carriage return. That must be taken into account on further processing the string value of val
. The solutions of Compo and aschipfl using two FOR loops as posted are better because the environment variable val
is defined with the version string of the DLL without the erroneous carriage return.
Upvotes: 1
Reputation: 38604
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
Upvotes: 2
Reputation: 34909
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.
Upvotes: 1