Welcome to TechNet Blogs Sign in | Join | Help

管理者は見た!~AD と ILM 一家の秘密~

あらまあ Microsoft Japan の ADSI / ILM / WMI /PCNS
サポートチームのブログなんですってよ奥様!(本当)

★よりぬき ILM 一家さん★

Download 系 Link

おすすめ Blog!

免責事項

必見リンク (AD 系)

必見リンク (WMI)

私たちってこんな人たち

[Windows 7] 前夜祭!秋葉原カフェソラーレであなたと握手!

皆さんごきげんよう、ういこです。
気づいたら、Windows 7 が明日ラウンチでございます。そんな緊迫した状況の中、本日 19 時から秋葉原カフェソラーレにおいてシステムビルダー主催の前夜祭が行われます。
ぜひ皆様お越しくださいませ!福引もあるようでございます。

詳細はこちら!
http://www.win7mania.com/launchevent/

ちなみに各ショップさんで、オリジナル前夜祭イベントも開催されるようです。
http://www.win7mania.com/launchevent/sboriginal/

私もいきたいのですが、今日は子供のお迎えなので行けません…。血涙を流したくなるほど残念でございます。 が、チームの誰かは行くみたいです。

Windows 7 は、Beta からいじったりしていますが、製品版、本当にいい感じです。
Windows 98 リリース直前の Windows 95 時代に購入して以来、なんと 11 年ぶりに私も自腹でノート PC (某社の Netbook) を購入し、Windows XP から Windows 7 製品版に入れなおして使っていますが、本当にストレス無く動いてます。ドライバのアンマッチも ACPI ドライバ以外特に無く、また電源関連で変な動作もしていないので満足しています。マウスユーティリティ for Windows XP も動くし。(※ 私のネットブックの場合です。デバイスや構成によって変わる可能性があるので、念のため、各ベンダー様に確認してくださいね。)

動きも軽いし、スペックバリバリじゃないけど軽めのネットブックとの相性の良さにいい意味で裏切られた気分です。社員としての使命感抜きで本当によいです。リモートデスクトップでサーバ管理できればいいや!という方や、Security からシン クライアント Love なあなたにも自信を持って薦められます。

皆さん、よろしくおねがいします!

ういこう@非公式キャラクターかわいい

[ILM/MIIS] Delta Import より Full Import のほうが早いときがある

みなさん御機嫌よう。ういこです。
今日 2009/10/08 はリンゴ台風以来の凄い台風が列島縦断しています。子供の学校はサックリ休みになっております。学童クラブからは、朝 8:30 から預かるが、空気を読んで自粛してほしいというメールを頂きましたが、断腸の思いでお弁当を持たせて行かせてしまいました…。(旦那がバイクで連れて行きました。)お弁当作るのって本当に大変です。奥様に作っていただいている世の旦那様、「いつもありがとう」の言葉と、せめて弁当箱くらいは洗ってあげてくださいね。でないと、微妙に不満や怨念が蓄積されていくかもしれませんよ。洗ってくれなくても言葉くらいはマジでほしいです。語らなくても通じるなんてうそです!!絶対に。ちなみに少なくとも私は蓄積されます。

と、まあ微妙に怨念が台風のように渦巻くのはさておき、今日のお題は、最近本業の ILM を忘れたような感じになってるので、ILM のことについて。

【今日のお題】
Active Directory / ADAM の MA を使ってます。Full Import は遅いので、Delta Import にしたいと思ってますがどうでしょう。

【回答】
結論からいうと、必ずしも Full Import より Delta Import のほうが早いとは限りません
場合によってはむしろ Full Import のほうが早い場合があります。

では、それはなぜか。まず、Active Directory / ADAM のマネージメントエージェント (MA) を例にとり、各 Import 処理はどんなことをしているか見てみましょう。

1. Import の処理ってどんなことをしているの?
・Full Import
ADAM および Active Directory の MA の Full Import では、LDAP API を使用し、接続先ディレクトリに存在するすべての対象オブジェクトに対してクエリーを実行します。たとえば、MA の "Select Object Types" プロパティ シートで指定されているオブジェクト クラスすべてを対象としてクエリーを実行する、というようなことが可能です。
Full Import で収集された情報には、特定オブジェクトに格納されているすべての属性値などがあります。
ILM も、最終更新時に関する情報を格納しているため、この情報は Delta Import でも使用することができます。

・Delta Import
Delta Import では、[Configure Partitions] ダイアログの [Containers] ボタンおよび [Deleted Objects] コンテナで設定されたコンテナのオブジェクトを対象としてクエリーを実行します。ADAM および Active Directory のマネージメント エージェントの Delta Import では、LDAP API と DirSync LDAP コントロールを併用します。DirSync LDAP コントロールを使用することにより、直近に成功した Full Import 以後、変更のあったディレクトリに対してのみ、クエリーを実行することが可能です。このような処理が可能なのは、Import した全オブジェクトのオブジェクト ステート情報を格納しているためです。

…これを見ていただいても、Delta Import は、クエリーを実行するのが、最後の Import 以後に変更の生じた箇所のみであるため、Full Import と比較し、Delta Import の実行時間がかなり短縮されるという以外に、何があるのだろう?といぶかしまれるかもしれません。

しかしながら、この、「最後の Import 以後に変更の生じた箇所」をチェックする、というところが実は誤解しやすいポイントなのです。ディレクトリのすべてオブジェクトあるいは大半が更新されるなど、大量の更新があった場合は Full Import の方が効率的な場合もあります。
実際、Delta Import でも Full Import の実行時間と変わらない場合や、逆に非常に遅くなることまであるのです。

2. Delta Import のコスト
Delta Import についてもう少し詳しく見てみましょう。
Active Directory は、 オブジェクトの属性に Update Sequence Number(USN) を持っています。
Delta Import では、コネクタ スペース (CS) 内のオブジェクトと Import 動作時に AD にアクセスし、USN 値を比較して差分を検出し、差分更新の生じているオブジェクトの Import を実施しています。
データ数が少ない状況ですと、Delta Operation は Full Operation と比較するとこれらの差分確認処理を含めても処理件数、プログラム コードの処理数的にも優位ですが、これが数万件単位になるとこの差分処理がオーバーヘッドとなります。
さらに、アクセスしにいくのは AD だけではありません。CD オブジェクトを参照し、比較する際に SQL Server にクエリを投げるのですが、これも処理コストとしては決して少なくない処理です。結果的に Full Operation よりも処理コストが高い処理になる、というからくりなのです。

まとめますと処理コストとなる要素として大きなものは下記となります。

・AD への USN の参照
・SQL Server に対する CS オブジェクトとの比較クエリ

件数が少ない場合、Delta Import のほうが早いというのは、差分が少なければディレクトリアクセスは抑制され、一連の処理で一番件数が増えて影響を受ける SQL クエリの処理の件数が少ないからです。

こうした事情により、更新オブジェクト数がディレクトリのほぼ全てに及ぶような場合、Delta Operetion の生じない Full Import の方が効率が良いことになります。つまり、若干の更新のみが検出されるような動作や運用初期においては Delta Import を通常操作としつつ、定期的に Full Import を施行する、というのが効率がよい運用ということになります。
なぜならば、定期的に Full Importをかけないと、差分が増加を続けるので、結果的に USN の処理も比例的に増加してしまうためです。

以下が公開されている情報でわりと詳しいものかと思います。

Understanding run profiles in MIIS 2003
http://support.microsoft.com/kb/827118/en-us

※ 補足
なお、AD 側でデータを直接登録、変更などを行った際は Full Import を定期的に行うほうが Delta Import の効率化を図れますが、たとえば AD 側で直接データ変更などを行わず、別のデータソースからのデータを Export のみで更新していくような運用であれば、定期的な Full Import は必ずしも有効ではありません。

・初回、AD 上の全オブジェクトが Export 操作により生成される前提条件であれば、Import 対象のオブジェクトはこの Export 操作により更新されていると判断されます。よって全オブジェクトが要更新対象(差分)とみなされますので、その後 Delta Import を行っても全てのオブジェクト属性が収集されます。

・Full Sync を以前行った日が半年以上前など、Active Directory における既定の TombStone 期間よりも前である場合、ドメインのオブジェクトの移動や削除に関する正しい情報が、データソースから得られないため、CS オブジェクトが無効となる恐れがあります。この場合、一旦 CS オブジェクトを削除し、Full Import と Delta Sync をやり直すことをお勧めします。

3. Delta Import と Full Import の所要時間逆転の閾値はシステムに依存する
残念ながら Delta Import と Full Import の所要時間が逆転する閾値に相当するかどうかの判断は、お客様の動作環境、ネットワーク構成および実際の動作状況から判断する必要があります。
また、ディレクトリ アクセスと SQL 負荷のどちらが、MIIServer サービスに影響を与えているかは、構成に依存するため、帯域、CPU 負荷、ハードディスクアクセスの状態など複数の要素によって状況が左右されるということがあり、ILM の製品的に一意の閾値は存在しません。
実際の運用の実績ベースの RunHistory からの更新件数、処理時間などから、判断する必要があります。

ではみなさんごきげんよう。

ういこう@うずまきといえば伊藤潤二先生だと思う

[~W2K8 / W2K8R2] Windows on Windows (WOW) の最大サポート CPU 基数はいくつ?

