JScriptでWMI（その３）


## はじめに

以前、[JScriptでWMI（その１）](http://qiita.com/tnakagawa/items/ae579f19d74dd86e40c6)でプロパティの一覧を取得しました。
また、[JScriptでWMI（その２）](http://qiita.com/tnakagawa/items/89917ca9fbde1c2f47a9)で、特殊な挙動や、クエリの記述方法について書きました。

今回は、WMIオブジェクトを取得し、操作してみます。

## オブジェクト取得

WMIのオブジェクト取得は、以前と同様に「ExecQuery」メソッドからも取得できますが、「Get」メソッドを利用することもできます。

### 「ExecQuery」メソッドを利用した場合

クエリ（WQL）によっては複数取得できてしまう為、配列を返します。
取得できなかった場合は空の配列となります。

```js
function wmiObjects(query) {
    // 結果
    var result = [];
    try {
        // 「SWbemLocator」オブジェクト取得
        var locator = new ActiveXObject("WbemScripting.SWbemLocator");
        // 「SWbemServices」オブジェクト取得（ローカルコンピュータ、名前空間「root\CIMV2」）
        var services = locator.ConnectServer(null, "root\\CIMV2");
        // クエリ実行、「SWbemObjectSet」オブジェクト取得
        var set = services.ExecQuery(query);
        // 「SWbemObjectSet」をJScriptで扱えるように「Enumerator」に変換
        var enumSet = new Enumerator(set);
        // 「SWbemObjectSet」の最後までループ
        while (!enumSet.atEnd()) {
            // 結果設定
            result.push(enumSet.item());
            // 次へ移動
            enumSet.moveNext();
        }
    } catch (e) {
        // エラーの場合
        throw e;
    }
    return result;
}
```

### 「ExecQuery」メソッドを利用した場合

引数としては、オブジェクト（SWbemObject）のパスとなります。
取得できなかった場合はnullとなります。
（エラーが発生してしまうので、nullを返すようにしています。）

文法としては、「クラス」＋「.」＋「キー」＋「=」＋「値」となります。
「クラス」はクエリのFROM句にあたる部分です、「キー」は各クラスによって異なります。
値は、「キー」の値となります。

例えば、「Win32_LogicalDisk」の「C:」ドライブであれば
「キー」は「DeviceID」となり、パスは「Win32_LogicalDisk.DeviceID="C:"」となります。

```js
function wmiObject(path) {
    // 結果
    var result = null;
    try {
        // 「SWbemLocator」オブジェクト取得
        var locator = new ActiveXObject("WbemScripting.SWbemLocator");
        // 「SWbemServices」オブジェクト取得（ローカルコンピュータ、名前空間「root\CIMV2」）
        var services = locator.ConnectServer(null, "root\\CIMV2");
        // 「SWbemObject」オブジェクト取得
        result = services.Get(path);
    } catch (e) {
        // エラーの場合
        result = null;
        //throw e;
    }
    return result;
}
```

### プロパティ

以前では、各クラスのオブジェクトからプロパティ「Properties_」を取得し、そこからプロパティ値を取得していましたが、他にもいくつか方法があります。

```js
// パス設定
var path = "Win32_LogicalDisk.DeviceID=\"C:\"";
// オブジェクト取得
var object = wmiObject(path);
// オブジェクト存在チェック
if (object != null) {
    // プロパティを直接取得
    WScript.Echo("" + object.Caption);
    // 「Properties_」経由での取得　その１
    WScript.Echo("" + object.Properties_.Item("Caption"));
    // 「Properties_」経由での取得　その２
    WScript.Echo("" + object.Properties_("Caption"));


    // オブジェクト情報出力
    WScript.Echo("" + object.GetObjectText_());
}
```

オブジェクト共通の「GetObjectText_」メソッドで、オブジェクトの情報を文字列で取得できます。

## オブジェクト制御

私が良く使うオブジェクト制御についてです。


### プロセス制御

プロセスの制御をやっていきます。

該当するクラスは「Win32_Process」です、プロセスの場合同名で、複数存在する場合があるので「wmiObjects」メソッドの方を利用します。

サンプルなので、「notepad.exe」プロセスを対称とします。

したがって、クエリは以下となります。
「SELECT * FROM Win32_Process WHERE Caption = 'notepad.exe'」

#### 優先度の設定

「Win32_Process」クラスの「SetPriority」メソッドを利用して優先度を設定します。

引数の優先度は以下の表のとおりです。

|値（10進数）|値（16進数）|説明|
|:--|:--|:--|
|256|0x100|リアルタイム|
|128|0x80|高|
|32768|0x8000|通常以上|
|32|0x20|通常|
|16384|0x4000|通常以下|
|64|0x40|低|

戻り値が結果となりますが、「0」の場合成功で、それ以外は失敗です。

```js
// クエリ設定
var query = "SELECT * FROM Win32_Process WHERE Caption = 'notepad.exe'";
// オブジェクト取得
var objects = wmiObjects(query);
// オブジェクト数分ループ
for (var i = 0; i < objects.length; i++) {
    // オブジェクト取得
    var object = objects[i];
    // 設定する優先度（通常以上）
    var priority = 32768;
    // 優先度設定
    var result = object.SetPriority(priority);
    // 結果判定
    if (result == 0) {
        // 成功
    } else {
        // 失敗
    }
}
```

__※注意※__

プロパティにも「Priority」という項目がありますが、
「SetPriority」メソッドと値が異なりますので注意してください。

|優先度|プロパティのPriority|SetPriorityで設定する値|
|:--|:--|:--|
|リアルタイム|24|256|
|高|13|128|
|通常以上|10|32768|
|通常|8|32|
|通常以下|6|16384|
|低|4|64|

__「リアルタイム」の設定は管理者権限がないとできません。__
また、 __管理者権限で動いているプロセスの優先度は管理者権限以外では変更できません。__

#### プロセスの終了

「Win32_Process」クラスの「Terminate」メソッドを利用してプロセスを終了させます。

戻り値が結果となりますが、 ~~「0」の場合成功で、それ以外は失敗です。~~
（サンプルのnotepad.exeの場合、戻り値が5であってもプロセスは終了しました・・・）

```js
var query = "SELECT * FROM Win32_Process WHERE Caption = 'notepad.exe'";
// オブジェクト取得
var objects = wmiObjects(query);
// オブジェクト数分ループ
for (var i = 0; i < objects.length; i++) {
    // オブジェクト取得
    var object = objects[i];
    // プロセスの終了
    var result = object.Terminate();
    // 結果判定
    if (result == 0) {
        // 成功
    } else {
        // 失敗
    }
}
```

---

### サービス制御

Windowsサービスの制御をやっていきます。
該当するクラスは「Win32_Service」です、サービスの場合複数取得する事がないので「wmiObject」メソッドの方を利用します。

キーは「Name」となります。
（「Name」はサービスのプロパティにある、「サービス名」です。）

サンプルなので、「Windows Update」サービスを対称とします。
この場合の「Name」は「wuauserv」となります。

#### サービスの起動

「Win32_Service」クラスの「StartService」メソッドを利用してサービス起動させます。

```js
// パス設定
var path = "Win32_Service.Name='wuauserv'";
// オブジェクト取得
var object = wmiObject(path);
// オブジェクト存在チェック
if (object != null) {
    // サービスステータスチェック
    if (object.State == "Stopped") {
        // サービス起動
        object.StartService();
    }
}
```

#### サービスの停止

「Win32_Service」クラスの「StopService」メソッドを利用してサービスを停止させます。

```js
// パス設定
var path = "Win32_Service.Name='wuauserv'";
// オブジェクト取得
var object = wmiObject(path);
// オブジェクト存在チェック
if (object != null) {
    // サービスステータスチェック
    if (object.State == "Running") {
        // サービス停止
        object.StopService();
    }
}
```

#### サービス制御を行うにあっての注意

* __管理者権限でスクリプトを起動しないと、サービス制御は出来ません。__
* __メソッドが終わっても、起動、終了は完了していません。__

---