UNPKG

regedit

Version:

Read, Write, List and do all sorts of funky stuff to the windows registry using node.js and windows script host

573 lines (464 loc) 14.6 kB
const fs = require('fs') const childProcess = require('child_process') const path = require('path') const debug = require('debug')('regedit') const errors = require('./errors.js') const StreamSlicer = require('stream-slicer') const through2 = require('through2') const helper = require('./lib/helper.js') const execFile = require('./lib/execFile.js')() const cscript = require('./lib/cscript.js') /* * Access the registry without using a specific os architecture, this means that on a 32bit process on a 64bit machine * when we access hklm\software we will actually be accessing hklm\software\wow6432node. */ const OS_ARCH_AGNOSTIC = 'A' /* * Access the registry using a specific os architecture, but determine what the architecture is automatically * This means that accessing in order to access the 32bit software registry on a 64bit machine we will need to * use the key hklm\software\wow6432node */ const OS_ARCH_SPECIFIC = 'S' /* * Access the registry using 32bit os architecture */ const OS_ARCH_32BIT = '32' /* * Access the registry using 64bit os architecture, this will have no effect on 32bit process/machines */ const OS_ARCH_64BIT = '64' /* * If this value is set the module will change directory of the VBS to the appropriate location instead of the local VBS folder */ let externalVBSFolderLocation function handleErrorsAndClose(child, callback) { let error child.once('error', function(e) { debug('process error %s', e) error = e }) child.once('close', function(code) { debug('process exit with code %d', code) if (error) { if (error.code in errors) { return callback(errors[error.code]) } return callback(error) } if (code !== 0) { if (code in errors) { return callback(errors[code]) } return callback(new Error('vbscript process reported unknown error code ' + code)) } callback() }) } function execute(args, callback) { if (typeof callback !== 'function') { throw new Error('missing callback') } debug(args) cscript.init(function(err) { if (err) { return callback(err) } childProcess.execFile(cscript.path(), args, function(err, stdout, stderr) { if (err) { if (stdout) { console.log(stdout) } if (stderr) { console.error(stderr) } if (err.code in errors) { return callback(errors[err.code]) } return callback(err) } // in case we have stuff in stderr but no real error if (stderr) { return callback(new Error(stderr)) } if (!stdout) { return callback() } debug(stdout) let result err = null try { result = JSON.parse(stdout) } catch (e) { e.stdout = stdout err = e } callback(err, result) }) }) } function spawnEx(args, keys, callback) { cscript.init(function(err) { if (err) { return callback(err) } debug(args) const child = execFile(cscript.path(), args, { encoding: 'utf8' }) handleErrorsAndClose(child, callback) helper.writeArrayToStream(keys, child.stdin) }) } //TODO: move to helper.js? function renderValueByType(value, type) { type = type.toUpperCase() switch (type) { case 'REG_NONE': if (value === '') { return '\0' } return value case 'REG_BINARY': if (!Array.isArray(value)) { throw new Error('invalid value type ' + typeof(value) + ' for registry type REG_BINARY, please use an array of numbers') } return value.join(',') case 'REG_MULTI_SZ': if (!Array.isArray(value)) { throw new Error('invalid value type ' + typeof(value) + ' for registry type REG_BINARY, please use an array of strings') } return value.join(',') case 'REG_SZ': if (value === '') { return '\0' } return value default: return value } } //TODO: move to helper.js? function baseCommand(cmd, arch) { let scriptPath // test undefined, null and empty string if (externalVBSFolderLocation && typeof(externalVBSFolderLocation) === 'string') { scriptPath = externalVBSFolderLocation } else { scriptPath = path.join(__dirname, 'vbs') } return ['//Nologo', path.join(scriptPath, cmd), arch] } //TODO: move to helper.js? function toCommandArgs(cmd, arch, keys) { let result = baseCommand(cmd, arch) if (typeof keys === 'string') { result.push(keys) } else if (Array.isArray(keys)) { result = result.concat(keys) } else { debug('creating command without using keys %s', keys ? keys : '') } return result } module.exports.setExternalVBSLocation = function(newLocation) { if (fs.existsSync(newLocation)) { externalVBSFolderLocation = newLocation return 'Folder found and set' } return 'Folder not found' } module.exports.list = function(keys, architecture, callback) { //console.log('list with callback will be deprecated in future versions, use list streaming interface') if (architecture === undefined) { callback = undefined architecture = OS_ARCH_AGNOSTIC } else if (typeof architecture === 'function') { callback = architecture architecture = OS_ARCH_AGNOSTIC } if (typeof keys === 'string') { keys = [keys] } if (typeof callback === 'function') { execute(toCommandArgs('regList.wsf', architecture, keys), callback) return } const outputStream = through2.obj(helper.vbsOutputTransform) cscript.init(function(err) { if (err) { return outputStream.emit('error', err) } const args = baseCommand('regListStream.wsf', architecture) const child = execFile(cscript.path(), args, { encoding: 'utf8' }, function(err) { if (err) { outputStream.emit('error', err) } }) child.stderr.pipe(process.stderr) const slicer = new StreamSlicer({ sliceBy: helper.WIN_EOL }) child.stdout.pipe(slicer).pipe(outputStream) helper.writeArrayToStream(keys, child.stdin) }) return outputStream } module.exports.createKey = function(keys, architecture, callback) { if (typeof architecture === 'function') { callback = architecture architecture = OS_ARCH_AGNOSTIC } if (typeof keys === 'string') { keys = [keys] } const args = baseCommand('regCreateKey.wsf', architecture) spawnEx(args, keys, callback) } module.exports.deleteKey = function(keys, architecture, callback) { if (typeof architecture === 'function') { callback = architecture architecture = OS_ARCH_AGNOSTIC } if (typeof keys === 'string') { keys = [keys] } const args = baseCommand('regDeleteKey.wsf', architecture) spawnEx(args, keys, callback) } module.exports.deleteValue = function(keys, architecture, callback) { if (typeof architecture === 'function') { callback = architecture architecture = OS_ARCH_AGNOSTIC } if (typeof keys === 'string') { keys = [keys] } var args = baseCommand('regDeleteValue.wsf', architecture) spawnEx(args, keys, callback) } module.exports.putValue = function(map, architecture, callback) { if (typeof architecture === 'function') { callback = architecture architecture = OS_ARCH_AGNOSTIC } const args = baseCommand('regPutValue.wsf', architecture) let values = [] for (const key in map) { if (map.hasOwnProperty(key)) { const keyValues = map[key] for (const valueName in keyValues) { if (keyValues.hasOwnProperty(valueName)) { const entry = keyValues[valueName] // helper writes the array to the stream in reversed order values.push(entry.type) values.push(renderValueByType(entry.value, entry.type)) values.push(valueName) values.push(key) } } } } spawnEx(args, values, callback) } module.exports.listUnexpandedValues = function(valuePaths, architecture, callback) { if (architecture === undefined) { callback = undefined architecture = OS_ARCH_AGNOSTIC } else if (typeof architecture === 'function') { callback = architecture architecture = OS_ARCH_AGNOSTIC } if (typeof valuePaths === 'string') { valuePaths = [valuePaths] } if (typeof callback === 'function') { execute(toCommandArgs('wsRegReadList.wsf', architecture, valuePaths), callback) return } const outputStream = through2.obj(helper.vbsOutputTransform) cscript.init(function(err) { if (err) { return outputStream.emit('error', err) } const args = baseCommand('wsRegReadListStream.wsf', architecture) const child = execFile(cscript.path(), args, { encoding: 'utf8' }, function(err) { if (err) { outputStream.emit('error', err) } }) child.stderr.pipe(process.stderr) const slicer = new StreamSlicer({ sliceBy: helper.WIN_EOL }) child.stdout.pipe(slicer).pipe(outputStream) helper.writeArrayToStream(valuePaths, child.stdin) }) return outputStream } module.exports.promisified = { list: function(keys, architecture = OS_ARCH_AGNOSTIC) { return new Promise(function(resolve, reject) { module.exports.list(keys, architecture, function(err, res) { if (err) { return reject(err) } return resolve(res) }) }) }, listUnexpandedValues: function(valuePaths, architecture = OS_ARCH_AGNOSTIC) { return new Promise(function(resolve, reject) { module.exports.listUnexpandedValues(valuePaths, architecture, function(err, res) { if (err) { return reject(err) } return resolve(res) }) }) }, createKey: function(keys, architecture = OS_ARCH_AGNOSTIC) { return new Promise(function(resolve, reject) { module.exports.createKey(keys, architecture, function(err) { if (err) { return reject(err) } return resolve() }) }) }, deleteKey: function(keys, architecture = OS_ARCH_AGNOSTIC) { return new Promise(function(resolve, reject) { module.exports.deleteKey(keys, architecture, function(err) { if (err) { return reject(err) } return resolve() }) }) }, deleteValue: function(keys, architecture = OS_ARCH_AGNOSTIC) { return new Promise(function(resolve, reject) { module.exports.deleteValue(keys, architecture, function(err) { if (err) { return reject(err) } return resolve() }) }) }, putValue: function(map, architecture = OS_ARCH_AGNOSTIC) { return new Promise(function(resolve, reject) { module.exports.putValue(map, architecture, function(err) { if (err) { return reject(err) } return resolve() }) }) }, } module.exports.arch = {} module.exports.arch.list = function(keys, callback) { return module.exports.list(keys, OS_ARCH_SPECIFIC, callback) } module.exports.arch.list32 = function(keys, callback) { return module.exports.list(keys, OS_ARCH_32BIT, callback) } module.exports.arch.list64 = function(keys, callback) { return module.exports.list(keys, OS_ARCH_64BIT, callback) } module.exports.arch.listUnexpandedValues = function(valuePaths, callback) { return module.exports.listUnexpandedValues(valuePaths, OS_ARCH_SPECIFIC, callback) } module.exports.arch.listUnexpandedValues32 = function(valuePaths, callback) { return module.exports.listUnexpandedValues(valuePaths, OS_ARCH_32BIT, callback) } module.exports.arch.listUnexpandedValues64 = function(valuePaths, callback) { return module.exports.listUnexpandedValues(valuePaths, OS_ARCH_64BIT, callback) } module.exports.arch.createKey = function(keys, callback) { return module.exports.createKey(keys, OS_ARCH_SPECIFIC, callback) } module.exports.arch.createKey32 = function(keys, callback) { return module.exports.createKey(keys, OS_ARCH_32BIT, callback) } module.exports.arch.createKey64 = function(keys, callback) { return module.exports.createKey(keys, OS_ARCH_64BIT, callback) } module.exports.arch.deleteKey = function(keys, callback) { return module.exports.deleteKey(keys, OS_ARCH_SPECIFIC, callback) } module.exports.arch.deleteKey32 = function(keys, callback) { return module.exports.deleteKey(keys, OS_ARCH_32BIT, callback) } module.exports.arch.deleteKey64 = function(keys, callback) { return module.exports.deleteKey(keys, OS_ARCH_64BIT, callback) } module.exports.arch.deleteValue = function(keys, callback) { return module.exports.deleteValue(keys, OS_ARCH_SPECIFIC, callback) } module.exports.arch.deleteValue32 = function(keys, callback) { return module.exports.deleteValue(keys, OS_ARCH_32BIT, callback) } module.exports.arch.deleteValue64 = function(keys, callback) { return module.exports.deleteValue(keys, OS_ARCH_64BIT, callback) } module.exports.arch.putValue = function(keys, callback) { return module.exports.putValue(keys, OS_ARCH_SPECIFIC, callback) } module.exports.arch.putValue32 = function(keys, callback) { return module.exports.putValue(keys, OS_ARCH_32BIT, callback) } module.exports.arch.putValue64 = function(keys, callback) { return module.exports.putValue(keys, OS_ARCH_64BIT, callback) } module.exports.arch.promisified = { list: function(keys) { return module.exports.promisified.list(keys, OS_ARCH_SPECIFIC) }, list32: function(keys) { return module.exports.promisified.list(keys, OS_ARCH_32BIT) }, list64: function(keys) { return module.exports.promisified.list(keys, OS_ARCH_64BIT) }, listUnexpandedValues: function(valuePaths) { return module.exports.promisified.listUnexpandedValues(valuePaths, OS_ARCH_SPECIFIC) }, listUnexpandedValues32: function(valuePaths) { return module.exports.promisified.listUnexpandedValues(valuePaths, OS_ARCH_32BIT) }, listUnexpandedValues64: function(valuePaths) { return module.exports.promisified.listUnexpandedValues(valuePaths, OS_ARCH_64BIT) }, createKey: function(keys) { return module.exports.promisified.createKey(keys, OS_ARCH_SPECIFIC) }, createKey32: function(keys) { return module.exports.promisified.createKey(keys, OS_ARCH_32BIT) }, createKey64: function(keys) { return module.exports.promisified.createKey(keys, OS_ARCH_64BIT) }, deleteKey: function(keys) { return module.exports.promisified.deleteKey(keys, OS_ARCH_SPECIFIC) }, deleteKey32: function(keys) { return module.exports.promisified.deleteKey(keys, OS_ARCH_32BIT) }, deleteKey64: function(keys) { return module.exports.promisified.deleteKey(keys, OS_ARCH_64BIT) }, deleteValue: function(keys) { return module.exports.promisified.deleteValue(keys, OS_ARCH_SPECIFIC) }, deleteValue32: function(keys) { return module.exports.promisified.deleteValue(keys, OS_ARCH_32BIT) }, deleteValue64: function(keys) { return module.exports.promisified.deleteValue(keys, OS_ARCH_64BIT) }, putValue: function(keys) { return module.exports.promisified.putValue(keys, OS_ARCH_SPECIFIC) }, putValue32: function(keys) { return module.exports.promisified.putValue(keys, OS_ARCH_32BIT) }, putValue64: function(keys) { return module.exports.promisified.putValue(keys, OS_ARCH_64BIT) }, }