From 7b89a598d6615c829405dd202df2874e46d3de2b Mon Sep 17 00:00:00 2001 From: Yosef Dinerstein Date: Wed, 14 Mar 2012 14:26:04 +0200 Subject: [PATCH 1/4] Parse XML output of WMIC. --- README.md | 22 +++++++---- lib/kill.js | 82 +++++++++++++++++++++------------------ lib/ps.js | 102 +++++++++++++++++++++++++++---------------------- package.json | 51 ++++++++++++++++--------- tests/tests.js | 60 ++++++++++++++--------------- 5 files changed, 179 insertions(+), 138 deletions(-) diff --git a/README.md b/README.md index 9c69b44..a6bad10 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,23 @@ -# wintools - Some windows tools for node.js # +# wintools - Some windows tools for node.js + +## Installation ```bash npm install wintools ``` - * __ps(callback)__ where callback is `function(err, list)` returns a list of running processes. - * __kill.pid(pid, callback)__ kills a process by PID. - * __kill.image(imageName, callback)__ kills a process by image name (e.g. `node.exe`). - * __shutdown.poweroff([callback])__ turns of off the machine immediately. - * __shutdown.restart([callback])__ rstarts the machine immediately. +```javascript +var wintools = require('wintools'); +``` + +## API + + * `wintools.ps(callback)` where callback is `function(err, list)` returns a list of running processes. + * `wintools.kill.pid(pid, callback)` kills a process by PID. + * `wintools.kill.image(imageName, callback)` kills a process by image name (e.g. `node.exe`). + * `wintools.shutdown.poweroff([callback])` turns of off the machine immediately. + * `wintools.shutdown.restart([callback])` rstarts the machine immediately. -## License ## +## License MIT \ No newline at end of file diff --git a/lib/kill.js b/lib/kill.js index 9c3146d..f9ca7ea 100644 --- a/lib/kill.js +++ b/lib/kill.js @@ -1,40 +1,48 @@ -var exec = require('child_process').exec; - +var exec = require('child_process').exec; + /** - * Kills a process by PID. - * @param pid Required. Process ID. - * @param callback Optional. - * @remarks Windows only - */ -exports.pid = function(pid, callback) { - if (!pid) throw new Error('pid is required'); - if (!callback) callback = function() {}; - - exec('taskkill /t /f /pid ' + pid.toString(), function (err, stdout, stderr) { - if (err) { - callback({ msg: "unable to kill " + pid, err: err, stdout: stdout, stderr: stderr }); - return; - } - - callback(); - }); -}; - +* Kills a process by PID. +* @param pid Required. Process ID. +* @param callback Optional. +* @remarks Windows only +*/ +exports.pid = function (pid, callback) { + if (!pid) throw new Error('pid is required'); + if (!callback) callback = function () { }; + + exec('taskkill /t /f /pid ' + pid.toString(), function (err, stdout, stderr) { + if (err) { + callback({ msg: "unable to kill " + pid, err: err, stdout: stdout, stderr: stderr }); + return; + } + + callback(); + }); +}; + /** - * Kills all the processes with the specified image name - * @param imageName Required. The name of the image (e.g. 'node.exe') - * @param callback Optional. - */ -exports.image = function(imageName, callback) { - if (!imageName) throw new Error('imageName is required'); - if (!callback) callback = function() {}; - - exec('taskkill /t /f /im ' + imageName, function (err, stdout, stderr) { - if (err) { - callback({ msg: "unable to kill " + imageName, err: err, stdout: stdout, stderr: stderr }); - return; - } - - callback(); - }); +* Kills all the processes with the specified image name +* @param imageName Required. The name of the image (e.g. 'node.exe') +* @param callback Optional. +*/ +exports.image = function (imageName, opts, callback) { + if (!imageName) throw new Error('imageName is required'); + + if (typeof opts === 'function') { + callback = opts; + opts = ''; + } + + if (!callback) callback = function () { }; + + var cmd = ('taskkill /t /f /im ' + imageName + ' ' + opts).trim(); + console.log('cmd:', cmd); + exec(cmd, function (err, stdout, stderr) { + if (err) { + callback({ msg: "unable to kill " + imageName, err: err, stdout: stdout, stderr: stderr }); + return; + } + + callback(); + }); } diff --git a/lib/ps.js b/lib/ps.js index 2b6b971..a5d8ac6 100644 --- a/lib/ps.js +++ b/lib/ps.js @@ -1,48 +1,58 @@ -var exec = require('child_process').exec; - +var spawn = require('child_process').spawn; +var xml2js = require('xml2js'); + /** - * Returns all the system processes - * @param callback {function(err, list)} Called with the list of all processes. - * @remarks Runs only on Windows (uses WMI) - */ -module.exports = function(callback) { - if (!callback) callback = function(err, list) { }; - - exec('wmic process list /format:csv', function (err, stdout, stderr) { - if (err) { - callback({ err: err, msg: "unable to enumerate processes" }); - return; - } - - stdout = stdout.replace(/\r/g, '').split('\n').slice(1); - fields = stdout.shift().split(','); - - var output = {}; - stdout.forEach(function (line) { - - var parts = line.split(','); - var entry = {}; - for (var i = 0; i < fields.length; ++i) { - entry[fields[i]] = parts[i]; - } - - var e = { - pid: entry.Handle, - desc: entry.Description, - cmd: entry.CommandLine, - prog: entry.ExecutablePath, - workingSet: entry.WorkingSetSize, - }; - - // remove some empty stuff - if (!e.cmd) delete e.cmd; - if (!e.prog) delete e.prog; - - if (e.pid) { - output[e.pid] = e; - } - }); - - callback(null, output); - }); +* Returns all the system processes +* @param callback {function(err, list)} Called with the list of all processes. +* @remarks Runs only on Windows (uses WMI) +*/ +module.exports = function (callback) { + if (!callback) callback = function (err, list) { }; + + var options = [ + 'process', + 'list', + '/format:rawxml' + ]; + + // Spawn process, since output from exec can be too big for buffer size supported. + var p = spawn('wmic', options); + + var xml = ''; + + p.stdout.on('data', function (data) { + xml = xml + data.toString(); + }); + + p.stderr.on('data', function (data) { + console.error(data); + }); + + p.on('exit', function () { + parser = new xml2js.Parser(); + parser.parseString(xml, function (err, result) { + var output = {}; + result.RESULTS.CIM.INSTANCE.forEach(function (p) { + var entry = {}; + p.PROPERTY.forEach(function (v) { + entry[v['@'].NAME] = v.VALUE; + }); + + var e = { + pid: entry.Handle, + desc: entry.Description, + cmd: entry.CommandLine, + prog: entry.ExecutablePath + }; + + if (!e.cmd) delete e.cmd; + if (!e.prog) delete e.prog; + + if (e.pid) { + output[e.pid] = e; + } + }); + callback(null, output); + }); + }); } \ No newline at end of file diff --git a/package.json b/package.json index a8b72a0..07959f2 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,35 @@ { - "name": "wintools", - "description": "Some Windows tools for node.js", - "main": "./main", - "author": "Elad Ben-Israel", - "version": "0.1.0", - "dependencies": { - "async": ">=0.1.15" - }, - "devDependencies": { - "nodeunit": "*" - }, - "repository": { - "type": "git", - "url": "https://github.com/anodejs/node-wintools" - }, - "scripts": { - "test": "node_modules/nodeunit/bin/nodeunit tests/" - } + "name": "wintools", + "description": "Some Windows tools for node.js", + "main": "./main", + "bin": {}, + "author": "anode ", + "version": "0.2.0", + "license": "MIT", + "contributors": [ + "Elad Ben-Israel ", + "Yosef Dinerstein " + ], + "keywords": [ + "nodejs", + "windows" + ], + "engines": { + "node": "~0.6.x" + }, + "dependencies": { + "async": "0.1.x", + "xml2js": "0.1.x" + }, + "devDependencies": { + "nodeunit": "0.6.x" + }, + "repository": { + "type": "git", + "url": "git://github.com/anodejs/node-wintools.git" + }, + "scripts": { + "test": "nodeunit test/*.js" + } } + diff --git a/tests/tests.js b/tests/tests.js index c60f6ff..97101e5 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -1,31 +1,31 @@ -var wintools = require('../main'); - -exports.ps = function(test) { - wintools.ps(function(err, ps) { - test.ok(!err, err); - test.ok(ps); - test.ok(ps && Object.keys(ps).length > 0); - test.done(); - }); -}; - -exports.killByPID = function(test) { - wintools.kill.pid(77777, function(err) { - test.ok(err); - test.done(); - }); -}; - -exports.killByImage = function(test) { - wintools.kill.image('bla.exe', function(err) { - test.ok(err); - test.done(); - }); -}; - -exports.shutdown = function(test) { - // only check that api exists - test.ok(wintools.shutdown.poweroff); - test.ok(wintools.shutdown.restart); - test.done(); +var wintools = require('../main'); + +exports.ps = function (test) { + wintools.ps(function (err, ps) { + test.ok(!err, err); + test.ok(ps); + test.ok(ps && Object.keys(ps).length > 0); + test.done(); + }); +}; + +exports.killByPID = function (test) { + wintools.kill.pid(77777, function (err) { + test.ok(err); + test.done(); + }); +}; + +exports.killByImage = function (test) { + wintools.kill.image('bla.exe', function (err) { + test.ok(err); + test.done(); + }); +}; + +exports.shutdown = function (test) { + // only check that api exists + test.ok(wintools.shutdown.poweroff); + test.ok(wintools.shutdown.restart); + test.done(); }; \ No newline at end of file From 675920ddf0b41c3bd92404e15266bc21ed0c2af7 Mon Sep 17 00:00:00 2001 From: Yosef Dinerstein Date: Wed, 14 Mar 2012 15:06:57 +0200 Subject: [PATCH 2/4] Support filter in process list. --- README.md | 2 +- lib/ps.js | 8 +++++--- tests/tests.js | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a6bad10..ed69d17 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ var wintools = require('wintools'); ## API - * `wintools.ps(callback)` where callback is `function(err, list)` returns a list of running processes. + * `wintools.ps(filter, callback)` where filter is a filter function `function(p)` executed on each process before pushing it to the list and callback is `function(err, list)` returns a list of running processes. * `wintools.kill.pid(pid, callback)` kills a process by PID. * `wintools.kill.image(imageName, callback)` kills a process by image name (e.g. `node.exe`). * `wintools.shutdown.poweroff([callback])` turns of off the machine immediately. diff --git a/lib/ps.js b/lib/ps.js index a5d8ac6..6187360 100644 --- a/lib/ps.js +++ b/lib/ps.js @@ -3,11 +3,13 @@ var xml2js = require('xml2js'); /** * Returns all the system processes +* @param filter {function(p)->Boolean} A filter function executed on each process before pushing it to the list. * @param callback {function(err, list)} Called with the list of all processes. * @remarks Runs only on Windows (uses WMI) */ -module.exports = function (callback) { - if (!callback) callback = function (err, list) { }; +module.exports = function (filter, callback) { + if (!filter) filter = function () { return true; } + if (!callback) callback = function () { }; var options = [ 'process', @@ -48,7 +50,7 @@ module.exports = function (callback) { if (!e.cmd) delete e.cmd; if (!e.prog) delete e.prog; - if (e.pid) { + if (e.pid && filter(e)) { output[e.pid] = e; } }); diff --git a/tests/tests.js b/tests/tests.js index 97101e5..95b4deb 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -1,7 +1,7 @@ var wintools = require('../main'); exports.ps = function (test) { - wintools.ps(function (err, ps) { + wintools.ps(null, function (err, ps) { test.ok(!err, err); test.ok(ps); test.ok(ps && Object.keys(ps).length > 0); From 0f364cd105a4e23987665d0a04c58ea8fcec51f4 Mon Sep 17 00:00:00 2001 From: Yosef Dinerstein Date: Thu, 15 Mar 2012 13:03:01 +0200 Subject: [PATCH 3/4] add filter under options --- README.md | 2 +- lib/ps.js | 23 ++++++++++++++++------- tests/tests.js | 2 +- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ed69d17..9cefc38 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ var wintools = require('wintools'); ## API - * `wintools.ps(filter, callback)` where filter is a filter function `function(p)` executed on each process before pushing it to the list and callback is `function(err, list)` returns a list of running processes. + * `wintools.ps(options, callback)` where callback is `function(err, list)` returns a list of running processes. * `wintools.kill.pid(pid, callback)` kills a process by PID. * `wintools.kill.image(imageName, callback)` kills a process by image name (e.g. `node.exe`). * `wintools.shutdown.poweroff([callback])` turns of off the machine immediately. diff --git a/lib/ps.js b/lib/ps.js index 6187360..684b56d 100644 --- a/lib/ps.js +++ b/lib/ps.js @@ -3,22 +3,31 @@ var xml2js = require('xml2js'); /** * Returns all the system processes -* @param filter {function(p)->Boolean} A filter function executed on each process before pushing it to the list. +* @param options +* filter {function(p)} filters processes before inserting to result list. * @param callback {function(err, list)} Called with the list of all processes. * @remarks Runs only on Windows (uses WMI) */ -module.exports = function (filter, callback) { - if (!filter) filter = function () { return true; } - if (!callback) callback = function () { }; +module.exports = function (options, callback) { - var options = [ + if (typeof options === 'function') { + callback = options; + options = {}; + } + + options = options || {}; + options.filter = options.filter || function () { return true; }; + + callback = callback || function () { }; + + var cmd = [ 'process', 'list', '/format:rawxml' ]; // Spawn process, since output from exec can be too big for buffer size supported. - var p = spawn('wmic', options); + var p = spawn('wmic', cmd); var xml = ''; @@ -50,7 +59,7 @@ module.exports = function (filter, callback) { if (!e.cmd) delete e.cmd; if (!e.prog) delete e.prog; - if (e.pid && filter(e)) { + if (e.pid && options.filter(e)) { output[e.pid] = e; } }); diff --git a/tests/tests.js b/tests/tests.js index 95b4deb..97101e5 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -1,7 +1,7 @@ var wintools = require('../main'); exports.ps = function (test) { - wintools.ps(null, function (err, ps) { + wintools.ps(function (err, ps) { test.ok(!err, err); test.ok(ps); test.ok(ps && Object.keys(ps).length > 0); From ed4eaa3fafd5c03870e39a76751ad59b2efefcf3 Mon Sep 17 00:00:00 2001 From: Yosef Dinerstein Date: Fri, 6 Apr 2012 12:08:51 +0300 Subject: [PATCH 4/4] Fix parameters handling, so that can call without options and without callback. --- lib/kill.js | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/kill.js b/lib/kill.js index f9ca7ea..e4edab0 100644 --- a/lib/kill.js +++ b/lib/kill.js @@ -33,6 +33,10 @@ exports.image = function (imageName, opts, callback) { opts = ''; } + if (!opts) { + opts = ''; + } + if (!callback) callback = function () { }; var cmd = ('taskkill /t /f /im ' + imageName + ' ' + opts).trim(); diff --git a/package.json b/package.json index 07959f2..28faba5 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "main": "./main", "bin": {}, "author": "anode ", - "version": "0.2.0", + "version": "0.2.1", "license": "MIT", "contributors": [ "Elad Ben-Israel ",