@echo off setlocal ENABLEDELAYEDEXPANSION rem Use real applications or testing stub for testing set MSIEXEC=msiexec set WMIC=wmic set CSCRIPT=cscript if not "%CFENGINE_MSIEXEC_TEST%"=="" ( set MSIEXEC=%CFENGINE_MSIEXEC_TEST% msiexec set WMIC=%CFENGINE_MSIEXEC_TEST% wmic set CSCRIPT=%CFENGINE_MSIEXEC_TEST% cscript ) rem choose a function to execute if "%1"=="supports-api-version" echo 1 if "%1"=="get-package-data" goto :get_package_data_list if "%1"=="list-installed" goto :list_installed if "%1"=="list-updates" rem not implemented if "%1"=="list-updates-local" rem not implemented if "%1"=="repo-install" rem not implemented if "%1"=="file-install" goto :file_install_list if "%1"=="remove" goto :remove_list goto :EOF rem Reads all stdin lines, for each line which starts with rem "File=" call the next function :get_package_data_list for /F "tokens=*" %%a in ('more') do ( rem Assign for-loop %%a variable to "normal" %_q% variable to extract substrings rem via %name:~begin,length% expansion (negative value means length of string - value) set "_q=%%a" rem * Use "Delayed Expansion" of variables (surround them with ! instead of %) if "!_q:~0,5!"=="File=" call :get_package_data_one "!_q:~5!" ) goto :EOF rem Choose one of two following functions to call based on whether file exists or not :get_package_data_one rem This function called with an argument in quotes, so: rem use %1 when you need value in quotes, rem use %~1 when you need without if not exist %1 call :get_package_data_repo %1 if exist %1 call :get_package_data_file %1 goto :EOF rem Print package information for an existing file :get_package_data_file echo PackageType=file rem %~dp0 expands to drive and path of current script rem TODO: if name is multi-line, print "Name=" only once for /f "usebackq delims=" %%b in (`%CSCRIPT% /nologo "%~dp0\WiRunSQL.vbs" %1 "select Value from Property where Property = 'ProductName'"` ) do echo Name=%%b for /f "usebackq delims=" %%b in (`%CSCRIPT% /nologo "%~dp0\WiRunSQL.vbs" %1 "select Value from Property where Property = 'ProductVersion'"` ) do echo Version=%%b goto :EOF rem If file does not exist - assume it's a repo :get_package_data_repo echo PackageType=repo echo Name=%~1 goto :EOF rem Call vbs script to read installed software from registry :list_installed %CSCRIPT% /nologo "%~dp0\msiexec-list.vbs" goto :EOF rem Reads all stdin lines, for each line which starts with "File=" call the next function :file_install_list for /F "tokens=*" %%a in ('more') do ( set "_q=%%a" if "!_q:~0,5!"=="File=" call :file_install_one "!_q:~5!" ) goto :EOF rem Install this file if it exists :file_install_one if not exist %1 ( echo ErrorMessage=File %1 not found! goto :EOF ) set log_dir="\cfengine_package_logs\" if not exist %log_dir% ( mkdir %log_dir% ) for /F "delims=" %%i in (%1) do @set basename="%%~ni" REM %log_dir:"=% replaces quotes with nothing, otherwise you get two double-quotes which causes failures set log_file="%log_dir:"=%%basename:"=%_install.log" %MSIEXEC% /quiet /passive /qn /norestart /l*vx %log_file% /i %1 if not errorlevel 0 ( echo ErrorMessage=msiexec.exe ErrorLevel was %ErrorLevel% for file %1 log at %log_file% ) goto :EOF rem Reads all stdin lines, calls next function for each of them :remove_list for /F "tokens=*" %%a in ('more') do ( call :remove_line "%%a" ) call :remove_one goto :EOF rem processes line of input, saves name and version, and calls rem next function before new block (which starts with "Name=" line) :remove_line set "_q=%~1" if "%_q:~0,5%"=="Name=" ( call :remove_one set "_name=%_q:~5%" set _ver= ) if "%_q:~0,8%"=="Version=" ( set "_ver=%_q:~8%" ) goto :EOF rem Remove file or software stored in "%_name%" env variable, if it's set. rem If such file does not exist - remove an installed program with such name :remove_one if "%_name%"=="" goto :EOF if exist "%_name%" ( call :remove_file "%_name%" goto :EOF ) if "%_ver%"=="" ( set "_condition=name='%_name%'" ) else ( set "_condition=name='%_name%' and version='%_ver%'" ) rem Characters > and & chars in for expression must be escaped for /f "delims=" %%a in ( '%WMIC% product where "%_condition%" get LocalPackage /value 2^>^&1' ) do ( set "_q=%%a" if "!_q:~0,13!"=="LocalPackage=" call :remove_file "!_q:~13!" ) goto :EOF rem Remove software from MSI package which name is passed as argument :remove_file %MSIEXEC% /quiet /passive /qn /norestart /x %1 rem TODO options, error checking goto :EOF