皆様御機嫌よう、ういこです。
今日は、せっかく今期から Windows SDK 一家の軒下を借りるようになったので、たまには Windows API についてのことでも書いてみようと思います。
Windows API というか、Windows の仕組みの話になっちゃいますが…。

Windows Server 2008 R2 から、64bit CPU に特化されましたことは、これまでのサーバー製品が 64bit 版にどんどんシフトしていっている流れ的にさもありなん、という感じはあったものの、ついにきたなという思いでした。ただ、64bit CPU が出てかなり時間が経つとはいえ、既存のアプリケーション資産は 32bit でビルドされたもの(32bit Windows 上で動作することを想定して作成されたものという意味)がまだまだ現役で動いている、という状況が大半ではないでしょうか。

Windows On Windows (WOW)
Windows OS では、64bit OS 上でも、32bit アプリケーションを動作させる仕組み "Windows On Windows" というサブ システムがあります。32bit アプリケーションは、このサブ システム上で動作します。あくまでもサブ システムなので、エミュレーションしているようなものです。そのため、厳密に 32bit Windows と同じ動作にはならないことがあることに注意しなくてはなりません。昔、Windows が出始めのころ、コマンド プロンプト上で DOS アプリケーションを動かした方で、挙動が微妙に違うと悩んだかたもいらっしゃるでしょう。それと同じことになることを頭に入れる必要があります。

CPU の最大サポート基数について
サーバー上で動作させるアプリケーションである場合、WOW 上で動作させるにしても、プロセッサを最大限使いたいというかたもいらっしゃると思います。そうした場合、WOW はいったい何基までの CPU をサポートするのでしょうか?
答えは、32 基までとなります。ドキュメントは、残念なことに本社の人にも聞いてみましたが、以下の MSDN のドキュメントくらいしか書いていないようです。

Processor Affinity (プロセッサの親和性)
http://msdn.microsoft.com/en-us/library/aa384228(VS.85).aspx

<--- 抜粋ここから ---->
32-bit Windows supports a maximum of 32 processors.
Therefore, functions such as GetProcessAffinityMask
simulate a computer with 32 processors when called under WOW64.
<--- 抜粋ここまで ---->

・Windows Server 2008 までの場合 (64bit アプリは 64 基、WOW は 32 基)
64 bit Windows OS の内部では、アプリケーションの動作の際に 64bit プラットフォーム上で動作することを前提としてビルドされているか、それ以外を対象としてビルドされたものかという判断を行っています。プロセッサ数は、MAXIMUM_PROCESSORS という定数で設定されており、以下のとおりとなります。

64bit アプリケーションの場合 64 基

それ以外の場合 32 基

・Windows Server 2008 R2 の場合 (64bit アプリは 256 基だが WOW は相変わらず 32 基)
Windows Server 2008 までの Windows の仕組みでは、ロック機構の実装にまだまだ改善の余地があり、64 基以上のプロセッサの場合動作が遅くなる可能性などがあり、上記のように 64 基までということになっていました。しかし、Windows Server 2008 R2 では、ある一人のすごい人がこのロックの実装ロジックを解決することができたそうです。(うわさではその人は勇者としてリアルにアワードをゲットしたとか…)

また、R2 では、CPU が複数あるマルチコア環境下で、Non-Uniform Memory Access (NUMA) の強化が行われています。
NUMA というのは耳慣れない言葉かと思いますが、実は結構前から概念はあったようです。これは、CPU をグループとして管理し、効率よく使おうとする見たいなことのようです。(プロセッサ グループはカーネルが決定) このグループ化の仕方がいい感じになり、1 スレッドを処理するコア = 1 論理プロセッサとして扱い、同一コア中の論理プロセッサ、同一の物理プロセッサ内のコア、物理に近い論理プロセッサなど、近隣の論理プロセッサ同士を同一のグループにすることで、バスのデータ転送の効率を上げようともくろんだようです。ちなみに NUMA グループは "ノード" という言葉で表現されるみたいです。

そして、256 基までサポートされるならば WOW もあわよくばサポート基数が増えたのでは…と思ったのですが、残念ながら WOW はあいかわらず 32 基でございます。
また、物理スロットは 64 基までです。なのに 256??

…実は、この 256 のからくりは、64 基 x 最大 4 ノード = 256 基、ということでして、なぜ WOW は 32 基なのかというと、32 基 x 1 ノード = 32 基ということだったりするのでした。

WOW 上での動作を見る際はお気をつけくださいませ。

ういこう@明日は小学校が臨時休校!?

[WMI] C++ で 2 つ以上の引数を与えてメソッドを実行するには? 2 / (2)

みなさん御機嫌よう、ういこです。
前回はお題が WMI C++ で 2 つ以上の引数をメソッドに与える方法についてなのに、VBScript やら C# やらで書いていてどうよ?って思われた方もいらっしゃるかと思います。すみません。

【お題 : C++ で WMI - メソッドに二つ以上引数を渡したいの】
前回はこちら。タイトル変えました。
[WMI] C++ で 2 つ以上の引数を与えてメソッドを実行するには? 1 / (2)
https://blogs.technet.com/jpilmblg/archive/2009/10/06/wmi-c-2-1-2.aspx

※ 前回のあらすじ ※
Windows を管理するには最高のパートナーの WMI。しかし、その実態は某大戦中の某国の大型戦車のように威力はすごいが足が遅かった!1 ターンでの移動力が 1 Hex 位しか進まないとまでは行かなくても。そんな WMI を改良すべく、スクリプトだと量がすごいすくないのはわかっていても、あえて C++ で動かそうと考えた熱い魂をもつ漢(おとこ)たち。しかし、MSDN には引数を一個しか指定しない感じのサンプルしかない。C# とかも微妙に参考にならない感じだ。
どうする!?

【はじめに】
早速、ExecQuery を…と思う前に、まあまあはやる心を抑えましょう。
C++ の場合は、自分で認証情報などをつけないといけないのです。C# や、VBScript などでよしなにしてくれた処理も、自分でやらなくてはならないのです。そこが大変な上に、コード量ももりもり増えます。

・IWbemService のプロキシが使用する認証情報を明示的に設定する必要がある。

(特に、リモートでアクセスする場合など)
WMI のプログラムのプロセス実行ユーザーがリモート コンピュータの管理者権限を持たない場合は、ConnectServer() で    管理者権限を持つユーザーの名前とパスワードを指定していても、ExecQuery() でアクセス拒否されてしまいます。
リモート コンピュータ上の情報を取得する際には、リモート コンピュータ上の WMI の実装が DCOM 経由で呼び出されます。この際、リモート コンピュータ上で実行されるスレッドのユーザーは適切な権限を持つユーザーである必要があるのです。この、リモートコンピュータ上で実行されるスレッドのユーザーを指定するには、CoSetProxyBlanket() を使用します。

ちなみに CoSetProxyBlanket() の第 7 引数がポイントです。NULL を指定した場合は「ローカル コンピュータ上で実行しているユーザー」として、リモート コンピュータ上でもスレッドを実行することを意味します。実行ユーザーとは別のリモート コンピュータ上で管理権限を持つユーザーとして、リモート コンピュータ上のスレッドを実行するには、CoSetProxyBlanket() の第 7 引数でユーザーを明示的に指定してあげてください。
それと、ふるーいバージョン Service Pack などがないの Windows XP では CoQueryProxyBlanket() の第 2 引数に DWORD のポインタを渡すように対応してください。Windows Server 2003 では修正されて出荷されているのですが、NULL を渡すと Access Violation が発生する不具合があります。XP のサービスパックなしバージョンなどで動作させようとすることもシステム要件に含む場合は注意してください。

1. ExecQuery() メソッドで、以下の WQL 文を発行します。

例 :
仮想マシン名「Windows Server 2003 (x86)」に対してシャットダウンを行う場合

    1 IEnumWbemClassObject* pEnumerator = NULL;

    2 hres = pSvc->ExecQuery(

    3 bstr_t("WQL"),

    4 bstr_t("SELECT * FROM Msvm_ComputerSystem WHERE ElementName='Windows Server 2003 (x86)'"),

    5     WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,

    6     NULL,

    7     &pEnumerator);

2. IEnumWbemClassObject から仮想マシンの GUID (Name) を列挙し、Get() メソッドで VARIANT 型の変数に格納します。

   10 IWbemClassObject *pclsObj = NULL;

   11 ULONG uReturn = 0;

   12 

   13 VARIANT vtProp;

   14 

   15 while (pEnumerator)

   16 {

   17     HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);

   18     if(0 == uReturn)

   19     {

   20         break;

   21     }

   22 

   23     // Get the value of the Name property

   24     hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);

   25     wcout << " VM's Name : " << vtProp.bstrVal << endl;

   26 

   27     pclsObj->Release();

   28     pclsObj = NULL;

   29 }

3. 上記ステップ 2. で取得した仮想マシン名を用いて、Msvm_ShutdownComponent クラスをクエリします。

   32 IEnumWbemClassObject* pVmshout = NULL;

   33 bstr_t WQL = _T("SELECT * FROM Msvm_ShutdownComponent WHERE SystemName='");

   34     WQL += vtProp.bstrVal;

   35     WQL += _T("'");

   36 

   37     VariantClear(&vtProp);

   38 

   39     hres = pSvc->ExecQuery(bstr_t("WQL"),

   40                         WQL,

   41                         WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,

   42                         NULL,

   43                         &pVmshout);

