我们有一个批处理文件,可以在开发人员设置中安装多个程序。当我们获得使用过的组件的新版本时,会定期运行。因此,只有在版本不同的情况下安装才会很好。
在命令提示符下,我可以运行它并返回安装的版本:
wmic datafile where name='C:\\Program Files (x86)\\Common Files\\Company\\Product\\Version12\\Product.exe' get version /format:list
其中输出Version=12.1.369.0
。
然而,当我把它放到像这样的批处理文件中并尝试提取版本时:
echo off
FOR /F "tokens=2 delims==" %%I in ('"wmic datafile where^(name^="C:\\Program Files (x86)\\Common Files\\Company\\Product\\Version12\\Product.exe" get version /format:list"') DO (SET "RESULT=%%I")
ECHO %RESULT%
我收到回复\\Common was unexpected at this time.
有些部分可能是多余的,因为我一直试图通过网络来解决这个问题。
我错过了什么?
答案 0 :(得分:8)
你有一套错位的双引号,还有一个额外的(
。
WMIC使用SQL语法,字符串用单引号括起来。内部单引号不会干扰包含单引号的命令。
您可以在WHERE子句(不包括WHERE关键字)周围加上双引号,以避免FOR DO()子句中的某些转义问题。
@echo off
FOR /F "tokens=2 delims==" %%I IN (
'wmic datafile where "name='C:\\Program Files (x86)\\Common Files\\Company\\Product\\Version12\\Product.exe'" get version /format:list'
) DO SET "RESULT=%%I"
ECHO %RESULT%
但这可能不是完整的解决方案。您无法使用上面的代码看到它,但RESULT实际上包含一个尾随回车符(0x0D)。这是由于FOR / F如何处理WMIC unicode输出的怪癖。 WMIC输出的每一行都有额外的尾随回车。
只要您始终使用%RESULT%
(正常扩展)访问RESULT,那么您将不会遇到任何问题。但如果您需要延迟扩展,那么您可能会遇到问题,如下所示。
@echo off
setlocal enableDelayedExpansion
FOR /F "tokens=2 delims==" %%I IN (
'wmic datafile where "name='C:\\Program Files (x86)\\Common Files\\Company\\Product\\Version12\\Product.exe'" get version /format:list'
) DO SET "RESULT=%%I"
ECHO %RESULT%xxx
ECHO !RESULT!xxx
剥离不需要的回车的一种方便方法是使用额外的FOR级别。
@echo off
setlocal enableDelayedExpansion
FOR /F "tokens=2 delims==" %%I IN (
'wmic datafile where "name='C:\\Program Files (x86)\\Common Files\\Company\\Product\\Version12\\Product.exe'" get version /format:list'
) DO FOR /F "delims=" %%A IN ("%%I") DO SET "RESULT=%%A"
ECHO %RESULT%xxx
ECHO !RESULT!xxx
答案 1 :(得分:3)
这是我在自己的软件更新批处理脚本中使用的子程序:
:getfattr
set %1=
setlocal
set "name=%~f2"
set "name=%name:\=\\%"
for /f "delims=" %%A in ('wmic datafile where "name='%name:'=\'%'" get %1 /format:list') do @^
for /f "delims=" %%B in ("%%A") do endlocal & set "%%B" & goto :eof
echo>&2 getfattr failed
endlocal
goto :eof
它可以获得wmic datafile get
支持的任何文件属性。例如,以下是如何获取当前安装的Adobe Reader的文件版本:
call :getfattr version "%ProgramFiles(x86)%\Adobe\Reader 11.0\Reader\AcroRd32.exe"
echo "!version!"
执行此操作后,环境变量version
将包含请求的版本字符串。如果:getfattr
失败,则保证version
未设置。
该示例的测试执行跟踪如下所示(已启用延迟扩展,但不会假设:getfattr):
>call :getfattr version "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe"
>set version=
>setlocal
>set "name=C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe"
>set "name=C:\\Program Files (x86)\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe"
>for /F "delims=" %A in ('wmic datafile where "name='C:\\Program Files (x86)\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe'" get version /format:list') do @for /F "delims=" %B in ("%A") do endlocal & set "%B" & goto :eof
>endlocal & set "Version=11.0.18.21" & goto :eof
>echo "!version!"
"11.0.18.21"
正如你所看到的,它非常直接,并且不会太过分。但是,它却悄悄穿过cmd
和wmic
陷阱的雷区。
首先,您要获取的属性的名称也是您希望结果在(上面的测试中为version
)的变量所使用的名称。在子例程中,该名称为%1
,因此set %1=
将其清除。
您传入的文件名需要进行一些预处理才能安全地传递给wmic
并且需要一个shell变量,因此发出setlocal
以避免重写调用者的变量。 / p>
set "name=%~f2"
在剥离任何周围的双引号并将其扩展为完整路径名后,将名称复制到环境变量中。双引号括起整个set
参数,以防止路径名中的&符号或括号引起的悲伤。
wmic
查询使用类似SQL的语法,其中字符串值由单引号'
字符包围,\
是一个转义符,用于抑制后续字符的任何特殊含义。由于这两者在Windows路径名中都是合法的,因此所有出现的都需要\
前缀。 set "name=%name:\=\\%"
转义嵌入的反斜杠,'%name:'=\'%'
命令行中的wmic
构造转义嵌入的单引号,并添加所需的周围引号。
cmd
的解析器不会关闭单引号之间的特殊处理,并且名称不再包含任何周围的双引号,因此嵌入的空格,括号或符号可能会破坏事物。为了防范这种情况,wmic
的整个name=
参数被双重引用。名称中已经不需要对双引号进行特殊处理,因为Windows文件名中禁止使用双引号 ,因此不能有任何。
包含for
命令的wmic
命令行以@^
序列结束。 ^
用于附加下一行作为外for
命令的有效负载;即使ECHO处于打开状态,@
也会阻止有效负载在执行跟踪中回显。
回声抑制主要是因为内部for
的存在只是为了摆脱由cmd
将wmic
的输出从Unicode转换为for
所引入的虚假CR字符ASCII(与@ dbenham的答案中使用的技术相同)并且如果允许回声,那些CR只会因为混乱的覆盖而污染了跟踪。作为附带好处,当内部for
从外部wmic
传递的行仅包含 CR时,内部for
将不会执行自己的有效内容,这是一个与版本相关的数字其中for
坚持要发光。如果启用了ECHO,则内部cmd
的有效负载会回显,因此跟踪仍会捕获所有有用的事件。
该有效负载由三个& -separated命令组成,set "%%B"
将在endlocal
处理各个命令之前作为单个命令行扩展。特别是,这意味着set
在setlocal
运行之前展开,这会将endlocal
创建的变量置于%%B
/ /format:list
范围之外并使其成为可能可供来电者使用。
wmic
切换传递给get
, set
将始终以 name = value 格式展开;该名称将与& goto :eof
动词指定的名称相同,这就是您传递的名称最终选择您获得的变量的方式。如果请求的属性包含shell特殊字符,则引用for
的整个 name = value 参数。这使得:getfattr本身安全,但你可能想要使用!延迟!扩展而不是%premature%扩展,只要你实际使用它交给你的变量。
同一行上的wmic get
从两个wmic
循环中断,并在内部实际执行任何操作后立即返回:getfattr的调用者,以防您传入一些奇怪的名称和{{ 1}}产生多个非空行输出。
如果{{1}}根本没有产生任何输出,那么最后三行只会运行,这就是它失败时会发生的情况。
答案 2 :(得分:0)
这是我的档案文件。
@echo off
If "%~1"=="" goto help
If "%~1"=="/?" goto help
If /i "%~1"=="/h" goto help
If "%~1"=="-?" goto help
If /i "%~1"=="-h" goto help
set filepath=%~f1
set file=%filepath:\=\\%
wmic datafile where name^="%file%" get version|findstr /i /v /c:"version"
echo %errorlevel%
goto finish
:help
Echo.
Echo. FileVer
Echo. -------
Echo.
Echo. Purpose:
Echo.
Echo. Reports the version number for an exe, dll, and similar files.
Echo.
Echo. Usage:
Echo.
Echo. filever ^<executable file^>
Echo.
Echo. filever [/h ^| -h ^| /? ^| -?] Starts this help
Echo.
echo. Examples:
Echo.
Echo. filever c:\windows\explorer.exe
Echo. filever "C:\Program Files\Windows NT\Accessories\wordpad.exe"
Echo. filever shell32.dll
Echo.
Echo. For Help
Echo.
Echo. filever
Echo. filever /?
Echo.
:finish
rem Pause if command double clicked
If /i "%cmdcmdline:~0,6%"=="cmd /c" pause
您似乎在整个命令
周围有一组额外的引号for循环的一个问题是它会在版本之后输出一个空行。
set filepath=%~f1
set file=%filepath:\=\\%
for /f "tokens=1 eol= " %%A in ('wmic datafile where name^="%file%" get version^|findstr /i /v /c:"version"') do set a=%%A & echo %%A
把它放在一个文件中。虽然该文件有两个空行。
set filepath=%~f1
set file=%filepath:\=\\%
wmic datafile where name^="%file%" get version|findstr /i /v /c:"version">test.txt
也许这可以起作用
set filepath=%~f1
set file=%filepath:\=\\%
for /f "tokens=1 eol= " %%A in ('wmic datafile where name^="%file%" get version^|findstr /i /v /c:"version"') do if not ""==%%A set a=%%A & echo %%A
或者拨打另一个批处理文件,不要返回。
这是一种解决空白行的方法。
set filepath=%~f1
set file=%filepath:\=\\%
for /f "tokens=1 eol= " %%A in ('wmic datafile where name^="%file%" get version^|findstr /i /v /c:"version"^|findstr /i /v /r "^$"') do set a=%%A & echo %A%
wmic datafile where name^="%file%" get version|findstr /i /v /c:"version"|findstr /i /v /r "^$">test.txt
答案 3 :(得分:0)
这是另一种方法,为powershell Get-WmiObject绕过WMIC。
@ECHO OFF
start /b powershell.exe -command "Get-WmiObject -Class CIM_DataFile -Filter \"Name='C:\\Program Files (x86)\\Knuckle.dll'\" | Select-Object Version"
PAUSE
双击.cmd批处理文件时返回此结果。
Version
-------
0.0.0.0
答案 4 :(得分:0)
以及没有外部工具的两种方式 1.的 WMIC 强>
WMIC DATAFILE WHERE name="C:\\install.exe" get Version /format:Textvaluelist
注意文件名的双斜杠。
2的 MAKECAB 强> 因为WMIC没有安装在家庭版本的Windows上,所以makecab将在每台Windows机器上运行:
; @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*"
示例输出(它有一个字符串版本,这是对wmic方法的一个小补充:)):
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 使用 shell.application 和杂交批处理\ jscript.Here 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();
用于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