JScriptでWMI（その２）


## はじめに

以前、[JScriptでWMI（その１）](http://qiita.com/tnakagawa/items/ae579f19d74dd86e40c6)でプロパティの一覧を取得しました。
そこで作ったメソッドを利用するにあたり、特殊な挙動をするもの、クエリの記述方法について記述します。


## Ping

WMIのクラスに「Win32_PingStatus」があります。
これは、クエリに「SELECT * FROM Win32_PingStatus」を設定しても何もおこりません。
（結果は、１行も帰ってきません。）

WHERE句に「Address」を指定してみると、Pingの結果が返されます。

```js
var query = "SELECT Address,StatusCode FROM Win32_PingStatus WHERE Address = '192.168.0.1'";
var props = wmiProps(query);
var csv = props2csv(props);
WScript.Echo(csv);
```

結果は、「StatusCode」に入ってきます。
結果コードは以下のとおりです。（[原文](http://msdn.microsoft.com/en-us/library/aa394350%28v=vs.85%29.aspx)のまま記載してます。）

|Value|Meaning||Value|Meaning|
|:--|:--|:--:|:--|:--|
|0|Success| |11011|Bad Request|
|11001|Buffer Too Small| |11012|Bad Route|
|11002|Destination Net Unreachable| |11013|TimeToLive Expired Transit|
|11003|Destination Host Unreachable| |11014|TimeToLive Expired Reassembly|
|11004|Destination Protocol Unreachable| |11015|Parameter Problem|
|11005|Destination Port Unreachable| |11016|Source Quench|
|11006|No Resources| |11017|Option Too Big|
|11007|Bad Option| |11018|Bad Destination|
|11008|Hardware Error| |11032|Negotiating IPSEC|
|11009|Packet Too Big| |11050|General Failure|
|11010|Request Timed Out| ||


## WQL

### 構文

WMIで設定するクエリは、WQL（WMI Query Language）というものです。
SQLのクエリと似ていますが、異なる部分があります。
（SQLの機能制限版みたいな感じです。）

> __WQL構文__
> SELECT _properties_ FROM _class_ [WHERE _conditions_]

***
_properties_

この部分で使えるのは、各クラスのプロパティ名と「*」です。
サンプルコードでも使っていますが、「*」は全てのプロパティを出力します。
SQLと異なる点として、内部での演算は出来ません。

>__OK__
> SELECT * FROM Win32_Process
> SELECT Caption,ProcessID,WorkingSetSize FROM Win32_Process
> __NG__
> ~~SELECT Caption,FileSystem,Size - FreeSpace FROM Win32_LogicalDisk WHERE DriveType = '3'~~

***
_class_

クラスの部分は、WMIクラスを指定します。
主に使うのが「Win32 Provider」に属するクラスです。
SQLと異なる点として、１つのクラスしか指定できません。

***
_conditions_

条件を指定する部分です。
条件の接続は、括弧「()」、かつ「AND」、または「OR」が使えます。

また、値の条件式は
演算子として、等しい「=」、未満「<」、以下「<=」、より大きい「>」、以上「>=」、等しくない「<>」
が利用できます。

また、「IS NOT NULL」「IS NULL」「LIKE」も利用出来ます。

> __ドライブCとDの情報__
> SELECT * FROM Win32_LogicalDisk WHERE DeviceID = 'C:' OR DeviceID = 'D:'
> 
> __ドライブCとDで空き容量が１G未満の情報__
> SELECT * FROM Win32_LogicalDisk WHERE (DeviceID = 'C:' OR DeviceID = 'D:') AND FreeSpace < 1048576
>
> __SQL関連のサービス情報__
> SELECT * FROM Win32_Service WHERE Name LIKE '%SQL%'


### datetime

WMIで利用するdatetime型のフォーマットは、`yyyymmddHHMMSS.xxxxxx±UUU`となっています。
そこで、JScriptのDate型から、datetime型の生成、datetime型フォーマットで出力の２メソッドを作成しました。
`UUU`の±が通常とは逆に設定するようで、わかりづらくなりそうなのでUTCを設定しています。

```js
function wmiDate(date) {
    var datetime = null;
    if (date && date instanceof Date) {
        // 「SWbemDateTime」オブジェクト生成
        datetime = new ActiveXObject("WbemScripting.SWbemDateTime");
        datetime.Year = date.getUTCFullYear();                     // 年
        datetime.Month = date.getUTCMonth() + 1;                   // 月
        datetime.Day = date.getUTCDate();                          // 日
        datetime.Hours = date.getUTCHours();                       // 時
        datetime.Minutes = date.getUTCMinutes();                   // 分
        datetime.Seconds = date.getUTCSeconds();                   // 秒
        datetime.Microseconds = date.getUTCMilliseconds() * 1000;  // ミリ秒
    }
    return datetime;
}

function wmiDateFormat(date) {
    var ret = null;
    if (date && date instanceof Date) {
        ret = date.getUTCFullYear()                         // 年
            + ("0" + (date.getUTCMonth() + 1)).slice(-2)    // 月
            + ("0" + date.getUTCDate()).slice(-2)           // 日
            + ("0" + date.getUTCHours()).slice(-2)          // 時
            + ("0" + date.getUTCMinutes()).slice(-2)        // 分
            + ("0" + date.getUTCSeconds()).slice(-2) + "."  // 秒
            + ("00" + date.getUTCMilliseconds()).slice(-3)  // ミリ秒
            + "000+000";                                    // ナノ秒＋UTC
    }
    return ret;
}
```

これを利用すると、本日0時以降のイベントデータの取得などが出来ます。

```js
var now = new Date();
var date = new Date(now.getYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
var wmidate = wmiDateFormat(date);
// var wmidate = wmiDate(date);
var query = "SELECT Category,EventCode,Message,TimeWritten FROM Win32_NTLogEvent WHERE TimeWritten >= '" + wmidate + "'";
var props = wmiProps(query);
var csv = props2csv(props);
WScript.Echo(csv);
```

一応、WMIのdatetime型からJScriptのDate型へ戻すメソッドも作成しました。

```js
function wmiDate2date(datetime) {
    var date = null;
    try {
        // 変換
        date = new Date(Date.parse(datetime.GetVarDate()));
    } catch (e) {
        // エラーの場合
        date = null;
        // throw e;
    }
    return date;
}
```