4. IEnumWbemClassObject を列挙し、Msvm_ShutdownComponent クラスのパスを取得します。

   44     hr = pclsObj->Get(L"__Path", 0, &vtProp, 0, 0);

※ デバッガ上でみたクラスのフルパス = vtProp のデータ例 (実際には改行はありません) 検証端末名 : UIKOUTEST2008

   46     vtProp BSTR = "\\UIKOUTEST2008\root\virtualization:    Msvm_ShutdownComponent.CreationClassName="Msvm_ShutdownComponent",    DeviceID="Microsoft:9F8233AC-BE49-4C79-8EE3-E7E1985B2077",

5. ConnectServer() の呼び出しの際に指定した IWbemServices オブジェクトを用いて Msvm_ShutdownComponent クラスを取得します。

   50 bstr_t ClassName = _T("Msvm_ShutdownComponent");

   51 

   52 IWbemClassObject* pClass = NULL;

   53 hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);

 

6. ステップ 5. で取得した Msvm_ShutdownComponent クラスの InitiateShutdown() メソッドを取得します。

 

   56 bstr_t MethodName = _T("InitiateShutdown");

   57 

   58 IWbemClassObject* pInParamsDefinition = NULL;

   59 hres = pClass->GetMethod(MethodName, 0,

   60 &pInParamsDefinition, NULL);

 

7. SpawnInstance() を使用してインスタンスを取得します。

 

   63 IWbemClassObject* pClassInstance = NULL;

   64 hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);

8. InitiateShutdown() メソッドの引数をPut() メソッドを使用して指定します。
以下の例では、InitiateShutdown() メソッドの引数 Force に true を、第二引数 Reason に文字列を指定します。なんと、わかれば単純!この形式でどんどん Put していけばよいのですね。

   67 // Create the values for the in parameters

   68 VARIANT varCommand;

   69 varCommand.vt = VT_BOOL;

   70 varCommand.boolVal = true;

   71 hres = pClassInstance->Put(L"Force", 0,&varCommand, 0);

   72 VariantClear(&varCommand);

   73 

   74 varCommand.vt = VT_BSTR;

   75 varCommand.bstrVal = L"Because I want to do it.";

   76 hres = pClassInstance->Put(L"Reason", 0,&varCommand, 0);

   77 VariantClear(&varCommand);

 

9. ステップ 4. で取得した Msvm_ShutdownComponent クラスのパスを ExecMethod() に指定し、InitiateShutdown() メソッド (第二引数 MethodName) を実行します。

   80 IWbemClassObject* pOutParams = NULL;

   81 hres = pSvc->ExecMethod(vtProp.bstrVal, MethodName, 0,

   82 NULL, pClassInstance, &pOutParams, NULL);

【注意点】
・ドメイン非参加の PC からリモート PC 上の管理者権限ユーザを指定してもアクセス拒否されることがある

ちなみにドメインに参加していない PC (Windows XP など) の既定の設定では、ネットワーク経由でのアクセスの際に認証されたユーザーはリモートコンピュータ上で Guest の権限のみを持ちます。このため、WMI を使ってリモート コンピュータ上の情報を取得する際に、リモート コンピュータ上での管理者権限を持つユーザーを指定してアクセスした場合でも、アクセスを拒否されることがあります。
この設定はローカル セキュリティ ポリシー管理ツールの以下の項目で変更可能です。

[セキュリティの設定]
- [ローカルポリシー]
- [セキュリティ オプション]
- [ネットワーク アクセス:ローカル アカウントの共有とセキュリティ モデル]

この項目を、「クラシック - ローカルユーザーがローカルユーザーとして認証する」に変更することで、ネットワーク アクセスの際に認証されたユーザがリモートコンピュータ上で、認証されたユーザーとしての権限を持つように変更できます。
なお、ドメインに参加している Windows XP 上ではネットワーク アクセスの際に認証されたユーザーは、リモートコンピュータ上でそのユーザーとしての権限を持ちます。ちなみに、Windows Server 2003 のデフォルトの設定では、この設定は「クラシック」に設定されています。

参考 :
エラー メッセージ : Access Denied; Specified User Is Not a Member of TelnetClients Group
http://support.microsoft.com/default.aspx?scid=kb;ja;298060

image 

image

【おまけ : 一連の処理をもっとわかりやすくしてみたです & 行番号がないコピペ対応版】

BSTR methodName = SysAllocString(L"InitiateShutdown");

BSTR className = SysAllocString(L"Msvm_ShutdownComponent");

 

IWbemClassObject *pClass = NULL;

hres = pSvc->GetObject(className, 0, NULL, &pClass, NULL);

 

IWbemClassObject *pInParamsDefinition = NULL;

hres = pClass->GetMethod(methodName, 0, &pInParamsDefinition, NULL);

 

IWbemClassObject *pClassInstance = NULL;

hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);

 

VARIANT varCommand;

varCommand.vt = VT_BOOL;

varCommand.boolVal = true;

VARIANT varCommand2;

varCommand2.vt = VT_BSTR;

varCommand2.bstrVal = L"Because I want to do it.";

 

pClassInstance->Put(L"Force",0,&varCommand,0);

pClassInstance->Put(L"Reason",0,&varCommand2,0);

 

hres = pclsObj->Get(L"__PATH", 0, &vtProp, 0, 0);

 

IWbemClassObject* pOutParams = NULL;

hr = pSvc->ExecMethod(vtProp.bstrVal, methodName,0,NULL,pClassInstance,&pOutParams,NULL);

if (FAILED(hr))

{

wcout << " Could not shutdown" << hex << hr << endl;

}

 

_bstr_t bstrret("ReturnValue");

BSTR ret;

hr = pOutParams->GetObjectText(0, &ret);

cout << "Return Value: " << ret << endl;

 

VariantClear(&varCommand);

VariantClear(&varCommand2);

pclsObj->Release();

pclsObj = NULL;

以上です。

それにしても、なんだかブログへの風当たりが強い今日この頃。わかりやすくて、使えるブログを目指しておりますので、皆さんこれからも応援していただければ幸いです。

ういこう@I Love メカニカルキーボード

[WMI] C++ で 2 つ以上の引数を与えてメソッドを実行するには? 1 / (2)

みなさん、大変ご無沙汰しておりました。ういこです。
しばらく心身ともに調子が悪く、ブログもやめようかな…と悩んでおりました。
しかし、会計年度も変わり、そろそろ年末も見えてきたあたりで復活しようかなと思いつつあります。またひとつよろしくお願いいたします。

なぜか前会計年度では Windows Media テクノロジーのサポートチームと同じチームでしたが (※ US も同じ構成ですが、いまだになぜ一緒なのか謎) 今期から Windows SDK のチームとさらにくっつき、最近は普通に API 案件などもやっていたりします。なぜ Windows Media と ILM / ADSI、Windows SDK が一緒なのか、それはきっと足が飾りだと思う必要がないレベルのえらい人にしかわからない何か事情があるんでしょう。というわけで、今後は SDK 案件も書いていくことになると思いますがよろしくお願いします。

…相変わらず前置き長くてすみません。本題に入らせていただきますです。
さて復活第一弾は、ILM ねたでいこうかなと思いましたが、現在稼働中の案件もいくつかあるので、あえて WMI を。…今回も文章、長いですよ…。というか、一回にしようと思いましたが、コード長すぎなんですみません。

続きはこちら。タイトル変えました。
[WMI] C++ で 2 つ以上の引数を与えてメソッドを実行するには? 2 / (2)
http://blogs.technet.com/jpilmblg/archive/2009/10/06/wmi-c-2-2-2.aspx

【お題 : C++ で WMI - メソッドに二つ以上引数を渡したいの】
WMI。それはシステム管理者様にとって、一見いいことずくめな感じなもの。スクリプトを気合で組めば、何だって自動化できちゃうぞ!人のマシンだってシャットダウンできちゃうぞ(※注 : それ相応のシステムの管理権限必要)!と、野望や夢も膨らむってもんですが、問題はえっらい遅いこと。
そんな「WMI 遅い」問題に果敢に挑み C++ で実装いただいている漢(おとこ)たちもいらっしゃいます。(あるいはこれまでの既存 C 資産に WMI を組み込む必要がある方々など…。)しかし、いかんせんコード量が多い。多いのです。スクリプトや、.NET Framework アプリとして C# や VB.net などで組んだ場合と比較してコード量が半端じゃありません。

何気に WMI はドキュメントが多いほうです。C++ も例外ではありません。英語ばっかりではあるものの拳でわかりあうように、コードをとりあえずコピペして動きに思いを馳せるってやりかたができるので割と敷居は低いほうのプロダクトです。
ただ、C++ の場合、メソッドを実行したいと思っても、複数個引数を与えるメソッド実行、どうやったらいいかって思ったことありませんか?今回は、C++ で WMI、複数引数でメソッド実行について、Msvm_shutdownComponent の InitiateShutdown() メソッドを例にとり、二回に分けてお話させていただきます。

例を挙げましょう。Windows Server 2008 の Hyper-V 上の OS をシャットダウンするというものです。 それぞれ、wmic コマンドを使った場合、VBScript の場合、C# の場合から見ていきます。C++ は次回のお楽しみです。

[1] WMIC コマンドの場合
WMIC コマンドを使った例です。まず、仮想マシンの名前が "Windows 7" のものをシャットダウンします。

1. GUID をゲットする
仮想マシン名から、仮想マシンの GUID をとってきます。このとき、Msvm_ComputerSystem を使います。

※注意 : 必ずコマンドプロンプトは権限を昇格させ、管理者で実行してください。

wmic /namespace:"\\root\virtualization" path Msvm_ComputerSystem where ElementName='Windows 7' get name

image

2. Msvm_shutdownComponent を使って、上記 1. を使いシャットダウンさせます。

メソッドは InitiateShutdown です。一つ目の引数 true は強制終了の意味、二つめはあのよくサーバを落とす際にかかされる「終了の理由」です。下記の引数に与えているオレンジ色の GUID は、上記 1. でとってきた GUID をコマンド プロンプトからコピペしてきたものです。

wmic /namespace:\\root\virtualization path Msvm_shutdownComponent where systemname='5EDE3587-0CF3-4C0A-913F-9BEAB8E84C83' call InitiateShutdown true,"てすと"

image

↑ただしく実行されると、ReturnValue = 0 で返されてきます。

↓シャットダウンされます

image

[2] VBScript の場合
wmic だと二行ですが、ちょいと増えます。ただ、systemname にあたるところも変数を使えるので、いちいち人間が name を取得してコピペしないですむので、作成の工数はかかりつつ、その後は格段に楽です。

' <==== ここから
Option Explicit
Dim vmshut
Dim VMName
Dim WMIObject
Dim VM
Dim VMList
Dim vmReturn

VMName = "Windows 7"

Set WMIObject = GetObject("winmgmts:\\.\root\virtualization")
Set VMList = WMIObject.ExecQuery("SELECT * FROM Msvm_ComputerSystem WHERE ElementName='" & VMName & "'")
VM = VMList.ItemIndex(0).Name
Set vmshut = WMIObject.ExecQuery("SELECT * FROM Msvm_ShutdownComponent WHERE SystemName='" & VM & "'")
vmReturn = vmshut.ItemIndex(0).InitiateShutdown(True,"てすと")
' <====
ここまで

[3] C# の場合
うわ、ながっ!って思うかも知れません。自分でも今見て、ながっ!と思いましたが、まだまだこれからです。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Management;

namespace ShutDownVM
{
   public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
           // root\virtualization クラスにスコープをあわせる
            ConnectionOptions options = new ConnectionOptions();
            ManagementScope scope = new ManagementScope(@"\\localhost\root\virtualization");
            scope.Connect();

           // Msvm_computersystem クラスを用いて、name を取得
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope,
            new ObjectQuery("SELECT * FROM Msvm_ComputerSystem WHERE ElementName = 'Windows 7'"));
            IEnumerator enumr = searcher.Get().GetEnumerator();
            enumr.MoveNext();
            ManagementObject msvm_computersystem = (ManagementObject)(enumr.Current);
            ManagementObjectCollection collection = msvm_computersystem.GetRelated("Msvm_ShutdownComponent");
            ManagementObjectCollection.ManagementObjectEnumerator enumerator =
            collection.GetEnumerator();
            enumerator.MoveNext();
            ManagementObject msvm_shutdowncomponent = (ManagementObject)enumerator.Current;

            // InitiateShutdown() メソッドの引数を指定
            ManagementBaseObject inParams =
            msvm_shutdowncomponent.GetMethodParameters("InitiateShutdown");           
            inParams["Force"] = true;
            inParams["Reason"] = "てすと";

            // InitiateShutdown() メソッドの実行
            ManagementBaseObject outParams =
            msvm_shutdowncomponent.InvokeMethod("InitiateShutdown", inParams, null);
            uint returnValue = (uint)outParams["ReturnValue"];

           // 処理失敗した場合は 0 以外が返ります
           if (returnValue != 0)
                        Console.WriteLine("失敗したよ");

            }
        }
    }

これを見ると、メソッドをただ実行するのではなく、以下の段階を踏んでいることがわかるかと思います。

1. メソッドの引数 (上記例だと、inParams) を指定する
2. メソッドを実行する

次回は、これを C++ でやるとどんな風かというのを、C++ 固有の処理も含めてご紹介させていただきます。

さて、このブログを初めてごらんいただく皆様もいらっしゃるかと思います。また、気がついたらブログ開設から一年とっくに過ぎておりました。
当初、ILM / MIIS という率直に言って決して今のところ、裾野が広いとは言い切れない分野に情報が提供できれば、またサポート契約でどうしても対応できない範囲やわかっていればお問い合わせいただく手間も必要ないような FAQ な事例などをご紹介しようと思い始めたブログですが、気がついたら WMI やら PowerShell やら担当製品が微妙に増加してしまい、今となっては何でもありというかそもそも、technet である必要があるのかもさっぱりわからないカオスな状態になっています。文章もカオスで、マイクロソフトのサポートチームなのか胡散臭いかもしれませんが、お役立ち度数は文章の胡散臭さの絶対値以上のものを目指しております。
今後ともよろしくお願いいたします!

ういこう@某国民的 GF な恋愛ゲームを誕生日プレゼントにだんなからもらいました

[PowerShell] PowerShell のコマンドって?

こんにちは、ILM一家のパパ(お父さん)です。

昨日、連休が明け、久しぶりに ILM一家のメンバーと顔を合わせました。
普段、リアル家族より長い時間を過ごす仲間で、なんか安心します。

リアル家族といえば、先月、娘のペットのハムスターがお亡くなりになり、新しい子をお迎えすることとなりました 。
行き着けのペットショップに行くと、そこには星となったハムスター(没名”ココア”ですが)と瓜二つのの子が...
結局、その子が新たな家族の一員となり、名前を "マロン" としたのですが、あまりにも前の子とそっくりなので、娘もつい前世の ”ココア” と呼んでしまいます。職業病でしょうか、私はその子を "ココア R2" と呼称していますが、お母さん(ういこさん) に言わせると "ココア MarkⅡ" が格好いいらしいです。やっぱ、ガン○ム 思考なんでしょうか... (※ 2009/10/06 ういこうより : 同じ「日の出系」ですが、むしろ思考はエ○ガイムか吉田拓郎です。)
ちなみに、ハムスターの名前の由来は色で、栗毛(ダウというらしい)長毛サテンで綺麗な毛艶だからだそうです。
見た目で、初代ハムを "ちゅうちゅう”、2代目を ”もこもこ” と命名する娘の思考は、今も変わりません...

さて、今回も PowerShell をいろいろ見ていきたいと思います。
前回、”get-help *” で使用できる、Alias、Cmdlet、HelpFile を列挙できる事を書きましたが、コマンドについて少し参照情報を絞り込んで見ましょう。

ここまでで使用した "get-help""get-help *" で列挙された Cmdlet を見て、お気づきなられたでしょうか。
PowerShell では操作を明示する、[動詞-名詞] のペアでコマンド名が定義されています。
何かを取得したい場合、"get-xxxxx" となりますし、逆に設定であれば "set-xxxxxxx”  といった名称の Cmdlet となります。

そのため、取得系の提供コマンドに絞って情報参照したい場合、"get-help get-*" (* はワイルドカード)とすれば、取得系コマンドのみを列挙することが可能です。

PowerShell01

その他にコマンド操作を明示する動詞には ”add”"clear"”copy”"enable"”disable” その他、多数が用いられます。どのような動詞があるかは、Cmdlet を列挙してみるのが良いかと思います。

ここでは  "get-command" を使用してみましょう。"get-command" では引数 -CommandType でコマンドタイプを限定することが可能です。"get-command -CommandType Cmdlet" と入力すると、Cmdlet(コマンドレット)のみが列挙されます。

PowerShell02

いかがでしょうか、PowerShell のコマンドで何かしたい場合、したい操作(動詞部分)を指定し "get-help" 試される事をお勧めします。標準のコマンドレットについては、このようにコンソール上で使用機能を検索、機能参照する事が可能です。(使用される機能によっては、"import-module" によるパッケージ参照動作が必要となりますが、コマンドを参照列挙したい場合の基本操作は同じです。)よろしければ、お試し下さい。

もっと、PowerShell 、Windows 7 をいじり倒したい
~ お父さん より ~

[PowerShell] PowerShell ってどんな感じ?

こんにちは、ILM一家のパパ(お父さん)です。
ご無沙汰しており恐縮です。

このところ、忙しくしていた我々 ILM一家ですが、この 5連休は追加の夏休みをいただいた感じです。
追加といっても、会社からいただいた夏休みが 2日残っていて如何しようか悩んでいる状況ですが...

この休みは、娘と ディズニーシーに行ってきました。
もう、半端な混み方ではなかったですね、200分待ちのアトラクションなど尋常ではありません。
ポップコーンも種類によっては買うのに 30分待ちとは、日本人はホント忍耐強い民族です。
私も、娘も、我慢が無いので、乗りたいものはファストパスで乗って、30分待ちぐらいのアトラクションしか並びませんでしたけど... それなりに乗り物乗って、ポップコーン二種類を含め一通り飲み食いできたので満足です。
それにしても歩きますね、車で行って徒歩はディズニーシーの中だけですが 26677歩記録されてます。1歩 60cm換算でも 16Km超えてて、さすがに疲れましたが、最近少し脱メタボをサボってたので丁度よい運動になりました。

