繁体   English   中英

如何在 Windows 批处理文件中使用 WMIC 将 DLL 或 EXE 的文件版本获取到变量?

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

我尝试使用 Windows 批处理文件获取文件版本。 此命令成功地将版本打印到控制台。

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

但是当我尝试使用以下方法将此输出传递给变量时,Windows 命令处理器输出:

Z:\\\\bin\\\\My_project.dll - 别名动词无效。

这个命令行有什么问题?

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

这就是我使用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"

第二个For循环旨在克服由 unicode WMIC结果产生的不需要的输出。


编辑

如果未规定WMIC ,您可以使用批处理文件中的VBScript

使用 Windows 脚本主机:

<!-- :
@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>

或通过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

问题在于where子句中的等号,它被cmd视为标准标记分隔符,就像SPACE , TAB , , , ; 、垂直制表符(代码0x0B )、换页(代码0x0C )和不间断空格(代码0xFF )。

for /F命令在单独的cmd实例中执行要解析的命令,但在此之前,每个标准标记分隔符序列都被单个SPACE替换。 所以=也被替换了,这留下了一些奇怪的语法。

要真正保留=符号,您需要像^=一样将其转义。 另一种方法是更改​​引用样式,以便=出现在""之间,方法是声明wmic DataFile where "Name='Z:\\\\bin\\\\My_project.dll'" get Version

但这仍然没有提供预期的结果,因为wmic返回 Unicode 输出,这留下了一些令人不安的转换人工制品,如孤立的回车字符。 这可以通过嵌套另一个for /F循环来避免。

此外,由于您选择的输出格式,您还将获得Version=前缀,这可能不是您想要包含的内容。 这可以通过for /F定义合适的tokensdelims选项来改变。

所有这些项目都会导致如下代码:

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"

这将从返回的版本中删除任何前导= -signs,如果有的话。

获取 DLL 版本的最简单解决方案是在批处理文件中使用此命令行:

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"

批处理文件中的命令行也可能略有不同:

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使用以%ComSpec% /c在后台启动的单独命令进程运行圆括号中的命令,并将所有行输出捕获到此命令进程的STDOUT 因此,必须考虑当前处理批处理文件的cmd.exe实例如何解析整个命令行以及FOR如何处理圆括号内的参数字符串。

当 Windows 命令处理器在执行FOR之前解析命令行时,必须使用^转义双引号字符串外的像>这样的重定向运算符,以使其首先被解释为文字字符。

并且双引号字符串外的等号=FOR解释为参数分隔符,如空格或逗号,如在命令提示符窗口中运行时可以看到的,例如:

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

此命令行输出:

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

出于这个原因,双引号字符串之外的=也必须用^转义以首先被解释为文字字符。

第二种解决方案使用备用WMIC语法将等号嵌入双引号字符串中,并使用反引号使用不同的FOR语法,以便能够在命令行中使用'以通过FOR执行。

带有选项/VALUE/FORMAT:Textvaluelist WMIC输出,例如:

 
 
Version=1.0.0.11
 
 

所以WMIC输出由两个空行组成,查询信息Version带有等号和版本值,另外两个空行。

问题是WMIC总是使用带有字节顺序标记 (BOM) 的 UTF-16 Little Endian 字符编码输出查询数据,并且FOR在正确处理此 Unicode 输出时存在错误。 FOR将十六进制值0D 00 0A 00的字节序列解释为 UTF-16 LE 将行尾回车 + 换行编码为0D 0D 0A 因此,在进一步处理剩余字符串之前,在由FOR删除的实行结尾处有一个错误的回车符。

有关此FOR错误的详细信息,请参见例如:

此错误是在这里工作部分是通过使用选项/VALUE来获得想要的信息输出由WMIC在格式一行Version=value期权和使用tokens=2 delims== 只有Version=value的捕获行有两个由等号分隔的字符串,因此命令SET仅在等号后的值的这一行上执行。 带有版本信息的前两个空行和后两个空行被FOR错误地解释为只有回车的行,不会导致执行命令SET,因为没有第二个字符串可以分配给循环变量I

这段代码期望版本字符串本身不包含一个或多个= ,对于 DLL 的版本来说应该总是如此。

注 1:环境变量val值未修改,如果出现任何错误,如根本找不到 DLL 文件,则该环境变量仍未定义。 WMIC输出的错误消息通过使用2>nul (带有转义> )从STDERR重定向到设备NUL来抑制。

注 2:分配给环境变量val的版本字符串的最后一个字符是错误的回车符。 在进一步处理val的字符串值时必须考虑到这一点。 的解决方案康波aschipfl使用两个for循环张贴更好,因为环境变量val与DLL的版本字符串没有错误回车确定。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM