Nous avons un fichier de commandes qui installe plusieurs programmes dans le cadre de l’installation des développeurs. Ceci est exécuté périodiquement lorsque nous obtenons de nouvelles versions des composants utilisés. Donc, ce serait bien d'installer seulement si les versions sont différentes.
À l'invite de commande, je peux l'exécuter et récupérer la version installée:
wmic datafile where name='C:\\Program Files (x86)\\Common Files\\Company\\Product\\Version12\\Product.exe' get version /format:list
Ce qui donne le Version=12.1.369.0
en sortie.
Cependant, lorsque je mets cela dans un fichier de commandes comme celui-ci et que je tente d'extraire la version:
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%
Je reçois la réponse \\Common was unexpected at this time.
Certaines parties peuvent être redondantes, car j’ai essayé d’essayer sur Internet pour corriger cela.
Qu'est-ce que j'ai manqué?
Vous avez un ensemble de guillemets doubles égarés, ainsi qu'un (
supplémentaire.
WMIC utilise la syntaxe SQL et les chaînes sont entre guillemets simples. Les guillemets simples internes n'interfèrent pas avec la commande qui entoure les guillemets simples.
Vous pouvez mettre des guillemets autour de la clause WHERE (sans le mot clé WHERE) pour éviter certains problèmes d'échappement au sein de la clause 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%
Mais ce n'est peut-être pas tout à fait la solution. Vous ne pouvez pas le voir avec le code ci-dessus, mais RESULT contient en réalité un retour chariot final (0x0D). Cela est dû à un hasard avec la façon dont FOR/F gère la sortie WMIC unicode. Chaque ligne de sortie WMIC aura le retour supplémentaire par chariot.
Tant que vous accédez toujours à RESULT en utilisant %RESULT%
(expansion normale), vous n'aurez aucun problème. Mais si vous avez besoin d'une expansion retardée, vous pouvez avoir des problèmes, comme illustré ci-dessous.
@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
Une méthode pratique pour éliminer le retour de chariot indésirable consiste à utiliser un niveau supplémentaire de 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
Voici le sous-programme que j'utilise pour cela dans mon propre script de traitement par lots de mises à jour logicielles:
: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
Il peut obtenir n'importe quel attribut de fichier pris en charge par wmic datafile get
. Par exemple, voici comment vous pouvez obtenir la version du fichier pour Adobe Reader actuellement installé:
call :getfattr version "%ProgramFiles(x86)%\Adobe\Reader 11.0\Reader\AcroRd32.exe"
echo "!version!"
Après cela, la variable d’environnement version
contiendra la chaîne de version demandée. Si :getfattr
échoue, il est garanti que version
sera inactif.
Une trace d'exécution de test pour cet exemple ressemble à ceci (le développement différé était déjà activé, bien que cela ne soit pas supposé par: 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"
Comme vous pouvez le constater, c’est assez direct et ça ne dérange pas trop. Cependant, il parcourt la zone de mines de cmd
et wmic
pièges.
Premièrement, le nom de l'attribut que vous voulez obtenir est également le nom utilisé pour la variable dans laquelle vous voulez que le résultat aboutisse (version
dans le test ci-dessus). Dans la sous-routine, ce nom est %1
, donc set %1=
l'efface.
Le nom de fichier que vous transmettez a besoin d'un peu de prétraitement avant de pouvoir être remis en toute sécurité à wmic
et une variable Shell est nécessaire à cet effet. Par conséquent, setlocal
est émis pour éviter de piétiner les variables de l'appelant.
set "name=%~f2"
copie le nom dans une variable d’environnement après avoir enlevé les guillemets et les avoir étendus à un chemin complet. Les guillemets doubles entourent tout l'argument set
pour éviter les problèmes causés par les esperluettes ou les parenthèses dans les noms de chemin.
Les requêtes wmic
utilisent une syntaxe de type SQL, dans laquelle les valeurs de chaîne sont entourées de guillemets simples '
et \
est un d'échappement qui supprime toute signification spéciale du caractère suivant. Comme ces deux noms sont légaux dans les chemins d'accès Windows, toutes les occurrences de l'un ou de l'autre ont besoin d'un préfixe \
. set "name=%name:\=\\%"
échappe aux barres obliques inverses incorporées et la construction '%name:'=\'%'
dans la ligne de commande wmic
échappe aux guillemets simples incorporés et ajoute les guillemets requis.
L’analyseur de cmd
n’active pas le traitement spécial entre guillemets simples et le nom ne comporte plus de guillemets, ce qui permet aux espaces, parenthèses ou esperluettes incorporés de se casser. Pour se prémunir contre cela, la totalité de l'argument name=
de wmic
est citée en double. Il n'y a pas besoin de traitement spécial pour les guillemets doubles déjà dans le nom, car les guillemets are sont interdits dans les noms de fichiers Windows, de sorte qu'il ne peut en exister aucun.
La ligne de commande for
contenant la commande wmic
se termine par une séquence @^
. Le ^
sert à attacher la ligne suivante comme charge utile de la commande externe for
; le @
empêche que l'échec de la charge utile dans une trace d'exécution, même si ECHO est activé.
Cette suppression d’écho est effectuée principalement parce que la variable for
intérieure n’existe que pour éliminer les caractères CR parasites injectés par la conversion boguée de cmd
de la sortie de wmic
de Unicode en ASCII (même technique que celle utilisée dans la réponse de @ dbenham) pour faire écho, ces CR juste salir la trace avec écrasements déroutants. En plus, for
interne n'exécutera pas sa propre charge lorsque la ligne for
externe contenue contient seulement un CR, un nombre dépendant de la version dont wmic
insiste pour émettre. La charge utile do de for
intérieur est répercutée si ECHO est activé, donc le traçage capture toujours tous les événements utiles.
Cette charge se compose de trois commandes séparées, que for
développera comme une seule ligne de commande avant que cmd
puisse traiter les commandes individuelles. Cela signifie notamment que set "%%B"
est développé avant l'exécution de endlocal
, ce qui place la variable créée par ce set
en dehors de la portée setlocal
/endlocal
et la met à la disposition de l'appelant.
%%B
sera toujours développé au format name = valeur à cause du commutateur /format:list
passé à wmic
; le nom sera le même que celui spécifié avec le verbe get
, et c'est ainsi que le nom que vous transmettez finit par choisir la variable que vous récupérez. L'ensemble de l'argument name = value de set
est cité au cas où l'attribut demandé contient des caractères spéciaux du shell. Cela rend: getfattr lui-même sûr, mais vous voudrez peut-être utiliser! Différé! expansion plutôt que% prématurée% où que vous utilisiez réellement la variable qu’elle vous remet.
Le & goto :eof
sur cette même ligne rompt les deux boucles for
et retourne à l'appelant de: getfattr dès que la boucle intérieure fait réellement quoi que ce soit, juste au cas où vous transmettriez un nom étrange et que wmic get
produirait plus d'une ligne non vierge.
Les trois dernières lignes ne sont exécutées que si wmic
ne produit aucune sortie, ce qui se produit en cas d'échec.
Ceci est mon fichier bat 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
Vous semblez avoir un ensemble supplémentaire de citations autour de la commande entière
Un problème avec les boucles for est qu’il dépasse une ligne vierge après la version.
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
Mettez-le dans un fichier. Bien que le fichier comporte deux lignes vides.
set filepath=%~f1
set file=%filepath:\=\\%
wmic datafile where name^="%file%" get version|findstr /i /v /c:"version">test.txt
Peut-être que cela pourrait fonctionner
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
Ou appelez un autre fichier de commandes et ne revenez pas.
Voici un moyen de récupérer des lignes vierges.
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
Voici une méthode alternative, contourne WMIC pour 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
Renvoie ce résultat lorsque vous double-cliquez sur un fichier de commandes .cmd.
Version
-------
0.0.0.0
et deux manières sans outils externes 1.WMIC
WMIC DATAFILE WHERE name="C:\\install.exe" get Version /format:Textvaluelist
Faites attention aux doubles barres obliques du nom du fichier.
2.MAKECABle WMIC n'étant pas installé sur les versions domestiques de Windows, voici un moyen d'utiliser makecab qui fonctionnera sur toutes les machines 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*"
exemple de sortie (il a une version chaîne qui est un petit ajout à la méthode 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 Utilisation de Shell.application et lot hybride\jscript.Here's 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();
utilisé contre 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