さて今回は、この休みに少し PowerShell を Windows 7 で触ってみたので、感触をご紹介しましょう。
みなさん、PowerShell はお試しいただいていますでしょうか?
Windows Server 2008 から OS の追加機能となった PowerShell ですが、Windows 7 でも標準搭載されています。
(Windows Server 2003、Windows XP、Vista ではダウンロード入手いただくことで使用可能です)

Windows 上の 従来のコマンドラインプロンプト(CMD.EXE)では、コマンド機能が DOS 由来のもので、OS 管理機能の多くを、他の実行ファイル(exe)や、スクリプティング(スクリプティングからの COM 呼び出し)などに依存していました。
PowerShell では コマンドラインシェル(CUI)から、今まで、 他の実行ファイル(exe)や、スクリプティング(スクリプティングからの COM 呼び出し)などに依存していた部分を、コマンドレット(Cmdlet) で提供しています。
 
まず PowerShell を 今までの CMD.EXE に替え、コマンドラインシェルとして使用してみましょう。
Windows 7(手元では Ultimateを使用しています) のスタートメニューからは、管理ツール内の "Windows PowerShell Modules" で起動します。

PowerShell_01

起動すると、上記のようにコンソールが開き表示されますが、慌てる必要はありません。
指示通りに "get-help about_signing” と入力してみましょう。以下のようにヘルプ表示されます。

PowerShell_02

Windows 7 環境の既定では、スクリプトの実行権限が与えられていないので警告が出ていた状況ですが、ヘルプメッセージの通り、”set-executionpolicy remotesigned” で権限設定すれば、次回以降の PowerShell コンソールの起動で警告が表示されなくなります。
ここで、覚えておいて欲しいのは、判らなくいことは ”get-help" で確認すればよいということです。
”get-help” は引数に、使用したい不明な cmdlet、Alias、HelpFile (about_xxxxx)などを指定して、情報を引き出すことが可能です。

次に、ファイル参照してみましょう。従来の CMD.EXE のように "dir" も使用可能です。

PowerShell_03

PowerShell の "dir" はどのように機能提供されているのか、”get-help” してみましょう。

PowerShell_04 

"Get-ChildItem""dir" という エイリアスがマッピングされている事が判ります。
実際に "Get-ChildItem" でも同様の結果が取得されます。

PowerShell_05 

PowerShell では 、"Get-ChildItem" で、指定したリソースの下位オブジェクトが参照可能です。さきほどの "dir" も実際には従来の “dir” ではありませんので、以下のようにレジストリ参照などもできてしまいます。

PowerShell_04b

ここでは、従来との違いを見て頂きたいために "dir" エイリアスを使いましたが、このような動きを考えると、PowerShell を使っていく上では、"Get-ChildItem" を使用されたほうが構文上自然です。
参照したいレジストリパスが予め判っている場合、コマンドラインで操作できるのは便利ですね。

おまけですが、"ls" エイリアスも用意されており、同様に "Get-ChildItem" にマップされています。
こちらの方が、違和感がない方もいるでしょうし、便利は便利です。

PowerShell_06

コマンドラインシェルとして、従来のコマンドプロンプト風に動かしてみましたが、いかがでしょうか。
ここまでで、興味がありましたら PowerShell コンソール上で "get-help *" を実行してみてください。既定で使用できる Alias、Cmdlet、HelpFile が列挙されます。さらに、詳細を知りたい場合、”get-help” の引数に、確認したい Alias、Cmdlet、HelpFile を指定して再実行すれば詳細が表示されます。    

PowerShell は今まで、コマンドラインやスクリプティングでできなかったことが実現可能です。
ILM 一家では、従来のスクリプトでの困りごとや、運用事例との対比で PowerShell の優位な部分について、ご紹介できればと考えています。

これから夏休みを取りたい
~ お父さんより ~

[WinRM] Windows Remoe Management を使って、らくらく管理!- その1

こんにちは。今週末に バリウム を飲みにいくのでぷるぷる震えている ぴろと です。

先日、お父さんと Windows Remote Management ( 以下、WinRM) について話あっていたのですが、どうやら US では、WinRM と WMI のサポートチームは一緒だということが判明しました。そのため、私たちの Blog でも WinRM を取り上げなくては!ということで、第一弾として、さっぱり簡単レシピをご紹介させていただきます。(最近、仕事と ETロボコンに追われて Blog を書けてませんでした。ぴろとファンの皆様申し訳ございません)

- そもそも WinRM ってなんですか?

WinRM は、WS-Management プロトコルのマイクロソフト実装です。WS-Management プロトコルは、さまざまなベンダが提供するハードウェアやオペレーティング システムの相互運用を可能にする標準的なファイアウォールに対応した SOAP ベースのプロトコルです。というのは大袈裟な言い方ですが、WinRM により、HTTP や HTTPS などの標準的なインターネット プロトコルを使用してコンピュータをリモート管理できるようになります。

ここで、標準的なファイアウォールに対応というところがいいですね! 最近の流行は、何でも HTTPS (Windows Server 2008 R2 の Hosted Mode で使用されるのも HTTPS) ですし、WMI を用いたリモート管理の場合、Port 135 (Remote Procidure Call) のポートが開いてなくてはいけませんものね!

構成を行うのも、割と簡単です。以下のサポート技術情報を参考ください。

How to enable Windows Remote Shell
http://support.microsoft.com/kb/555966/en-us

これで、あなたの端末も WinRM で管理できちゃいます。

また、WMI と同じくスクリプトでの管理も容易です。”Hey,Scripting Guy!” にて公開されているスクリプトがあったので、あわせてご紹介させていただきます。

Hey, Scripting Guy! あの世からのデスクトップ管理
http://technet.microsoft.com/ja-jp/magazine/2007.11.heyscriptingguy.aspx

Hey, Scripting Guy! 帰ってきた WinRM
http://technet.microsoft.com/ja-jp/magazine/2007.12.heyscriptingguy.aspx

すごいネーミングセンスですね!”帰ってきた”と聞くと、”帰マン” とか “新マン”とかを連想する人が多いチームメンバーたちに囲まれて、軽いジェネレーションギャップを感じざるを得ないのはここだけの話です。

VB や C# を使って開発されている場合は、WMI みたいに System.Management 名前空間を用いて開発されているかと存じます。WinRM は、WinRM Scripting API と WinRM C++ API が用意されています。オートメーション インタフェースが公開されているので、WinRM Scripting API を使って実装できます。次回は、サンプルを含めて実装を行っていく予定です!

今後は、WMI だけではなく ”WinRM” も Blog で盛り上げて行きたいと思いますので、どうぞよろしくお願いいたします!

~ すぐにコースアウトするミニ四駆しか作れない ぴろと より~

[MSDN/Technet] ついに Windows7 提供開始!ダウンロード可能になりました。(Ver1.01)

みなさんごきげんよう。ういこです。無事、アメリカから帰国しました。帰国後は素敵な時差ぼけや、お弁当作りでギブアップしたりいろいろでした。

さて、今日は Windows 7 がついに MSDN サブスクライバー ダウンロードに Up されたことをご報告申し上げます。どうやら昨日 up された様子です。(Technet もです!)

MSDN サブスクライバ ダウンロード ログイン
http://msdn.microsoft.com/ja-jp/subscriptions/dd179326.aspx

(8/7 11 AM update1)
日本時間の深夜 2 AM に Up されたようです。 ちなみに、Windows Server 2008 R2 はまだのようです。(8/7)

Professional
Home Premium
Home Basic (※ x86 のみ)
Ultimate
Enterprise
Starter (※ x86 のみ)
デバッグ シンボル(x86, x64)

Windows 自動インストール キット (WAIK) 言語パックの日本語版も Up されています。

Ultimate、Enterprise のみ、FileTransferManager からのダウンロードに制限があるようです。
[ダウンロード] ボタンがクリックできません。
Top Download サイトからは、後述の Akamai のダウンロード マネージャを使ってダウンロードするようになっています。

しかし、早速ログインしてはやる気持ちがあるのはわかるのですが、まあいまはひとまず落ち着きましょう。いきなり罠があります。日本人であると、わりと「言語 : Japanese」が最初から選ばれている状態が多いと思うのですが、ここを「言語 : English」にしないと、左ペインの “Windows 7” を選んでも、ダウンロード候補出てきません。まだ英語版しかないからなんですね。

image

↑ここを、こうします↓

image

これで、Windows 7 を左ペインで選べば、出てきますよ。ただ、よく見ると、「ダウンロード」リンクがグレーアウトしてるので、一瞬あせりますが、”詳細情報” をクリックすればよいです。

image

詳細情報をクリックしたところです。

image

詳細情報をクリックすると、したが展開され、まあ要は青字の Top Downloads をクリックしろってことですね。クリックすると、以下のリンクに行きます。ここで注意が。

https://msdn.microsoft.com/ja-jp/subscriptions/downloads/bb608344.aspx

"下記の一覧で項目をクリックすると Top Subscriber Downloads (ダウンロード サブスクライバ ランキング) の一部にアクセスできます。この新しい機能にアクセスするには、Akamai Technologies Download Manager Browser アドオンをインストールしてこれらのファイルにアクセスする必要があります。"

・・・つまり、ダウンロードは、今までの File Transfer Manager ではない、Akamai なんとかって言うのが使われるように変更されたのです。つまり、すでに他の OS やらなにやらを MSDN サブスクライバーダウンロードから落としたことがある環境でも、Ultimate / Enterprise 落とすためには、新しい ActiveX を入れなくてはいけないのです。(8/7 現在) これに、20 秒くらいかかることがあります。気長に待ちましょう。

