Узнать версию установленной программы из пакетного файла
у нас есть пакетный файл, который устанавливает несколько программ в рамках установки разработчиков. Это выполняется периодически, когда мы получаем новые версии используемых компонентов. Поэтому было бы неплохо установить, если версии разные.
в командной строке я могу запустить это и вернуть установленную версию:
wmic datafile where name='C:Program Files (x86)Common FilesCompanyProductVersion12Product.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 FilesCompanyProductVersion12Product.exe" get version /format:list"') DO (SET "RESULT=%%I")
ECHO %RESULT%
Я получаю ответ Common was unexpected at this time.
некоторые части могут быть избыточными, поскольку я пробовал вещи из сети, чтобы исправить это.
что я пропустила?
5 ответов
у вас есть набор неуместных двойных кавычек, а также дополнительный (
.
WMIC использует синтаксис SQL, а строки заключены в одинарные кавычки.Внутренние одинарные кавычки не мешают команде, заключающей одинарные кавычки.
вы можете поместить двойные кавычки вокруг предложения WHERE (не включая ключевое слово WHERE), чтобы избежать некоторых проблем с escape в предложении 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%
но это может быть не совсем все решение. Ты не видишь этого. с вышеуказанным кодом, но результат фактически содержит возврат завершающей каретки (0x0D). Это связано с причудой с тем, как FOR /F обрабатывает вывод wmic unicode. Каждая строка вывода WMIC будет иметь дополнительный возврат трейлинг-каретки.
пока вы всегда получаете доступ к результату с помощью %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
вот подпрограмма, которую я использую для этого в моем собственном пакетном скрипте обновления программного обеспечения:
: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
гарантированно будет unset.
трассировка выполнения теста для этого пример выглядит так (отложенное расширение уже включено, хотя это не предполагается :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
и для этого требуется переменная оболочки, поэтому setlocal
выдается, чтобы избежать топтания переменных вызывающего абонента.
set "name=%~f2"
копирует имя в переменную среды после удаления всех окружающих двойных кавычек и расширения его до полного пути. Двойные кавычки окружают весь set
аргумент для предотвращения горя, вызванного амперсандами или круглые скобки в именах путей.
wmic
запросы используют SQL-подобный синтаксис, где строковые значения окружены одинарной кавычкой '
символы и \
- это побег, который подавляет любое особое значение следующего символа. Поскольку оба они являются законными в именах путей Windows, все вхождения либо нуждаются в \
префикс. set "name=%name:\=\%"
escapes встроенные обратные косые черты и '%name:'=\'%'
построить в wmic
командная строка экранирует встроенные одинарные кавычки и добавляет требуются окружающие.
cmd
парсер не отключает специальную обработку между одинарными кавычками, и имя больше не имеет никаких окружающих двойных кавычек, поэтому встроенные пробелы, круглые скобки или амперсанды могут потенциально нарушать вещи. Чтобы защититься от этого, wmic
всю name=
аргумент получает двойную кавычку. Нет необходимости в специальной обработке для двойных кавычек уже внутри имени, потому что двойные кавычки are запрещено в именах файлов Windows так их не может быть.
на for
командная строка, содержащая заканчивается @^
последовательности. The ^
служит для присоединения следующей строки в качестве полезной нагрузки внешнего ; С @
предотвращает эхо этой полезной нагрузки в трассировке выполнения, даже если Эхо включено.
это подавление Эха делается главным образом потому, что внутреннее for
существует только для того, чтобы избавиться от ложных символов CR, введенных cmd
багги преобразование wmic
вывод из Unicode в ASCII (тот же метод, что и в ответе @dbenham), и если разрешено Эхо, эти CRs просто загрязняют трассировку с запутанными перезаписями. Как побочное преимущество, внутреннее for
не будет выполнять свою собственную полезную нагрузку, когда линия передана из внешнего for
содержит только CR, зависящий от версии номер которого wmic
настаивает на ИСП. Внутреннее for
С нагрузкой тут получить Эхо, если Эхо включено, поэтому трассировка все еще захватывает все полезные события.
что груз состоит из трех разделенных команд, которые for
будет расширяться как одна командная строка перед cmd
получает для обработки отдельных команд. В частности, это означает, что set "%%B"
расширяется до endlocal
выполняется, что ставит переменную, созданную этим set
за пределами setlocal
/endlocal
объем и делает его доступным для абонента.
%%B
всегда будет расширяться в формате name=value из-за /format:list
переключатель перешел в wmic
; имя будет таким же, как указано в get
глагол, и вот как имя, которое вы передаете, в конечном итоге выбирает переменную, которую вы возвращаете. Весь name=value до set
цитируется в случае, если запрошенный атрибут содержит специальные символы оболочки. Это делает: getfattr безопасным, но вы можете использовать !отложено! расширение, а не % преждевременное % расширение везде, где вы на самом деле используйте переменную, которую он возвращает вам.
на & goto :eof
на этой же строке разрывается от обоих for
петли и возвращается к: вызывающий getfattr, как только внутренний на самом деле что-то делает, на случай, если вы передадите какое-то странное имя и wmic get
производит больше чем одну non-пустую линию выхода.
последние три строки только когда-либо работать, если wmic
не производит никакого вывода вообще, что и происходит, когда он терпит неудачу.
Это мой файл filever bat.
@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-это wmic outpus пустая строка после версии.
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
вот альтернативный метод, обходит WMIC для powershell Get-WmiObject.
@ECHO OFF
start /b powershell.exe -command "Get-WmiObject -Class CIM_DataFile -Filter \"Name='C:\Program Files (x86)\Knuckle.dll'\" | Select-Object Version"
PAUSE
возвращает этот результат при двойном щелчке a .пакетный файл cmd.
Version
-------
0.0.0.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.применение и гибридный пакет\jscript.Вот!--6-->tooptipInfo.летучая мышь!--7--> :
@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