ps.jsとps.cmd / kill.cmd ― 2008年06月17日 00時54分14秒
なんちゃってコマンド 第四弾
我ながらしつこいなと思いつつ「なんちゃってコマンド」スクリプト。今度はps作ってみました。
ま、WMIでWin32_Process列挙できればそんなに難しくないので、似たようなことやってる人はいるだろなぁ。
例によってソース
ちょっと長いけど例によってのっけときます。NYSLです。
var fso = new ActiveXObject("Scripting.FileSystemObject");
var shell = new ActiveXObject("WScript.Shell");
// コマンドライン引数の取得
var args = new function() {
var args = WSH.Arguments, result = [];
for(var col = new Enumerator( args ); ! col.atEnd(); col.moveNext()) {
result[ result.length ] = String( col.item() );
}
var named = {};
for(var col = new Enumerator( args.Named ); ! col.atEnd(); col.moveNext()) {
named[ String( col.item() ) ] = String( args.Named.Item( col.item() ) );
}
var unnamed = [];
for(var col = new Enumerator( args.Unnamed ); ! col.atEnd(); col.moveNext()) {
unnamed[ unnamed.length ] = String( col.item() );
}
result.named = named;
result.unnamed = unnamed;
result.toArray = function() {
var result = [];
for(var i = 0, l = this.length; i < l; i++) {
result[ i ] = /((^".*"$)|(^'.*'$))/.test( this[i] ) ?
this[i] : [ '"', this[i], '"' ].join("");
}
return result;
};
result.toString = function() {
return this.toArray().join(" ");
};
return result;
}();
// cscriptで強制起動
if( /wscript\.exe$/i.test( WSH.FullName ) ) {
shell.Run( [
"cscript",
/((^".*"$)|(^'.*'$))/.test( WSH.ScriptFullName ) ? WSH.ScriptFullName : [ '"', WSH.ScriptFullName, '"' ].join(""),
args
].join(" ") );
WSH.Quit();
}
// ユーティリティ関数定義
var echo = function(s) {
print( [ s, "\n" ].join("") );
}
var print = function(s) {
WSH.StdOut.Write( s || "" );
}
var input = function() {
if( arguments[0] ) print( arguments[0] );
print( ">" );
return WSH.StdIn.ReadLine();
}
Error.prototype.toString = function() {
return this.description || this.message || this.number || this;
};
var $break = {};
var $continue = {};
Enumerator.prototype.each = function(iterator) {
try {
var i = 0;
for(this.moveFirst(); ! this.atEnd(); this.moveNext()) {
try {
iterator( this.item(), i++ );
} catch(e) {
if( e != $continue ) throw e;
}
}
} catch(e) {
if( e != $break ) throw e;
}
};
String.prototype.repeat = function(count) {
var buf = [];
for(var i = 0; i < count; i++) buf[buf.length] = this;
return buf.join("");
};
String.prototype.align = function(align, size) {
if( ! /^((left)|(right)|(center))$/i.test( align ) ) align = "left";
if( isNaN(size) || size < 1 ) size = this.length;
switch( align ) {
case "left":
return [ this, " ".repeat(size) ].join("").substr(0, size);
case "right":
return [ " ".repeat(size), this ].join("").slice(-1 * size);
default:
var pad = " ".repeat( size );
var s = [ pad, this, pad ].join("");
return s.substr( parseInt(s.length / 2) - parseInt(size / 2), size );
}
};
Number.prototype.toTime = function() {
var sec = this % 60;
var min = Math.floor( this / 60 );
var hour = Math.floor( min / 60 );
min = hour ? min % 60 : min;
return [
hour,
( "00" + min ).slice(-2),
( "00" + sec ).slice(-2)
].join(":");
};
var ProcMgr = function() {
this.wmi = new ActiveXObject("WbemScripting.SWbemLocator").ConnectServer();
var wshNet = new ActiveXObject("WScript.Network");
this.currentUser = [ wshNet.UserDomain, wshNet.UserName ].join("\\");
};
ProcMgr.prototype = {
list : function(id) {
var query = "SELECT * FROM Win32_Process";
query += id != null ? [ " WHERE ProcessId = ", id ].join("") : "";
return new Enumerator( this.wmi.ExecQuery(query) );
},
kill : function(id) {
this.list(id).each( function(proc) {
proc.Terminate();
throw $break;
} );
},
exec : function(params) {
if( params[0] && params[0].toLowerCase() == "--kill" && params[1] ) {
// --kill
this.kill( params[1] );
} else if( params[0] && params[0].toLowerCase() == "--list" ) {
// --list
// -a オプション。全ユーザのプロセスを列挙
var allUser = ( params[1] != null && /^-.*A/i.test( params[1] ) );
// -d オプション。コマンドラインの情報を付加
var detail = ( params[1] != null && /^-.*d/i.test( params[1] ) );
var inited = false;
var _self = this;
this.list().each( function(proc) {
if( ! inited ) {
inited = true;
echo( [
"PID".align( "right", 5 ),
"PPID".align( "right", 5 ),
"OWNER".align( "left", 16 ),
"WK-SIZE".align( "right", 8 ),
"PEAK".align( "right", 8 ),
"TIME".align( "right", 10 ),
"CMD".align( "left", 16 )
].join(" ") );
}
var cmd = proc.CommandLine == null ? "(null)" : String( proc.CommandLine );
var time = parseInt( ( Number(proc.KernelModeTime) + Number(proc.UserModeTime) ) / 10000 / 1000 );
var info = proc.ExecMethod_( proc.Methods_.Item("GetOwner").Name, null );
// プロセスオーナーのチェック
if( ! allUser && [ info.Domain, info.User ].join("\\").toLowerCase() != _self.currentUser.toLowerCase() ) throw $continue;
echo( [
String(proc.ProcessId).align( "right", 5 ),
String(proc.ParentProcessId).align( "right", 5 ),
String(info.User || "(null)" ).align( "left", 16 ),
String(Number(proc.WorkingSetSize) / 1024).align( "right", 8 ),
String(Number(proc.PeakWorkingSetSize) / 1024).align( "right", 8 ),
String( time.toTime() ).align( "right", 10 ),
[
String(proc.Name),
detail ? [ "(", cmd, ")" ].join("") : ""
].join(" ")
].join(" ") );
} );
} else {
// no parameter -> --list
this.exec( [ "--list" ] );
}
}
};
new ProcMgr().exec( args );
今回のダウンロードはzip形式にしてます。こちらからどうぞ。
使い方
今回は不精して、1つのスクリプトで2つのコマンドを兼用しています。おかげでjsファイルとしての呼び出しはちと不自然な感じなんですが。
プロセスの列挙 - psコマンド風味
何も引数をつけずに起動すると psコマンドっぽく(?)稼動中のプロセスを列挙します。ただし、標準入力での入力待ちを行わないので、明示的にcscriptで起動したほうがよいでしょう。
C:\ps_command\scripts>cscript ps.js
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
PID PPID OWNER WK-SIZE PEAK TIME CMD
472 1532 dara-j 2072 4912 0:01:01 tp4serv.exe
2172 2112 dara-j 29992 95644 0:42:34 explorer.exe
2272 2172 dara-j 4384 6808 0:00:30 TSVNCache.exe
:
(中略)
:
1640 2172 dara-j 2840 2884 0:00:00 cmd.exe
4920 1640 dara-j 6612 6612 0:00:00 cscript.exe
C:\ps_command\scripts>
列の意味は、左から
- PID - プロセスID
- PPID - 親プロセスID
- OWNER - プロセスのオーナー
- WK-SIZE - ワーキングセット サイズ
- PEAK - ピークメモリサイズ
- TIME - CPU時間(カーネル+ユーザ)
- CMD - コマンドイメージ名
また、第一引数に「--list」をつけた場合も上と同じ動作になります。
C:\ps_command\scripts>cscript ps.js --list
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
PID PPID OWNER WK-SIZE PEAK TIME CMD
472 1532 dara-j 2072 4912 0:01:01 tp4serv.exe
2172 2112 dara-j 29928 95644 0:42:39 explorer.exe
2272 2172 dara-j 4384 6808 0:00:30 TSVNCache.exe
:
(中略)
:
1640 2172 dara-j 2840 2884 0:00:00 cmd.exe
5864 2172 dara-j 1888 6716 0:00:01 taskmgr.exe
5212 1640 dara-j 6604 6604 0:00:00 cscript.exe
C:\ps_command\scripts>
--listで起動した場合はさらに第二引数にオプションをつけることができます。
「-a」オプションをつけると、他のオーナーが所有するプロセスも列挙します。といってもだいたい「SYSTEM」や「NETWORK SERVICE」くらいでしょうが。
C:\ps_command\scripts>cscript ps.js --list -a
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
PID PPID OWNER WK-SIZE PEAK TIME CMD
0 0 (null) 16 0 73:50:31 System Idle Process
4 0 SYSTEM 36 2040 0:05:51 System
836 4 SYSTEM 44 480 0:00:00 smss.exe
:
(中略)
:
1932 2172 dara-j 2848 2864 0:00:00 cmd.exe
4696 1932 dara-j 6624 6624 0:00:00 cscript.exe
3356 1168 NETWORK SERVICE 5728 5728 0:00:00 wmiprvse.exe
C:\ps_command\scripts>
これは個人的な趣味でつけたのですが、「-d」オプションをつけると、起動時のコマンドライン(引数まで込み)を出力します。
C:\ps_command\scripts>cscript ps.js --list -d
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
PID PPID OWNER WK-SIZE PEAK TIME CMD
472 1532 dara-j 2072 4912 0:01:02 tp4serv.exe ("C:\Progr
am Files\Lenovo\TrackPoint\tp4serv.exe")
2172 2112 dara-j 30244 95644 0:43:04 explorer.exe (C:\WINDO
WS\Explorer.EXE)
2272 2172 dara-j 4408 6808 0:00:30 TSVNCache.exe ("C:\Pro
gram Files\TortoiseSVN\bin\TSVNCache.exe")
:
(中略)
:
5864 2172 dara-j 2632 6716 0:00:10 taskmgr.exe (C:\WINDOW
S\system32\taskmgr.exe)
1932 2172 dara-j 5516 5592 0:00:00 cmd.exe ("cmd.exe" /K
cd C:\ps_command)
2260 1932 dara-j 6624 6624 0:00:00 cscript.exe (cscript p
s.js --list -d)
C:\ps_command\scripts>
複数インスタンス起動できるエディタなんかの、あるインスタンスを特定する場合なんかに便利かなとか思ってつけたのですが、正直表示が見づらいです。まぁオマケ機能くらいの感じで。
実行例は示しませんが、「-a」と「-d」は「-ad」といった具合で同時に指定できます。
プロセスの強制終了 - killコマンド風味
第一引数に「--kill」をつけるとkillモードで起動します。この呼び出し方法は第二引数にプロセスIDを必ず指定する必要があります。
以下はメモ帳(notepad.exe)を起動し、プロセスIDを確認後にkillモードで終了させる例です。
C:\ps_command\scripts>notepad C:\ps_command\scripts>cscript ps.js | findstr notepad 5728 1932 dara-j 4888 4888 0:00:00 notepad.exe C:\ps_command\scripts>cscript ps.js --kill 5728 Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. C:\ps_command\scripts>cscript ps.js | findstr notepad C:\ps_command\scripts>
バッチファイル
見てきたように2種類の動作を1つのスクリプトに集約したため、ちょっと引数が気持ち悪いのですが、バッチファイルを添付してあるので勘弁してください(ダウンロードファイルをzipにしたのはこのため)。
ダウンロードファイルを解凍すると、以下のような構造になっています。
- ps_command/
- scripts/
- ps.js - スクリプト本体
- kill.cmd - killモード起動用のバッチファイル
- ps.cmd - psモード起動用のバッチファイル
- scripts/
バッチファイルはスクリプトパスを「"%~dP0\scripts\ps.js"」としているため、「ps_command」フォルダごとリロケータブルになっています。「%~dp0」がなんなのかはこちらのサイトなんかが参考になるのでは。
ps.cmdは見れば即わかるくらいシンプルですが、kill.cmdは引数なしの時にusageを表示する分岐処理を入れてます。まぁぜんぜん難しいことしてるわけではないのですが。
その他
なんというか、できそうだからやってみました、以上のことがないようなネタですが。本当はvmstatとかfreeとかもやろうかと思ったけど、まんまlinuxと同じ情報があるわけでなし、なにを出力するか考えるのも面倒になってきたのでなんちゃってシリーズはこれでおしまいかな。
ま、そうはいっても今回はCPU時間とかオーナー情報の取得でちとてこずったので、そこらへんを別記事にまとめる予定。
コメント
トラックバック
このエントリのトラックバックURL: http://dara-j.asablo.jp/blog/2008/06/17/3581400/tb
※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。

コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※なお、送られたコメントはブログの管理者が確認するまで公開されません。