image

上記より、iso イメージのリンクをクリックすると、こんな風にでます。

image

そして、ActiveX のダウンロードが開始されます。インストールしないと、スーパーマリオの 8-4 みたいに、上記ページの無限ループになるので必ず入れてください。

image

インストールする、を選んでください。

image

ダウンロードが開始されます。

image

ここまでいけばあとはこっちのもんです。ダウンロードしまくってください。

それでは、取り急ぎですが皆様 Windows 7 をかわいがってあげてください!よろしくお願いします。

~ ういこう

[ADSI プログラミング] お役立ちツールのご紹介

こんにちは、 ILM 一家のパパ ( お父さん ) です。
今週は、一家のお母さん(ういこさん)がいない、非常に寂しい日々を送っています。 ピロトと二人で留守を守り、指折り数えて帰りを待ってます。また、今月は余暇も非常にバタバタしていまして、ブログ書き込みもお休みがちでした、読者の方すみません。

さて、寂しさのあまりテンションも低い状況ですが、気を取り直してお役立ち情報をご紹介することにしましょう。
過去に製品の管理ツール、サポートツール、リソースキット等のユーティリティをご紹介しましたが、我々サポートエンジニアが、その他、トラブルシュートや動作の診断に使用しているツールは他にも多数あります。

まず、サイトを見ていただきましょう。

Windows Sysinternals
 http://technet.microsoft.com/ja-jp/sysinternals/default.aspx

ここで紹介しているツール類は 10年以上前から使っていたものですが、以前は 他社(Sysinternals 社)のツールとしてご紹介に難がある状況がありました。2006年に マイクロソフトが買収したことにより Technet のサイトに内包されることとなっています。
このサイトには、我が Blog で扱っている ADSI、WMI、ILM のみでなく、一般的な Windows トラブル、プログラミングトラブルの診断に使用できるツールが数多く登録されています。

ADSI , WMI プログラミングで有効と考えられるツールとしては、以下のようなものがあります。

AD Explorer (英語)
Active Directory Explorer は、Active Directory (AD) の高度なビューアーおよびエディターです。

AD Insight (英語)
AD Insight は、Active Directory クライアント アプリケーションのトラブルシューティングを目的とした LDAP (ライトウェイト ディレクトリ アクセス プロトコル) リアルタイム監視ツールです。

AdRestore (英語)
削除した Server 2003 の Active Directory オブジェクトを復元します。

TCPView (英語)
アクティブなソケットを表示するコマンドライン ビューアーです。

AccessChk (英語)
このツールでは、ファイル、レジストリ キー、Windows サービスに対して、指定したユーザーやグループが持つアクセス権を確認できます。

AccessEnum (英語)
シンプルかつ強力なセキュリティ ツールです。システム上のディレクトリ、ファイル、およびレジストリ キーについて、どのユーザーがどのアクセス権を持っているかどうかを確認できます。このツールを使用すると、アクセス許可のセキュリティ ホールを見つけることができます。

Process Explorer (英語)
プロセスが開いたファイル、レジストリ キーなどのオブジェクト、読み込んだ DLL などを調べます。この非常に強力なユーティリティでは、各プロセスの所有者も表示できます。

PsTools
PsTools スイートには、ローカル コンピューターまたはリモート コンピューターで実行されているプロセスの一覧の取得、リモートでのプロセスの実行、コンピューターの再起動、イベント ログのダンプなど、さまざまな操作を行うためのコマンド ライン ユーティリティが含まれています。

なお、以下のようなスクリーンセーバもあるようですが、どうしたものでしょう.... サポート担当者としては微妙な気持ちです。

BlueScreen (英語)
このスクリーン セーバーは、ブルー スクリーンを正確に模した画面を表示するだけでなく、CHKDSK を含む再起動を模した画面も表示します。このユーティリティは、Windows NT 4、Windows 2000、Windows XP、Server 2003、および Windows 9x で使用できます。

いかがですか?
使えそうなツールはありますでしょうか。
またの機会に、この中の幾つかを具体的に紹介したいと思います。

今週は ろんりーはーと な
~ お父さんより ~

[AD/ADAM] 10000件以上のデータが登録された環境でサーバソートすると 0x8007202C (3)/4 – DirectorySearcher.VirtualListView

みなさんごきげんよう、ういこです。
これまでは、大量データ保持の AD / ADAM に対してソートを行う際の問題についてお伝えしてまいりました。今回は、回避策として、Virtual List View が使えるか?という内容です。

【問題】
10000 件以上、大量に ADAM および AD にオブジェクトが登録されている環境に対し、ソートを実行すると

"サーバーは要求された重大な拡張子をサポートしていません。(0x8007202C)"

というエラーが返され、ソートができない。しかし、Name など一部の属性では問題なく動作する。 ただし、降順ソートの場合、すべての属性に対してソートができず、上記エラーが発生する。

【解説】Active Directory の大容量データに対するサーバソートについて
(1) 昇順ソート ~ インデックスつき属性と、インデックスなし属性での挙動の違い

(2) 降順ソート ~ 既知の問題
(3) Virtual List View は対処方法となりえるか?← このコンテンツです!
(4) まとめ (4 回目予定)

- これまでの経緯
サーバ ソート(データをサーバ側で「整える(取得したデータの並べ替えを行う))の昇順ソートの場合は、インデックス化されていない属性をソートキーに指定した場合は、データの並べ替えのためサーバ側で一時的にデータを格納するテーブルが作成され、このテーブル内で指定されたキーによる整列を行います。この一時的なソートに用いられるテーブルのサイズは、"MaxTempTableSize" という LDAP ポリシーで決められており、既定は 10000 です。
ソートする対象のレコード数が MaxTempTableSize を超えた場合、ソート処理は行われません。
一方、インデックス化された属性のソートの場合にはこの一時データ格納テーブルを使わないためこの制限に抵触しません。このため、インデックス化された属性の場合はうまくいき、インデックス化されてない属性をソートキーに指定して昇順ソートを行った場合は上記問題が発生してしまうことになるのでした。
そして、降順ソート時は MaxTempTableSize のサイズ制限抵触以外の問題が存在するため、インデックス化属性であっても降順ソート時大量件数が存在する場合、非インデックス属性の昇順ソート時の動作と同様のエラーが発生する問題があります。この問題は製品の障害となります。そのため、降順ソートを実装する必要があるシステムの場合は、属性のインデックス化は回避手段とはなりません。

- VLV は回避策にならない
MSDN を見ると、VLV は大きなサイズの ResultSet に向いてます、みたいなことが書いてあるのですが、実際は、VLV も Temp tableを使って中間結果を保持することで動作する設計です。しかし、この Temp Table はすなわち MaxTempTableSize が制限値になるため、VLV の計算に必要な中間結果がこの値を超えた場合、昇順ソートのインデックスなし属性がソートキーに指定された場合と同様処理が中断することになります。よって、回避策として有効な手段には残念ながらならないという結論になります。なお、問題発生時のエラーは、非インデックス属性の大量データの昇順ソート実行時と同じく「"サーバーは要求された重大な拡張子をサポートしていません。(0x8007202C)」となります。なお、MaxTempTableSize のサイズをオブジェクト数をカバーする値に変更しますと、正常に Resultset が返されるようになります。

- VLV サンプル コード

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.DirectoryServices;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SearchResultCollection results;
            using (DirectorySearcher searcher = new DirectorySearcher())
            {           
                DirectoryEntry de = new DirectoryEntry("LDAP://CN=Users,DC=corp,DC=contoso,DC=com");
                searcher.SearchRoot = de;
                searcher.Filter = "(objectclass=*)";
                searcher.PropertiesToLoad.Add("samaccountname");
                searcher.PropertiesToLoad.Add("name");
                searcher.PropertiesToLoad.Add("displayName");
                searcher.PropertiesToLoad.Add("mail");
                searcher.SearchScope = SearchScope.Subtree;
                DirectoryVirtualListView virtualList = new DirectoryVirtualListView(0, 50, 10);
                string searchAttributeName = null;
                searchAttributeName = "name";
                SortOption sort = new SortOption(searchAttributeName, SortDirection.Descending);
                searcher.Sort = sort;
                searcher.VirtualListView = virtualList;
                results = searcher.FindAll();
                if (results.Count >= 0)
                {
                    Console.WriteLine(searcher.VirtualListView.ApproximateTotal);
                    MessageBox.Show(searcher.VirtualListView.ApproximateTotal.ToString());
                }
            }
        }
    }
}

~ ういこう ~

[AD/ADAM] 10000件以上のデータが登録された環境でサーバソートすると 0x8007202C (2)/4 - 降順ソートの障害
みなさんごきげんよう、ういこです。
今回も、前回と同じく、大量件数保持 AD (or ADAM) に対してのサーバソートについての記事です。ただし、今回は降順ソートの挙動についてとなります。昇順ソートと降順ソート、基本は同じ…はずだと思いきや、じつは昇順ソートと降順ソート、内部実装(プログラムの書き方)自体が異なっているのです。
さらに、降順の場合だけ、障害があり、二重の意味で挙動が異なるという結果となってしまっています。
降順ソートでこの問題にすでに直面されていらっしゃった皆様、弊社製品の不具合のためにご迷惑をおかけしたことをお詫び申し上げます。

