1@echo off 2setlocal ENABLEDELAYEDEXPANSION 3 4rem Use real applications or testing stub for testing 5 6set MSIEXEC=msiexec 7set WMIC=wmic 8set CSCRIPT=cscript 9 10if not "%CFENGINE_MSIEXEC_TEST%"=="" ( 11 set MSIEXEC=%CFENGINE_MSIEXEC_TEST% msiexec 12 set WMIC=%CFENGINE_MSIEXEC_TEST% wmic 13 set CSCRIPT=%CFENGINE_MSIEXEC_TEST% cscript 14) 15 16rem choose a function to execute 17 18if "%1"=="supports-api-version" echo 1 19if "%1"=="get-package-data" goto :get_package_data_list 20if "%1"=="list-installed" goto :list_installed 21if "%1"=="list-updates" rem not implemented 22if "%1"=="list-updates-local" rem not implemented 23if "%1"=="repo-install" rem not implemented 24if "%1"=="file-install" goto :file_install_list 25if "%1"=="remove" goto :remove_list 26 27goto :EOF 28 29 30 31rem Reads all stdin lines, for each line which starts with 32rem "File=" call the next function 33:get_package_data_list 34 for /F "tokens=*" %%a in ('more') do ( 35 rem Assign for-loop %%a variable to "normal" %_q% variable to extract substrings 36 rem via %name:~begin,length% expansion (negative value means length of string - value) 37 set "_q=%%a" 38 rem * Use "Delayed Expansion" of variables (surround them with ! instead of %) 39 if "!_q:~0,5!"=="File=" call :get_package_data_one "!_q:~5!" 40 ) 41goto :EOF 42 43 44rem Choose one of two following functions to call based on whether file exists or not 45:get_package_data_one 46 rem This function called with an argument in quotes, so: 47 rem use %1 when you need value in quotes, 48 rem use %~1 when you need without 49 if not exist %1 call :get_package_data_repo %1 50 if exist %1 call :get_package_data_file %1 51goto :EOF 52 53 54rem Print package information for an existing file 55:get_package_data_file 56 echo PackageType=file 57 rem %~dp0 expands to drive and path of current script 58 rem TODO: if name is multi-line, print "Name=" only once 59 for /f "usebackq delims=" %%b in (`%CSCRIPT% /nologo "%~dp0\WiRunSQL.vbs" %1 60 "select Value from Property where Property = 'ProductName'"` 61 ) do echo Name=%%b 62 for /f "usebackq delims=" %%b in (`%CSCRIPT% /nologo "%~dp0\WiRunSQL.vbs" %1 63 "select Value from Property where Property = 'ProductVersion'"` 64 ) do echo Version=%%b 65goto :EOF 66 67 68rem If file does not exist - assume it's a repo 69:get_package_data_repo 70 echo PackageType=repo 71 echo Name=%~1 72goto :EOF 73 74 75 76rem Call vbs script to read installed software from registry 77:list_installed 78 %CSCRIPT% /nologo "%~dp0\msiexec-list.vbs" 79goto :EOF 80 81 82 83rem Reads all stdin lines, for each line which starts with "File=" call the next function 84:file_install_list 85 for /F "tokens=*" %%a in ('more') do ( 86 set "_q=%%a" 87 if "!_q:~0,5!"=="File=" call :file_install_one "!_q:~5!" 88 ) 89goto :EOF 90 91 92rem Install this file if it exists 93:file_install_one 94 if not exist %1 ( 95 echo ErrorMessage=File %1 not found! 96 goto :EOF 97 ) 98 99 set log_dir="\cfengine_package_logs\" 100 if not exist %log_dir% ( 101 mkdir %log_dir% 102 ) 103 for /F "delims=" %%i in (%1) do @set basename="%%~ni" 104 REM %log_dir:"=% replaces quotes with nothing, otherwise you get two double-quotes which causes failures 105 set log_file="%log_dir:"=%%basename:"=%_install.log" 106 %MSIEXEC% /quiet /passive /qn /norestart /l*vx %log_file% /i %1 107 if not errorlevel 0 ( 108 echo ErrorMessage=msiexec.exe ErrorLevel was %ErrorLevel% for file %1 log at %log_file% 109 ) 110goto :EOF 111 112 113 114rem Reads all stdin lines, calls next function for each of them 115:remove_list 116 for /F "tokens=*" %%a in ('more') do ( 117 call :remove_line "%%a" 118 ) 119 call :remove_one 120goto :EOF 121 122 123rem processes line of input, saves name and version, and calls 124rem next function before new block (which starts with "Name=" line) 125:remove_line 126 set "_q=%~1" 127 if "%_q:~0,5%"=="Name=" ( 128 call :remove_one 129 set "_name=%_q:~5%" 130 set _ver= 131 ) 132 133 if "%_q:~0,8%"=="Version=" ( 134 set "_ver=%_q:~8%" 135 ) 136goto :EOF 137 138 139rem Remove file or software stored in "%_name%" env variable, if it's set. 140rem If such file does not exist - remove an installed program with such name 141:remove_one 142 if "%_name%"=="" goto :EOF 143 144 if exist "%_name%" ( 145 call :remove_file "%_name%" 146 goto :EOF 147 ) 148 149 if "%_ver%"=="" ( 150 set "_condition=name='%_name%'" 151 ) else ( 152 set "_condition=name='%_name%' and version='%_ver%'" 153 ) 154 155 rem Characters > and & chars in for expression must be escaped 156 for /f "delims=" %%a in ( 157 '%WMIC% product where "%_condition%" get LocalPackage /value 2^>^&1' 158 ) do ( 159 set "_q=%%a" 160 if "!_q:~0,13!"=="LocalPackage=" call :remove_file "!_q:~13!" 161 ) 162goto :EOF 163 164 165rem Remove software from MSI package which name is passed as argument 166:remove_file 167 %MSIEXEC% /quiet /passive /qn /norestart /x %1 168 rem TODO options, error checking 169goto :EOF 170