• WMIを用いた DNS操作 をPowershellで書く

    あるイベント起動で、「AD統合DNSのCNAMEの指すAレコードを変える」、ということをしたい。
    イベントハンドリングはとりあえずおいといて、スクリプトでDNSのCNAMEを変更する方法を探す。

    やっぱりというかなんというかWMIにしっかりと用意されていた。
     DNS WMI Classes (Windows)

    PowershellはWMIオブジェクトも扱えるので、こんな感じに。

    $cnames = gwmi -Class MicrosoftDNS_CNAMEType -Namespace Root\MicrosoftDNS -ComputerName DCコンピュータ名
    $cname = $cnames | ? {$_.OwnerName -eq "cname.example.com"}
    $cname.Modify($null, "some.example.com.")

     
    特定のCNAMEを表すMicrosoftDNS_CNAMETypeだけすぱっと取得したかったが、全CNAMEを取る方法しか分からなかったので場当たり的にWhere-Objectで絞り込む。とても無駄な感じ。

    • CNAMEもAレコードも事前に作成してある前提なので、見つからない場合を考えていない。
    • 適切な権限が必要。

    環境:
     Windows XP Pro SP3 x86
      Powershell 1.0
     Windows Server 2008 Standard x64
      Active Directory
      DNS

  • jscriptから WMIを使ってレジストリキー/値列挙

    regコマンド+query操作の方が手っ取り早くはある。。。

    ↓のページに書かれているように、VBScriptだとStdRegProvオブジェクトにEnumKey/EnumValuesなどのメソッドが生えているが、jscriptからだとこれらがない。
     Writing WMI Scripts in JScript (Windows)

    StdRegProvをGetして、
    var locator = new ActiveXObject("WbemScripting.SWbemLocator");
    var server = locator.ConnectServer(computer, "root\\default");
    this.stdregprov = server.Get("StdRegProv");

    呼び出したいメソッド用の入力パラメータを入れる箱のインスタンスを取得して、呼び出したいメソッド用のパラメータ設定をし、
    var in_param = this.stdregprov.Methods_.Item(method_name).InParameters.SpawnInstance_();
    in_param.hDefKey = hkey;
    in_param.sSubKeyName = key;

    StdRegProvにメソッドを呼び出してもらい、
    var out = this.stdregprov.ExecMethod_(method_name, in_param);

    呼び出したメソッドに合わせて結果を取り出す(EnumKeyの例)
    var names = [];
    if(out_param.sNames != null)
    {
    names = out_param.sNames.toArray();
    }
    return names;


    WMIを経由したことでリモートコンピュータに対しても同じコードで処理出来るのはメリットかも。
    しかし、
    •  regコマンドqueryでもリモートコンピュータのキーを列挙できる
    •  リモートコンピュータに対してレジストリ参照するには、当該コンピュータでWindows RPCが動作していて、なおかつWindows Firewallにはじかれないこと
    ので注意。ちまちまと複数のキーを列挙しないといけない状況で外部コマンドをぽこぽこ起動したくない or 一時ファイルを作りたくない、とするならばjscriptで完結するのはいいかもしれない。

    HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall配下を列挙するサンプル。
    例によって無保証です。利用は自己責任で。
    WScript.Echo()しているのでcscript.exeで実行を推奨。

    (function() {

    var Registry = function () {
    this.initialize.apply(this, arguments);
    };

    Registry.prototype = {
    initialize: function(computer) {
    var locator = new ActiveXObject("WbemScripting.SWbemLocator");
    var server = locator.ConnectServer(computer, "root\\default");
    this.stdregprov = server.Get("StdRegProv");

    this.HKCR = 0x80000000; // HKEY_CLASSES_ROOT
    this.HKCU = 0x80000001; // HKEY_CURRENT_USER
    this.HKLM = 0x80000002; // HKEY_LOCAL_MACHINE
    this.HKUS = 0x80000003; // HKEY_USERS
    this.HKCC = 0x80000005; // HKEY_CURRENT_CONFIG

    this.REG_SZ = 1;
    this.REG_EXPAND_SZ = 2;
    this.REG_BINARY = 3;
    this.REG_DWORD = 4;
    this.REG_MULTI_SZ = 7;
    },

    do_method: function(method_name, hkey, key, value_name) {
    var in_param = this.stdregprov.Methods_.Item(method_name).InParameters.SpawnInstance_();
    in_param.hDefKey = hkey;
    in_param.sSubKeyName = key;
    if(value_name != null)
    {
    in_param.sValueName = value_name;
    }
    var out = this.stdregprov.ExecMethod_(method_name, in_param);
    return out;
    },

    EnumKey: function(hkey, key) {
    var out_param = this.do_method("EnumKey", hkey, key);
    var names = [];
    if(out_param.sNames != null)
    {
    names = out_param.sNames.toArray();
    }
    return names;
    },

    EnumValues: function(hkey, key) {
    var out_param = this.do_method("EnumValues", hkey, key);
    var value_names = [];
    if(out_param.sNames != null)
    {
    value_names = out_param.sNames.toArray();
    }
    var value_types = [];
    if(out_param.Types != null)
    {
    value_types = out_param.Types.toArray();
    }

    return {
    Names: value_names,
    Types: value_types
    };
    },

    GetStringValue: function(hkey, key, name) {
    // REG_SZ
    var out_param = this.do_method("GetStringValue", hkey, key, name);

    // 値が存在しない場合null
    return out_param.sValue;
    },

    GetExpandedStringValue: function(hkey, key, name) {
    // REG_EXPAND_SZ
    var out_param = this.do_method("GetExpandedStringValue", hkey, key, name);

    // 値が存在しない場合null
    return out_param.sValue;
    },

    GetDWORDValue: function(hkey, key, name) {
    // REG_DWORD
    var out_param = this.do_method("GetDWORDValue", hkey, key, name);

    // 値が存在しない場合null
    return out_param.uValue;
    }
    };

    var enum_installs = function(reg, base_key)
    {
    var names = reg.EnumKey(reg.HKLM, base_key);
    for(var i = 0 ; i < names.length; i++)
    {
    WScript.Echo(names[i]);

    var sub_key = base_key + "\\" + names[i];
    var values = reg.EnumValues(reg.HKLM, sub_key);

    var value_names = values.Names;
    var value_types = values.Types;

    for(var j = 0 ; j < value_names.length; j++)
    {
    var value_name = value_names[j];
    var value_type = value_types[j];
    var val = "";
    switch(value_type)
    {
    case reg.REG_SZ:
    val = reg.GetStringValue(reg.HKLM, sub_key, value_name);
    break;
    case reg.REG_EXPAND_SZ:
    val = reg.GetExpandedStringValue(reg.HKLM, sub_key, value_name);
    break;
    case reg.REG_DWORD:
    val = reg.GetDWORDValue(reg.HKLM, sub_key, value_name);
    break;
    }

    if(val == null)
    {
    val = "";
    }

    // 改行をつぶしちゃう
    val = val.toString().replace(/[\x0a\x0d]/g, " ");
    WScript.Echo(["", value_name, value_type, val].join("\t"));
    }
    }

    };

    var computer = WScript.Arguments.Named("computer");
    if(!computer)
    {
    computer = ".";
    }

    var reg = new Registry(computer);

    enum_installs(reg, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall");
    enum_installs(reg, "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"); })();

    環境:
    Windows XP Professional SP3
    Windows Vista Ultimate SP2 x64
    Windows Server 2008 SE x64