【問題】
10000 件以上、大量に ADAM および AD にオブジェクトが登録されている環境に対し、ソートを実行すると

"サーバーは要求された重大な拡張子をサポートしていません。(0x8007202C)"

というエラーが返され、ソートができない。しかし、Name など一部の属性では問題なく動作する。 ただし、降順ソートの場合、すべての属性に対してソートができず、上記エラーが発生する。

【解説】Active Directory の大容量データに対するサーバ ソートについて
(1) 昇順ソート ~ インデックスつき属性と、インデックスなし属性での挙動の違い

(2) 降順ソート ~ 既知の問題  ← このコンテンツです!

(3) Virtual List View は対処方法となりえるか?(3 回目予定)
(4) まとめ (4 回目予定)

- これまでの経緯
サーバ ソート(データをサーバ側で「整える(取得したデータの並べ替えを行う))の昇順ソートの場合は、インデックス化されていない属性をソートキーに指定した場合は、データの並べ替えのためサーバ側で一時的にデータを格納するテーブルが作成され、このテーブル内で指定されたキーによる整列を行います。
この一時的なソートに用いられるテーブルのサイズは、"MaxTempTableSize" という LDAP ポリシーで決められており、既定は 10000 です。
ソートする対象のレコード数が MaxTempTableSize を超えた場合、ソート処理は行われません。
一方、インデックス化された属性のソートの場合にはこの一時データ格納テーブルを使わないためこの制限に抵触しません。
このため、インデックス化された属性の場合はうまくいき、インデックス化されてない属性をソートキーに指定して昇順ソートを行った場合は上記問題が発生してしまうことになるのでした。

- 降順ソート時の現象およびその原因
降順ソートに関しては、MaxTempTableSize のサイズ制限抵触以外の問題が存在し、インデックス付与済みの属性もこの問題の影響を受けてしまいます。昇順ソートと降順ソートは、同じ処理ではありません。内部でどちらのソートを実行するかという目印(フラグ)の値を保持しており、処理が分岐しています。
インデックス化属性であっても降順ソート時大量件数が存在する場合、非インデックス属性の昇順ソート時の動作と同様のエラーが発生する問題があります。この問題は製品の障害となります。そのため、降順ソートを実装する必要があるシステムの場合は、属性のインデックス化は回避手段とはなりません。
実は、この問題は修正リクエストが米国にて行われたのですが、修正時の副作用が広範囲になるという判断から修正が見送られたという経緯があります。

- 再現サンプル コード
さて、[Active Directory スキーマ] スナップ インを使い、インデックスがふられていない属性にインデックス化したとします。昇順ソートはうまくいくでしょう。しかし、降順ソートにした場合、解消したはずの "サーバーは要求された重大な拡張子をサポートしていません。(0x8007202C)" がまた発生してしまいます。

<< VBScript の場合 >>
cmd.Properties("Sort On") = "company DESC"

<<.NET Framework の場合>>
ds.Sort.Direction = SortDirection.Descending 

(※) サンプル全文はこちら ⇒ http://blogs.technet.com/jpilmblg/archive/2009/07/24/ad-adam-10000-0x8007202c-1-4.aspx

- 対処方法
対処方法は、LDAP ポリシーの MaxTempTableSize を拡張することだけです。拡張方法はこちらがご参考いただけます。

[AD初級編] AD と ADAM の微妙な違い 2 ~ ntdsutil と dsmgmt で LDAP ポリシーを管理しよう!~ http://blogs.technet.com/jpilmblg/archive/2009/06/25/ad-ad-adam-2-ntdsutil-dsmgmt-ldap.aspx

上記リンクのページの "dsmgmt : ADAM でポリシーを変更する (AD も手順 2 からは共通) " の 7. のところを、以下のようにして、8. の commit changes を実行すればよいだけです。以下は、サイズを 50000 件でも対応できるように拡張した例です。

ldap policy : set MaxTempTableSize to 50000

あらためて弊社製品の問題につきまして製品担当としてお詫び申し上げます。

~ ういこう ~

[AD/ADAM] 10000件以上のデータが登録された環境でサーバソートすると 0x8007202C (1)/4 - 昇順ソートの挙動

みなさんごきげんよう、ういこです。
最近気付いたんですが、このブログって、Technet というより MSDN 寄りなんでしょうか?もしかして浮いてるのでしょうか。
今日のお題は、文字化けの続き…と思ったのですが、Active Directory 関連で、ひとつ重要なケースがあったのでそちらを先に紹介させていただこうと思います。ちょっと長くなるので、3 部作になりそうです。あさってから出張で本社にいってしまうので、それまでに一気に Up します。

【問題】
10000 件以上、大量に ADAM および AD にオブジェクトが登録されている環境に対し、ソートを実行すると

"サーバーは要求された重大な拡張子をサポートしていません。(0x8007202C)"

というエラーが返され、ソートができない。しかし、Name など一部の属性では問題なく動作する。

【解説】Active Directory の大容量データに対するサーバ ソートについて
(1) 昇順ソート ~ インデックスつき属性と、インデックスなし属性での挙動の違い
← このコンテンツです!
(2) 降順ソート ~ 既知の問題 (次回予定)
(3) Virtual List View は対処方法となりえるか?(3 回目予定)
(4) まとめ (4 回目予定)

- はじめに
Active Directory からデータを取ってくる際に、ソートしてデータを取得したい場合があると思います。このときのアプローチは、COM ベースの ADSI を使うのと、.NET Framework の System.DirectoryEntry を使うことになるでしょう。ソートの種類は、大きく分けて二つあります。

・サーバ ソート
・クライアント ソート

ソートされたデータを取得することが最終的な目的になりますが、これらの違いを端的にいえば、データをサーバ側で「整える(取得したデータの並べ替えを行う)」か、クライアント側で整えるかということです。サーバ側でデータを整えてやれば、処理は比較的早いです。しかし、サーバ側でメモリを使う、また後述しますがデータを整えるための一時作業領域の制限などがあるといったデメリットがあります。

一方、クライアント側でデータをもらってから整えるような処理を行えば、サーバの一時作業領域の制限に抵触しないですむものの、処理が遅くなりますし、クライアント側のメモリが必要になってしまいます。
ここいらへんの兼ね合いをどうするか、というのは、それぞれのシステム構成、要件などを総合的に判断する必要がありますので、一意にこれがいいという最大公約数的なソリューションはありません。

この記事がソートを要件に持つアプリケーションの設計の一助になればと考えています。この記事は、サーバ ソートにフォーカスしてご紹介させていただきます。
今日のポイントは、「数万件以上の大容量データが Active Directory に存在する場合のサーバ ソートの挙動」というところです。

- 昇順ソートの場合の現象のトリガーおよび原因
この現象は、サーバ側でソートを行う際、ソート キーにインデックス化されていない属性が指定された場合かつ LDAP ポリシーのソートを行う際のデータの一時格納領域 (MaxTempTableSize) に指定された数以上のデータ数が登録されている場合に発生します。
環境は、Active Directory だけでなく、ADAM でも発生します。トリガーは単純に、登録数です。
昇順ソート時に発生するのは、想定しうる動作であり、障害ではありません。

- 再現サンプル コード
<< サンプル スクリプト >>
'''''''''''''''''''' ここから ''''''''''''''''''
Const ADS_SCOPE_BASE = 0
Const ADS_SCOPE_ONELEVEL = 1
Const ADS_SCOPE_SUBTREE = 2

MsgBox "処理開始します"

Set conn = CreateObject("ADODB.Connection")
Set cmd = CreateObject("ADODB.Command")
conn.Provider = "ADSDSOObject"
conn.Open "ADs Provider"
Set cmd.ActiveConnection = conn

cmd.Properties("Cache results") = false
cmd.Properties("Page Size") = 1000
cmd.Properties("Size Limit") = 1000
cmd.Properties("SearchScope") = ADS_SCOPE_SUBTREE
cmd.Properties("Sort On") = "Name"
'cmd.Properties("Sort On") = "otherLoginWorkstations"
'cmd.Properties("Sort On") = "company"
'cmd.Properties("Sort On") = "department"
'cmd.Properties("Sort On") = "displayName"

cmd.CommandText = "SELECT Name FROM 'LDAP://dc=corp,dc=contoso,dc=com' WHERE objectCategory='user'"

Set rs = cmd.Execute
Wscript.Echo rs.EOF

conn.Close
'''''''''''''''''''' ここまで ''''''''''''''''''
<< .NET Framework サンプル>>
// ソースここから
DirectorySearcher ds = new DirectorySearcher();
ds.CacheResults = false;
ds.SearchRoot = objde;
ds.SearchScope = SearchScope.OneLevel;
ds.Filter = "(objectClass=oskevContact)";
ds.PageSize = 1000;
ds.SizeLimit = intRestrictCount; //制限数指定(ex. 1000)
ds.PropertiesToLoad.Add("company");
ds.PropertiesToLoad.Add("department");
ds.PropertiesToLoad.Add("displayName");
ds.ReferralChasing = ReferralChasingOption.All;
ds.Sort.Direction = SortDirection.Ascending; // or SortDirection.Descending
ds.Sort.PropertyName = "name"; // or company or department or displayName
SearchResultCollection src = ds.FindAll();
// ソースここまで

