1 (изменено: Rumata, 2021-10-19 20:47:17)

Тема: CMD/JS: msiprobe скрипт проверки и распаковки MSI файлов

msiexec стандартная утилита для установки/удаления приложений из MSI-файлов. У ней есть различные опции, в частности для распаковки файлов. Иногда может быть полезно.

Написал гибридный CMD/JS скрипт для проверки и распаковки MSI-файлов.

Примеры использования.

Посмотреть информацию о файле


msiprobe filename.msi /property

Посмотреть содержимое файла


msiprobe filename.msi /list

распаковать файл в некоторый каталог


msiprobe filename.msi C:\TEMP\zzz
+ исходный код

Актуальная версия лежит здесь


0</*! ::

::Probe and unpack a MSI file.
::
::Usage:
::    msiprobe msi-file /LIST
::    msiprobe msi-file /PROPERTY
::    msiprobe msi-file target-dir

@echo off

if /i "%~2" == "" (
	for /f "usebackq tokens=* delims=:" %%s in ( "%~f0" ) do (
		if /i "%%s" == "@echo off" goto :EOF
		if not "%%s" == "0</*! ::" echo:%%s
	)
	goto :EOF
)

for %%o in ( LIST PROPERTY ) do if /i "%~2" == "/%%~o" (
	cscript //nologo //e:javascript "%~f0" %*
	goto :EOF
)

echo:Executing...
echo:msiexec /quiet /a "%~f1" TARGETDIR="%~f2"
call msiexec /quiet /a "%~f1" TARGETDIR="%~f2"

goto :EOF
*/0;

// ========================================================================

try {
	var msiFile = WScript.Arguments.item(0);
	var mode = WScript.Arguments.item(1);
	var msiInfo =
		mode.match(/^\/LIST$/i) ? getMsiListing(msiFile) :
		mode.match(/^\/PROPERTY$/i) ? getMsiProperty(msiFile) :
		'/LIST or /PROPERTY required';
	WScript.StdOut.WriteLine(msiInfo);
} catch(e) {
	WScript.StdErr.WriteLine('Cannot probe file: ' + msiFile);
	WScript.StdErr.WriteLine('Error: ' + e.message);
	WScript.Quit(1);
}

// ========================================================================

// JS code was adapted from VBS implementation found by these links:
// https://serverfault.com/a/465717/423234
// http://scriptbox.toll.at/index.php?showcontent=Get%20MSI-File%20properties.vbs&list=1
// https://www.hanselman.com/blog/how-to-list-all-the-files-in-an-msi-installer-using-vbsciript

function getMsiListing(filename) {
	return getMsiView(filename, {
		sql: 'Select FileSize, FileName From File',
		header: 'FileSize FileName'.split(' '),
		align: function(value, width, padding) {
			return ( padding + value ).slice(-width);
		}
	});
}

function getMsiProperty(filename) {
	return getMsiView(filename, {
		sql: 'Select * From Property',
		header: 'Property Value'.split(' '),
		align: function(value, width, padding) {
			return ( value + padding ).slice(0, width);
		}
	});
}

function getMsiView(filename, options) {
	var installer = new ActiveXObject('WindowsInstaller.Installer');
	var installerDatabase = installer.OpenDatabase(filename, 0);
	var installerView = installerDatabase.OpenView(options.sql);
	installerView.Execute();

	var installerRecord;

	var r = [];
	var maxLen = 0;

	while ( installerRecord = installerView.Fetch() ) {
		var n = installerRecord.FieldCount;
		var s = [];
		for (var i = 1; i <= n; i++) {
			s.push(installerRecord.StringData(i));
		}
		maxLen = Math.max(maxLen, s[0].length);
		r.push(s);
	}

	var padding = new Array(maxLen + 1).join(' ');

	r.unshift(options.header);

	for (var i = 0; i < r.length; i++) {
		r[i][0] = options.align(r[i][0], maxLen, padding);
		r[i] = r[i].join(' : ');
	}

	return r.join('\n');
}

// ========================================================================

// EOF

Близкое по содержанию обсуждение уже поднималось мной же здесь: Распаковка (не инсталляция) MSI файлов

( 2 * b ) || ! ( 2 * b )

2

Re: CMD/JS: msiprobe скрипт проверки и распаковки MSI файлов

Изменения:
-- переписал вывод справки
-- избавился от повторяющихся кусков кода в JS
-- упростил вызов в BATCH-части

( 2 * b ) || ! ( 2 * b )