chkconfig.js2008年06月15日 06時19分04秒

またくだらんモノ作ったなぁ

くだらんと思いつつも、chkconfig風にWindowsサービスの起動方法を確認したり変更したりするユーティリティスクリプト作ってみました。

いや、前回のservice.cmdの引数に渡す「サービス名」を確認するのが主な目的だったんだけど、起動方法の変更とかもなんとなくできそうだったのでやってみたらできたってことで。

ソース

こんな感じ。例によって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("");
};
var SvcMgr = function() {
  this.wmi = new ActiveXObject("WbemScripting.SWbemLocator").ConnectServer();
};
SvcMgr.prototype = {
  list : function(name) {
    var query = "SELECT Name, DisplayName, Description, StartMode, State FROM Win32_Service";
    if( name ) query += " WHERE Name = '" + name + "'";
    return new Enumerator( this.wmi.ExecQuery( query ) );
  },
  change : function(name, value) {
    this.list(name).each( function(service) {
      service.ChangeStartMode( value );
      throw $break;
    } );
  },
  exec : function(params) {
    if( params[0] && params[0].toLowerCase() == "--list" ) {
      // --list
      var max = 39;
      this.list( params[1] || false ).each( function(service) {
        echo( [
          service.Name.length < max ?
            ( service.Name + " ".repeat(max) ).substr(0, max) : service.Name,
          service.StartMode
        ].join(" ") );
      } );
    } else if( params[0] && params[0].toLowerCase() == "--detail" && params[1] ) {
      // --detail
      this.list( params[1] ).each( function(service) {
        echo( "サービス名 : " + service.Name );
        echo( "表示名     : " + service.DisplayName );
        echo( "スタートアップの種類 : " + ( {
          "Boot" : "ブート",
          "System" : "システム",
          "Auto" : "自動",
          "Manual" : "手動",
          "Disabled" : "無効"
        }[ service.StartMode ] || service.StartMode ) );
        echo( "状態       : " + ( {
          "Running" : "実行中",
          "Stopped" : "停止中"
        }[ service.State ] || service.State ) );
        echo( "説明 : " );
        echo( "  " + ( service.Description || "(no description)" ) );
        echo( "" );
        throw $break;
      } );
    } else if( params[0] && ! /^--/.test(params[0]) && params[1] ) {
      // change startmode
      var mode = {
        "auto" : "automatic",
        "sys" : "system",
        "man" : "manual",
        "dis" : "disabled"
      }[ params[1] ] || params[1];
      this.change(params[0], mode);
      this.exec( [ "--list", params[0] ] );
    } else {
      echo( "使い方 : [cscript | wscript] chkconfig.js --list [サービス名]" );
      echo( "         [cscript | wscript] chkconfig.js --detail サービス名" );
      echo( "         [cscript | wscript] chkconfig.js サービス名 [ Boot |" );
      echo( "                                                       System |" );
      echo( "                                                       Automatic |" );
      echo( "                                                       Manual |" );
      echo( "                                                       Disabled ]" );
      echo();
    }
  }
};

new SvcMgr().exec( args.unnamed );

これをcscript経由で起動するバッチファイルを%SystemRoot%にでも入れておけばよいかと。

使い方

そのまま起動すると使い方は表示されるのでだいたいわかると思いますが、以下の3種類の引数を受け付けます。

  1. --list [サービス名]
  2. <サービス名> <起動方法>
  3. --detail <サービス名>

--list [サービス名]

「--list」はサービスの起動方法を確認します。こんな感じ。

C:\Documents and Settings\dara-j>cscript chkconfig.js --list
AcPrfMgrSvc                             Auto
AcSvc                                   Disabled
Alerter                                 Disabled
ALG                                     Disabled
AppMgmt                                 Manual
aspnet_state                            Manual
AudioSrv                                Auto
  :
 (中略)
  :
WudfSvc                                 Manual
WZCSVC                                  Auto
xmlprov                                 Manual

C:\Documents and Settings\dara-j>

各行はサービス名と起動方法が出力されます。

ここに表示されるサービス名は管理ツールの「サービス」で表示される「表示名」ではなく、内部のサービス名で、前回のservice.cmdに(というか、net startやnet stopに)渡すサービス名はこれになります。

--listの後ろにサービス名をつけると、そのサービスの情報のみが表示されます。

C:\Documents and Settings\dara-j>cscript chkconfig.js --list iisadmin
IISADMIN                                Auto

C:\Documents and Settings\dara-j>

また、パイプでfindstrにつないでもいいかもしれません。
C:\Documents and Settings\dara-j>cscript chkconfig.js --list | findstr -i vnc
winvnc                                  Auto

C:\Documents and Settings\dara-j>

findstrは-i(Ignore Case)がよいでしょう。サービス名うろ覚え時にぜひ。

<サービス名> <起動方法>

サービスの起動方法を変更します。Linuxのようなランレベルの概念はないため、--level <levels>のようなパラメータは必要なく、on/off/resetの代わりに「Boot」「System」「Automatic」「Manual」「Disabled」の5種類の指定が可能です(が、「Boot」と「System」はよくわかりません。指定しても反映されてるやらされてないやら)。

実行すると、設定反映後の状態を出力します。

C:\Documents and Settings\dara-j>cscript chkconfig.js w3svc disabled
W3SVC                                   Disabled

C:\Documents and Settings\dara-j>cscript chkconfig.js w3svc automatic
W3SVC                                   Auto

C:\Documents and Settings\dara-j>

ちなみに大文字小文字は区別されません。

--detail <サービス名>

これは本家chkconfigには相当する機能はないのですが、オマケで実装してみました。指定サービスの詳細を表示します。

C:\Documents and Settings\dara-j>cscript chkconfig.js --detail iisadmin
サービス名 : IISADMIN
表示名     : IIS Admin
スタートアップの種類 : 自動
状態       : 実行中
説明 :
  インターネット インフォメーション サービスのスナップインを使用した Web と FTP
サービスの管理を提供します。

Enter キーで終了します>

C:\Documents and Settings\dara-j>

ちょっとした解説

たいしたことはしてないのですが、WMIでWin32_Serviceクラスを扱っています。サービスの列挙は

SELECT * FROM Win32_Service
ってのが基本で(実際は取得するプロパティを限定してますが)、WHERE句でサービスを限定したり、返ってきたインスタンスに対してChangeStartModeメソッドを実行して起動方法を変えたりしています。

参考リンク

コメント

コメントをどうぞ

※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。

※なお、送られたコメントはブログの管理者が確認するまで公開されません。

名前:
メールアドレス:
URL:
コメント:

トラックバック

このエントリのトラックバックURL: http://dara-j.asablo.jp/blog/2008/06/15/3578148/tb

※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。