実は、既定の設定で、10000 件以上のデータが存在する環境に対し、このスクリプトを実行すると、cmd.Properties("Sort On") = "Name" の場合はよいのですが、それ以外の "company" などをソート キーにすると、ResultSet (処理結果) がマイナスで返ってしまいます。あるいは、"サーバーは要求された重大な拡張子をサポートしていません。(0x8007202C)" というエラーが返ります。

image

- なぜ ソートキーに指定した属性によって挙動が違うのか?
インデックス化されていない属性でサーバ側でソートを行い、その結果をクライアント側に渡す場合は、データの並べ替えのためサーバ側で一時的にデータを格納するテーブルが作成され、このテーブル内で指定されたキーによる整列を行います。この一時的なソートに用いられるテーブルのサイズが、前述の "MaxTempTableSize" という LDAP ポリシーで決められており、既定は 10000 です。ソートする対象のレコード数が MaxTempTableSize を超えた場合、ソート処理は行われません。

一方、インデックス化された属性のソートの場合にはこの一時データ格納テーブルを使わないためこの制限に抵触しません。[Active Directory スキーマ] スナップ イン (★) でこれらの属性を見てみると、問題の発生しなかった name 属性はインデックス化されています。

image
一方、現象が発生してしまう company 属性などはインデックス化されていないことがわかります。

image
属性ごとの昇順ソート時の動作の違いはこの「インデックスあり / インデックスなし」という状況から生じているのです。

★ Active Directory スキーマ スナップインの使い方はこちらのリンクに詳しい使い方があります。参考になれば幸いです。

[AD初級編] AD と ADAM の微妙な違い ~管理ツールもちと違う : スキーマ管理ツール編~ http://blogs.technet.com/jpilmblg/archive/2009/06/24/ad-ad-adam.aspx
image

- 対処方法
この現象の対処方法は、以下のとおりですが、ただし一番簡単なインデックス付与は、降順ソート時固有の問題にも影響されるため、昇順ソートだけでよいシステム上でのみの対処としかなりません

-1. MaxTempTableSize 値を拡張する (※変更方法はこちらあるいはこちらをごらんください)
-2. ソートキー対象のスキーマ属性にインデックスを付与する
-3. クライアント側でソートを行う

- 対処方法のメリット、デメリット
上記 3 点は、それぞれメリット、デメリットがあります。環境、アプリケーションの設計などにあわせ、 いずれの方法がよいか検討をお勧めいたします。

-1. MaxTempTableSize 値を拡張する
メリット
・クライアント側の負担が少ない
・アプリケーションの実装を変更する必要がない、もしくは変更が少なくてすむ
デメリット
・レコード件数の増加とともに、常に変更させる必要がある
・値を増加させるとサーバ側のメモリ消費量が大きくなる
・サーバ側の設定を変更する必要がある

-2. ソートキー対象のスキーマ属性ににインデックスを付与する
メリット
・インデックス付き属性に基づくクエリのパフォーマンスの向上が期待できる
・検索文字列を指定するときに、ワイルドカード (*) が使用可能になる
・アプリケーションの実装を変更する必要がない、もしくは変更が少なくてすむ
デメリット
・AD データベース のサイズの増加だけでなく、レプリケーションおよびオブジェクト作成時にもサイズ増加による悪影響を与えることがある(特にマルチバリュー属性の場合)
・値を増加させるとサーバ側のメモリ消費量が大きくなる
・サーバ側の設定を変更する必要がある

-3. クライアント側でソートを行う
メリット
・サーバ側に負担をかけない
・サーバ側の設定を変更する必要がない
デメリット
・クライアント アプリケーション側でソートを行うため、クライアント側のメモリ消費量が増大する可能性がある
・クライアント アプリケーションの動作が遅くなる
・アプリケーションの実装を変更する必要がある

- クライアント ソート
サーバ側に負担をかけたくない場合は、ADO.NET などを使用し、クライアント側に処理を持たせる "クライアント カーソル" の機能の実装も有効でしょう。クライアント側でレコードセットに "Page Size" 属性を設定することにより一回の検索につき、一ページ分のレコードの取得を行うようになります。
これは、サーバ側でも同様で、一回の検索につき、クライアントから要求されたレコード数のみのキャッシュを作成し、クライアントに送信します。このとき、クライアント側カーソルを使用している場合、サーバは 1 ページ分のレコードをクライアントに提供し、次のページのデータ要求が発生するまで、検索を一時停止します。この方法でも、一回につきある程度まとまったデータを取得するため、効率の向上が期待できます。
以下の技術情報に一例が載っていますので、ぜひごらんください。

"Windows 2000 または Windows Server 2003 LDAP クエリを並べ替えるため
に、 distinguishedName 属性は使用できません。"
http://support.microsoft.com/default.aspx?scid=842637

Visual Basic .NET で ADO レコードセットを使用する方法
http://support.microsoft.com/kb/315974/ja

~ ういこう ~

[Info] Windows 7 & Windows Server 2008 R2 の開発完了しました!

おひさしぶりです。ういこです。

7 月も気付いたらもう終わりな勢いですが、皆様いかがお過ごしでしょうか。夏休みに入ってしまったため、学童クラブに子供を朝からいかせているのですが、お弁当が必要という状態で…。朝早く起きて弁当作ってチャリで会社まで爆走してるとコアダンプしそう death。(食事中の皆様ごめんなさい) だれか !analyze me!!そんなやけっぱちな気分の私ですが、来週 7 月 27 日から亜米利加行ってきます。一応、出張です。仕事を超特急で色々してるところに早起きはつらいです、眠いです。でもがんばります。

さて、わたしが屍のようになっている間にも着々と Windows 7 の開発は進んでいたんですね…。米国時間 7 月 22 日、Windows 7 及び Windows Server 2008 R2 の製品開発完了(RTM)が発表となったようです。RTM されたということは、いよいよ生産工程に入るということですね。日本語版については英語版リリース後、順次リリースする予定になります。時期については近いうち、公表されるようです。

Microsoft最新情報
●マイクロソフト、Windows(R)7 ならびにWindows Server(R) 2008 R2のRTM(開発完了)を発表
~ 新製品の世界各国同時リリースに向けパートナー各社が最終準備へ ~
http://www.microsoft.com/japan/presspass/detail.aspx?newsid=3736
"マイクロソフト コーポレーション(Microsoft Corporation、本社:米国ワシントン州レドモンド)は、米国時間7月22日(水)、同社のデスクトップならびにサーバー用オペレーティング システムの旗艦製品の次期バージョンである、Windows(R) 7 ならびにWindows Server(R) 2008 R2の開発工程が完了し、生産部門向けにリリース(RTM: Release To Manufacturing)されたことを発表しました。この開発フェーズの完了に伴い、今後同社は、Windows 7 ならびにWindows Server 2008 R2の世界各国同時期リリース(Worldwide General Availability)に向けた準備を整えるよう、パートナー各社に対して要請する方針です。Windows 7 の一般向け発売日は10月に予定されています。従来どおり、現在Windowsのボリュームライセンスを契約されているお客様、MSDNの登録メンバー、ならびにTechNetの登録メンバーに対しては、数週間後にWindows 7 およびWindows Server 2008 R2の初のユーザーとしての利用権が提供されます。"

ちなみに社内のまわりでは、ぴろとくんは RTM 版をメインマシンにして元気に調査していますが、とくに困ることもなく、快適に仕事を進めてるようです。ぬう、速そう…。
そしてお父さんはネットブックを買って中に Windows 7 Beta をいれてましたが、最近 RTM 版にして快適だーと言ってます。多分あの様子では本当に快適そうです。
妬ましいので、私も近いうちに時間を作って入れてやろうと思っています。出張から帰ってきたらやりますよ!

しかし、よーくみたら、このブログ、7 月は文字化けの件を書いただけで、本業は全然書いてませんね。文字化けの件、かならず書きますので、お待ちください。先に AD のほうで書く予定です。(順番が違くってすみません)

それでは、また。

~ ういこう@なんでマスターレアばっかりダブるんだろう ~

補足 : Windows 7 および Windows Server 2008 R2 RTM についての詳細はこちらをご覧ください。
Is Your Application Ready for Windows 7 RTM?
http://windowsteamblog.com/blogs/developers/archive/2009/07/23/is-your-application-ready-for-windows-7-rtm.aspx

[info] サポート窓口休業のお知らせ (7/8 終日、/13 午後)
いつもお世話になっております。ILM / ADSI サポートチームです。
今日はサポート窓口休業のお知らせです。

誠に 8 日水曜日終日および 13 日午後は弊社社内行事日のため休業とさせていただきます。
サポート受付専用電話窓口は、緊急案件 (Severity A) およびメールでの受付業務は通常通り行わせていただき、サポート エンジニアからは翌営業日以降にご連絡申し上げます。
お急ぎのところ大変申し訳ございませんが、翌日よりより一層の対応に励んで参りますので、何卒ご理解ご了承のほどどうぞよろしくお願いいたします。

その他、弊社窓口の休業予定につきましては下記をご参照ください。

 電話サポート窓口休業予定のお知らせ
 http://support.microsoft.com/gp/Holiday

 弊社社内行事に伴う窓口の一部休業について
 http://www.microsoft.com/japan/customer/default.aspx

~ ILM / ADSI / WMI / PCNS サポートチーム ~

More Posts Next page »
Page view tracker