@naimi/alib
Version:
544 lines (503 loc) • 18.1 kB
JavaScript
/**
* WARNING: since version 1.23 this script is deprecated and should not be used.
*
* This script is available since version 1.10.
*
* This library contains useful code for installing and removing software.
* Since version 1.20 of the Installer Helper the preferred way to run
* a JScript file is to use the "ExecJS.bat".
*
* This library can be used alternatively
* via cscript.exe e.g. from .Npackd\Install.bat:
* cscript //Nologo //E:JScript //T:300 //U .Npackd\Install.js
*
* ...and in the Install.js script The environment variable "NIH" below
* should point to a valid directory with Installer Helper:
*
* try {
* var fs = new ActiveXObject("Scripting.FileSystemObject");
* var sh = WScript.CreateObject("WScript.Shell");
* var lib = eval(fs.OpenTextFile(
* sh.ExpandEnvironmentStrings("%NIH%") + "\\Lib.js", 1).ReadAll());
* lib.installerHelper = sh.ExpandEnvironmentStrings("%NIH%");
*
* lib.sendKeysToWindow("NetSurf - NetSurf Uninstall", "{ENTER}");
* } catch (e) {
* WScript.Echo(e.name + ": " + e.message);
* WScript.Echo(e.number + ": " + e.description);
* WScript.Quit(1);
* }
*/
lib = (function () {
var L = {/* library interface */};
/**
* Wait for the dialog with the specified title and emulates key press.
*
* @param title dialog title
* @param keys e.g. "{ENTER}". See WScript.SendKeys for more details
*/
L.sendKeysToWindow = function(title, keys) {
var sh = WScript.CreateObject("WScript.Shell");
var found = false;
for (var i = 0; i < 60; i++) {
WScript.Sleep(1000);
if (sh.AppActivate(title)) {
found = true;
break;
}
}
if (found) {
WScript.Sleep(10000);
sh.SendKeys(keys);
}
};
/**
* This function is available since 1.11.
*
* Adds a property to an .msi file.
*
* @param msi the name of the .msi file
* @param property the name of the property (e.g. APPDIR)
* @param value property value (e.g. C:\)
*/
L.addPropertyToMSI = function(msi, property, value) {
var installer = WScript.CreateObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(msi, 1);
var view = database.OpenView("INSERT INTO Property (Property, Value) VALUES ('" +
property + "', '" + value + "')");
view.Execute(null);
view.Close();
database.Commit();
};
/**
* This function is available since 1.12.
*
* Searches for a file in the specified directory using the specified regular
* expression.
*
* @param dir directory name. Use "." for the current directory.
* @param re regular expression for the file name. Example: /\.js$/i
* @return the found file name without the path or null
*/
L.findFile = function(dir, re) {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var f = fso.GetFolder(dir);
var fc = new Enumerator(f.files);
var result = null;
for (; !fc.atEnd(); fc.moveNext()) {
var file = fc.item();
if (file.name.match(re)) {
result = file.name;
break;
}
}
return result;
};
/**
* This function is available since 1.13.
*
* Searches for a directory in the specified directory using the specified regular
* expression.
*
* @param dir directory name. Use "." for the current directory.
* @param re regular expression for the file name. Example: /^KeePassX-/i
* @return the found file name without the path or null
*/
L.findDir = function(dir, re) {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var f = fso.GetFolder(dir);
var fc = new Enumerator(f.SubFolders);
var result = null;
for (; !fc.atEnd(); fc.moveNext()) {
var file = fc.item();
if (file.name.match(re)) {
result = file.name;
break;
}
}
return result;
};
/**
* This function is available since 1.12.
*
* Executes the specified command, prints its output. The stdout and stderr will
* be printed separately on the corresponding output streams of this process
* (cscript.exe).
*
* @param cmd this command should be executed
* @return [exit code, [stdout line 1, stdout line2, ...],
* [stderr line 1, stderr line2, ...]]
*/
L.exec = function(cmd) {
var shell = WScript.CreateObject("WScript.Shell");
var p = shell.exec(cmd);
var output = [];
var stderr = [];
var line;
while (true) {
var n = 0;
while (!p.StdOut.AtEndOfStream) {
line = p.StdOut.ReadLine();
WScript.StdOut.WriteLine(line);
output.push(line);
n++;
}
while (!p.StdErr.AtEndOfStream) {
line = p.StdErr.ReadLine();
WScript.StdErr.WriteLine(line);
stderr.push(line);
n++;
}
if (n === 0)
break;
}
return [p.ExitCode, output, stderr];
}
/**
* This function is available since 1.12.
*
* Installs an .msi package into the current directory.
*
* @param msi .msi file name or null if the first found .msi file in the current
* directory should be used.
* @param property the name of the MSI property that changes the installation
* directory. Example: "INSTALLLOCATION"
* @return true if the installation succeeded
*/
L.installMSI = function(msi, property) {
if (msi === null)
msi = L.findFile(".", /\.msi$/i);
var shell = WScript.CreateObject("WScript.Shell");
var curDir = shell.currentDirectory;
var fso = new ActiveXObject("Scripting.FileSystemObject");
var TemporaryFolder = 2;
var tfolder = fso.GetSpecialFolder(TemporaryFolder);
var tname = fso.BuildPath(tfolder.path, fso.GetTempName());
// MSIFASTINSTALL: http://msdn.microsoft.com/en-us/library/dd408005%28v=VS.85%29.aspx
var r = L.exec("msiexec.exe /qn /norestart " +
"/Lime \"" + tname + "\" " +
"/i \"" + msi + "\" " +
property + "=\"" + curDir + "\" ALLUSERS=1 MSIFASTINSTALL=7");
var result = L.exec("cmd.exe /d /c type \"" + tname + "\" 2>&1");
// list of errors: http://msdn.microsoft.com/en-us/library/windows/desktop/aa368542(v=vs.85).aspx
// 3010=restart required
return r[0] === 0 || r[0] === 3010;
};
/**
* This function is available since 1.12.
*
* Uninstalls an .msi package into the current directory.
*
* @param msi .msi file name or null if the first found .msi file in the current
* directory should be used.
* @return true if the installation succeeded
*/
L.uninstallMSI = function(msi) {
if (msi === null)
msi = L.findFile(".", /\.msi$/i);
var shell = WScript.CreateObject("WScript.Shell");
var curDir = shell.currentDirectory;
var fso = new ActiveXObject("Scripting.FileSystemObject");
var tfolder = fso.GetSpecialFolder(TemporaryFolder);
var TemporaryFolder = 2;
var tname = fso.BuildPath(tfolder.path, fso.GetTempName());
// MSIFASTINSTALL: http://msdn.microsoft.com/en-us/library/dd408005%28v=VS.85%29.aspx
var r = L.exec("msiexec.exe /qn /norestart " +
"/Lime \"" + tname + "\" " +
"/x \"" + msi + "\" " +
" MSIFASTINSTALL=7");
var result = L.exec("cmd.exe /d /c type \"" + tname + "\"");
// list of errors: http://msdn.microsoft.com/en-us/library/windows/desktop/aa368542(v=vs.85).aspx
// 3010=restart required
return r[0] === 0 || r[0] === 3010 || r[0] === 1605 ;
};
/**
* This function is available since 1.12.
*
* Registers an application for the "Open with" list in Windows Explorer.
*
* @param key name of the registry key.
* Example: "org.7-zip.SevenZIP64-%NPACKD_PACKAGE_VERSION%"
* @param cmd command that should be executed.
* Example: '"C:\\Program Files\\7-zip\\7zFM.exe" "%1"'
* @param title title for the command
* Example: 7-Zip File Manager (7-ZIP/64 bit %NPACKD_PACKAGE_VERSION%)
* @param extensions array of extensions. Example: [".001", ".7z", ".zip"]
*/
L.registerOpenWith = function(key, cmd, title, extensions) {
var shell = WScript.CreateObject("WScript.Shell");
shell.RegWrite("HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Applications\\" + key + "\\",
1, "REG_BINARY");
shell.RegWrite("HKLM\\SOFTWARE\\Classes\\Applications\\" + key +
"\\shell\\",
1, "REG_BINARY");
shell.RegWrite("HKLM\\SOFTWARE\\Classes\\Applications\\" + key +
"\\shell\\open\\",
1, "REG_BINARY");
shell.RegWrite("HKLM\\SOFTWARE\\Classes\\Applications\\" + key +
"\\shell\\open\\FriendlyAppName",
title, "REG_SZ");
shell.RegWrite("HKLM\\SOFTWARE\\Classes\\Applications\\" + key +
"\\shell\\open\\command\\",
cmd, "REG_SZ");
for (var i = 0; i < extensions.length; i++) {
shell.RegWrite("HKLM\\SOFTWARE\\Classes\\" + extensions[i] +
"\\OpenWithList\\" + key +
"\\", 1, "REG_BINARY");
}
};
/**
* This function is available since 1.12.
*
* Un-registers an application for the "Open with" list in Windows Explorer.
*
* @param key name of the registry key.
* Example: "org.7-zip.SevenZIP64-%NPACKD_PACKAGE_VERSION%"
* @param extensions array of extensions. Example: [".001", ".7z", ".zip"]
*/
L.unregisterOpenWith = function(key, extensions) {
var shell = WScript.CreateObject("WScript.Shell");
shell.RegDelete("HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Applications\\" +
key + "\\shell\\open\\command\\");
shell.RegDelete("HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Applications\\" +
key + "\\shell\\open\\");
shell.RegDelete("HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Applications\\" +
key + "\\shell\\");
shell.RegDelete("HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Applications\\" +
key + "\\");
for (var i = 0; i < extensions.length; i++) {
shell.RegDelete("HKLM\\SOFTWARE\\Classes\\" + extensions[i] +
"\\OpenWithList\\" + key + "\\");
}
};
/**
* This function is available since 1.13.
* Since 1.18 .tar.gz is also supported.
* Since 1.19 .tar.xz is also supported.
*
* Unpacks the specified file or directory and deletes
* the file or directory. Unpacking a directory means moving all the contents
* one level up.
*
* @param file a .7z, .tar, .gz, .tar.gz or .tar.xz file or a directory.
* All other file extensions will result in an error.
* @param target target directory
*/
L.unpackAndDelete = function(file, target) {
var fs = new ActiveXObject("Scripting.FileSystemObject");
if (fs.FolderExists(file)) {
var f = fs.GetFolder(file);
try {
fs.MoveFile(f.Path + "\\*", target);
} catch (e) {
// ignore. This can happen if there are no files in the directory.
}
try {
fs.MoveFolder(f.Path + "\\*", target);
} catch (e) {
// ignore. This can happen if there are not sub-directories.
}
f.Delete(true);
} else if (file.match(/\.tar\.gz$/i) || file.match(/\.tar\.xz$/i)) {
var r = L.exec("\"" + this.installerHelper +
"\\private\\7za.exe\" x " +
"\"" + file + "\"");
if (r[0] !== 0)
throw new Error("Failed to unpack the .gz/.xz file " + file);
fs.DeleteFile(file);
file = file.substring(0, file.length - 3);
var r = L.exec("\"" + this.installerHelper +
"\\private\\7za.exe\" x " +
"\"" + file + "\" " +
"-o\"" + target + "\"");
if (r[0] !== 0)
throw new Error("Failed to unpack the .tar file " + file);
fs.DeleteFile(file);
} else {
var r = L.exec("\"" + this.installerHelper +
"\\private\\7za.exe\" x " +
"\"" + file + "\" " +
"-o\"" + target + "\"");
if (r[0] !== 0)
throw new Error("Failed to unpack the .7z file " + file);
fs.DeleteFile(file);
}
};
/**
* This function is available since 1.15.
*
* Removes the whitespace characters at the beginning and at the end of a
* string. All characters that match \s in regular expressions will be remove.
*
* @param value text with spaces
* @return text without spaces
*/
L.trim = function(value) {
var w = new RegExp("^\\s+","gm");
var w2 = new RegExp("\\s+$","gm");
return value.replace(w, "").replace(w2, "");
};
/**
* This function is available since 1.15.
*
* Lists the sub-keys from the Windows registry.
*
* @param key path to a registry key, e.g.
* HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
* @return array of child keys. Full paths will be returned in every element.
* Example: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Adobe Flash Player ActiveX
*/
L.listRegistryKeys = function(key) {
var r = L.exec("reg.exe query \"" + key + "\"");
if (r[0] === 0) {
var result = [];
var output = r[1];
for (var i = 0; i < output.length; i++) {
if (L.trim(output[i]).length !== 0) {
result.push(output[i]);
}
}
return result;
} else {
throw new Error("reg.exe exited with the code " + r[0]);
}
};
/**
* This function is available since 1.15.
*
* Removes from "a" all elements that also exist in "b".
* The order of the elements is not important. The elements are compared using
* the operator "===".
*
* @param a the first array
* @param b the second array
* @return "a" without all elements in "b"
*/
L.subArrays = function(a, b) {
var result = [];
for (var i = 0; i < a.length; i++) {
var ai = a[i];
var found = false;
for (var j = 0; j < b.length; j++) {
var bj = b[j];
if (ai === bj) {
found = true;
break;
}
}
if (!found) {
result.push(ai);
}
}
return result;
};
/**
* This function is available since 1.16.
*
* Detects the system type: 32 bit or 64 bit.
*
* @return true if this system runs a 64 bit Windows
*/
L.is64bit = function() {
var r = false;
var sh = WScript.CreateObject("WScript.Shell");
var env = sh.Environment("Process");
// WScript.Echo("PROCESSOR_ARCHITECTURE: " + env("PROCESSOR_ARCHITECTURE"));
// WScript.Echo("PROCESSOR_ARCHITEW6432: " + env("PROCESSOR_ARCHITEW6432"));
if (env("PROCESSOR_ARCHITECTURE") === "x86") {
r = env("PROCESSOR_ARCHITEW6432") !== "";
} else {
r = true;
}
return r;
}
/**
* This function is available since 1.20.
*
* Safely executes another function logging the possible error to the
* console and exiting the execution with the exit code 1.
*
* @param f this function will be executed. The only parameter is this
* library object (see the variable L in this file).
* @return true if this system runs a 64 bit Windows
*/
L.safe = function(f) {
try {
f(L);
} catch (e) {
WScript.Echo(e.name + ": " + e.message);
WScript.Echo(e.number + ": " + e.description);
WScript.Quit(1);
}
}
/**
* This function is available since 1.21.
*
* Removes an application silently by its title in the Control Panel "Software".
*
* @param re regular expression to match the program title
* Example: /my editor/i
* @param silent true = use the silent command, false = use the normal removal command
* @param bits64 true = search for 64 bit programs, false = search for 32 bit
* programs
* @return true if the program was found and removed,
* false otherwise
*/
L.uninstallByTitle = function(re, silent, bits64) {
var shell = WScript.CreateObject("WScript.Shell");
var middle = "";
if (L.is64bit()) {
if (!bits64)
middle = "Wow6432Node";
}
var keys = L.listRegistryKeys("HKEY_LOCAL_MACHINE\\SOFTWARE\\" +
middle +
"\\Microsoft\\Windows\\CurrentVersion\\Uninstall");
var suffix = silent ? "QuietUninstallString": "UninstallString";
for (var i = 0; i < keys.length; i++) {
try {
var dn = shell.RegRead(keys[i] + "\\DisplayName");
} catch (e) {
// ignore
continue;
}
if (dn.match(re)) {
var cmd = shell.ExpandEnvironmentStrings(
shell.RegRead(keys[i] + "\\" + suffix));
if (L.trim(cmd) !== "") {
var r = L.exec(cmd);
if (r[0] !== 0)
throw new Error("The uninstall command failed with the exit code " + r[0]);
return true;
} else {
throw new Error("Empty uninstall command found for " + dn);
}
}
}
return false;
};
L.installerHelper = WScript.arguments.length > 0 ? WScript.arguments(0) : "";
var TESTING = false;
if (TESTING) {
L.installerHelper = "C:\\Users\\t\\projects\\installer-helper";
// WScript.Echo(L.findFile(".", /\.js$/i));
//L.registerOpenWith("org.test", '"C:\\Program Files\\7-zip\\7zFM.exe" "%1"',
// "Test 7373", [".001", ".7z"]);
// L.unregisterOpenWith("org.test", [".001", ".7z"]);
// L.installMSI(null, "INSTALLDIR");
//L.uninstallMSI(null);
//L.unpackAndDelete("test", ".");
//WScript.Echo(L.findDir(".", /^pri/i));
//WScript.Echo(L.listRegistryKeys("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall").length);
//WScript.Echo("12" === "1" + "2");
//WScript.Echo(L.subArrays(["12d", "2", "8"], ["8", "2"])[0]);
//var before = L.listRegistryKeys("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall");
//var after = L.listRegistryKeys("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall");
//WScript.Echo("Difference: " + before.length + " " + after.length + " " + L.subArrays(after, before).length);
//WScript.Echo("64 bit: " + L.is64bit());
//WScript.Echo(typeof {}["name"] === "undefined");
WScript.Echo(L.uninstallByTitle(/poedit/i, true, false));
}
return L;
}).call();
lib