December, 2008 - フィールドSEあがりの安納です - Site Home - TechNet Blogs

フィールドSEあがりの安納です

Microsoft Evangelist -- Junichi Anno

December, 2008

  • 【Management】Windows Server 2008 DFS(分散ファイルシステム)でのアクセスベースの列挙 その1

    アクセスベースの列挙(Access-Based Enumeration)」という機能はご存知でしょうか?初めての方もいらっしゃるかもしれないので、例を挙げて説明します。

    詳しく知りたい方は、TechNet内のこちら をご覧ください。

    以下のようなフォルダ構成があったとします。Home は共有フォルダです。

    図1

    User01 が Z: ドライブに \\FileServer01\Home を接続した場合、Z:ドライブをエクスプローラーで開くと、おそらく、User02 や User03 など他のユーザーのフォルダも見えてしまいます。見えてしまっても、NTFSアクセス権さえ適切に設定しておけば、実際にアクセスしようとすれば「アクセス拒否」が発生します。よって、ひとまず心配は無いのですが、フォルダが見えてしまうということ自体、気持ち悪いかもしれません���

    Homeディレクトリの場合、その配下に1000人や5000人分のホームディレクトリが存在する可能性もあり、その中から自分のフォルダを探すのもかなり面倒です。一覧が表示されるまでに相当に時間がかかるかもしれません。

    そんなときに「アクセスベースの列挙」という機能を使用すると、アクセス権の無いフォルダは、はなから非表示にすることができるため、利用者を混乱させずにすみます。

    Windows Server 2008 でアクセスベースの列挙を設定するには、「共有と記憶域の管理」スナップインを使用します。サーバーマネージャからも「共有の記憶域の管理」にアクセスできます。

    image

    「共有と記憶域の管理」を開いたら、共有ファオルダの一覧から「アクセスベースの列挙」を有効にする共有フォルダを選択し、コンテキストメニューから[プロパティ]を開きます。

    以下をご覧ください。既定では「無効」に設定されています。

    image

    そこで、[詳細設定] をクリックして、以下のように「アクセスベースの列挙を有効にする」をチェックします。

    image

    これで、この共有フォルダの配下ではアクセスベースの列挙機能が有効になりました。

    今後、アクセス権のないフォルダは一切表示されなくなります。

    さて、同じようなことがDFSでもできるかどうか?

    できます。

    が、ここで紹介した方法では残念ながら実現できません。

    長くなったので、これについては次回の投稿で。

    ちなみに、Windows Server 2003 (SP1以降)での実装方法が、以下に書かれています。

    DFS 環境で Windows Server 2003 アクセス ベースの列挙を実装する方法
    http://support.microsoft.com/kb/907458/ja

  • 【IDM】MSMQ を使って確実なユーザー登録を行う その4 ~ メッセージの送信

    MSMQを使用してユーザー登録を工夫しようシリーズの第4回目です。

    前回の登録から..なんと半年...Tech・Ed 2008 では「続き待ってます」と言われておりました...すみませんです。他にも書きかけの記事があったりもして...えーと、えーと、干支が変わる前になんとかしたいかなぁと思う今日この頃です(あ、なんか今日 冴えてるかも!)。

    前回までの記事は以下の通りです。

    今回は、VBScript(PowerShellじゃないところがニクいじゃぁありませんか)を使用してMSMQでメッセージを送信してみます。

    ■メッセージを送信してジョブを作成する

    第3回の後半で使用したスクリプトを見てみましょう。拡張子はvbsです。

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    Const MQ_RECEIVE_ACCESS  = 1 
    Const MQ_SEND_ACCESS     = 2 
    Const MQ_PEEK_ACCESS     = 32 
    Const MQ_ADMIN_ACCESS    = 128
    Const MQ_DENY_NONE           = 0 
    Const MQ_DENY_RECEIVE_SHARE  = 1

    set objQueueInfo = CreateObject("MSMQ.MSMQQueueInfo")
    set objMsgQueue = CreateObject("MSMQ.MSMQQueue")
    set objMessage = CreateObject("MSMQ.MSMQMessage")

    objQueueInfo.PathName = "junichia03\private$\Input"

    'objQueueInfo.Formatname = "DIRECT=OS:junichia03\private$\Input"
    'objQueueInfo.Formatname = "DIRECT=HTTP://junichia03/msmq/private$\Input"

    set objDist = objQueueInfo.Open(MQ_SEND_ACCESS ,MQ_DENY_NONE)

    objMessage.Label = "msg" & date & time
    objMessage.Body = "メッセージボディ"
    objMessage.Delivery = 1
    objMessage.Send(objDist)

    objDist.Close

    上のスクリプトで重要なのは、2点です。

    1点目は、12行目および14/15行目で指定している、キューのパスです。MSMQQueueInfo オブジェクトをいずれかのキューと対応付けるため、PathNameプロパティまたは FormatNamtプロパティを使用してキューのパスを設定しなければなりません。ここで設定したキューは、17行目のOpenメソッドによって初期化され、22行目のSendメソッドでメッセージ送信の宛先として使用されます。

    12行目と14/15行目の違いは、パスの設定に PathName を使用しているか、FormatName を使用しているかです。このスクリプトでは、14/15行目がコメントアウトされているので、12行目が使われます。

    ローカルコンピューターのプライベートキューをスクリプトから操作する場合には PathNameでもよいのですが、リモートコンピュータのプライベートキューを操作する場合には FormatName を使用します。

    まずは PathName から見てみましょう。

    PathNameに必要な情報は、「コンピュータ名(NetBios名またはDNS名)」と「キューの名前」です。例えば、Compuer01 に Input という名前のプライベートキューを作成した場合には以下のような指定になります。

    • Computer01\private$\input
    • .\private$\input

    private$ は、プライベートキューであることを現しています。MSMQのインストール時に「ディレクトリサービス統合」も同時に組み込んでおり、キューを ActiveDirectory に公開している場合には「パブリックキュー」を作成することが可能です。パブリックキューの場合には、Private$は必要ありません。

    また、どうせローカルコンピュータなので、指定を省略して「.\」とすることも可能です。このほうがいろいろなサーバーで使用する場合には汎用的ではあります。

    プライベートキューとパブリックキューの違いについて、詳しくはこちらをご覧ください。

    さて、次に FormatName です。

    リモートコンピュータからプライベートキューにメッセージを発信する場合には、FormatName を使用しなければなりません。おそらく、より汎用的なアプリケーションにするために FormatName を使用することが多くなると思います。MSMQを使用するアプリケーションの場合、メッセージを発信するのはリモートコンピュータとなることが多いでしょうから、FormatName を使うものと覚えてしまってもよいかもしれません。

    また FormatNameプロパティを使用すると Direct Format Name という記述形式が使えます。この形式はプライベートキューとパブリックキューのいずれにも使用可能ですが、面白いのはパブリックキューにアクセスする場合に、一旦ディクレクトリサービスから情報を収集することなく「直接」キューと通信が行える形式であるということです。

    例えば、インターネット上のコンピュータからキューに対してメッセージを送信することを考えてみると、Active Directory をインターネット上のコンピュータに公開するというのは、ひとまず現実的ではありません。

    ただ、ディレクトリサービスにアクセスしないということは、逆にいえば、メッセージをルーティングしたり、メッセージ送信時に認証したり暗号化する際には使用できないということでもありますので注意してください。

    FormatName を使用したパスの指定例は以下の通りです。

    • DIRECT=IPX:00000012:00a0234f7500\private$\Input
    • DIRECT=TCP:192.168.1.1\private$\Input
    • DIRECT=OS:Computer01\private$\Input
    • DIRECT=HTTP://Computer01.microsoft.com/msmq/private$\input
    • DIRECT=HTTPS://Computer01.microsoft.com/msmq/private$\input

    Direct Format Name を使用すると、プライベートキュー、パブリックキューを問わず、 HTTP やHTTPSを使用してメッセージを送信できるところが便利です。HTTP/HTTPS を使用すると、ファイアウォールの設定でMSMQサービスへの通信が止められていてもメッセージが受け取れるところもよいですね。

    ただ、HTTP/HTTPSはメッセージのSendでのみ使用可能であり、PeekやReceive時には使用できないことに注意してください。

    参考までに、MSMQで使用されるポート番号についてはこちらをご覧ください。

    2点目は17行目です。ここでは、Open メソッドを使用してキューをオープンしていますが、この時にキューのアクセスモードと共有モードを指定します。

    Open(アクセスモード, シェアモード)

    指定できる値は以下の通りで、これらを用途に応じて組み合わせます。

    アクセスモード

    • 1(MQ_RECEIVE_ACCESS):キューからメッセージを読み取った後で削除する
    • 2(MQ_SEND_ACCESS):キューにメッセージを送信する
    • 32(MQ_PEEK_ACCESS):メッセージを参照する(削除しない)
    • 128(MQ_ADMIN_ACCESS):ローカルのキューに対して指定できるモードで、outgoingキュー(メッセージが送信先に出される前に一時的に格納されるローカルのキュー)にスタックされたメッセージを参照したり削除する際に使用する。MQ_PEEK_ACCESS および MQ_RECEIVE_ACCESS ともに指定する。

    共有モード

    • 0(MQ_DENY_NONE):すべてのユーザーがキューにアクセス可能
    • 1(MQ_DENY_RECEIVE_SHARE):MQ_RECEIVE_ACCESSで指定可能なオプションで、既にキューがオープンされている場合には他のプロセスからのアクセスを拒否する

    このスクリプト例では、メッセージを送信するためにキューをオープンするので、MQ_SEND_ACCESSとMQ_DENY_NONEを指定しています。

    19行目~22行目では実際にメッセージを送信していますが、例えばこの部分を以下のように修正すれば、CSVファイルから読み込んだレコードを 1行=1メッセージ としてキューに登録することができます。

    Const MQ_RECEIVE_ACCESS  = 1 
    Const MQ_SEND_ACCESS     = 2 
    Const MQ_PEEK_ACCESS     = 32 
    Const MQ_ADMIN_ACCESS    = 128
    Const MQ_DENY_NONE           = 0 
    Const MQ_DENY_RECEIVE_SHARE  = 1 

    set objQueueInfo = CreateObject("MSMQ.MSMQQueueInfo")
    set objMsgQueue = CreateObject("MSMQ.MSMQQueue")
    set objMessage = CreateObject("MSMQ.MSMQMessage")

    objQueueInfo.Formatname = "DIRECT=HTTP://junichia03/msmq/private$\Input"

    set objDist = objQueueInfo.Open(MQ_SEND_ACCESS ,MQ_DENY_NONE)

    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objInputFile = objFSO.OpenTextfile("userlist.csv", 1, false)

    Do Until objInputFile.AtEndOfStream

        Rec = objInputFile.ReadLine
        Wscript.Echo Rec
        strUserName = Split(Rec, ",")(0)
        objMessage.Label = "USERADD " & _
                   strUserName & " " & _
                   date & " " & _
                   time
        objMessage.Body = Rec
        objMessage.Delivery = 1
        objMessage.Send(objDist)

    Loop

    objInputFile.Close
    Set objFSO = Nothing

    objDist.Close

    上記スクリプトを拡張子 vbs で保存し、以下のようなCSVファイルを用意して useerlist.csv というファイル名で保存してください。

    testuser001,Password,\\servername\share\testuser001
    testuser002,Password,\\servername\share\testuser002
    testuser003,Password,\\servername\share\testuser003
    testuser004,Password,\\servername\share\testuser004
    testuser005,Password,\\servername\share\testuser005
    testuser006,Password,\\servername\share\testuser006
    testuser007,Password,\\servername\share\testuser007
    testuser008,Password,\\servername\share\testuser008
    testuser009,Password,\\servername\share\testuser009
    testuser010,Password,\\servername\share\testuser010

    コマンドプトンプトでスクリプトを実行すると、CSVファイルから読み込まれたレコードが以下のようにキューに登録されます。

    csv2msmq

  • 【Management】Windows Server 2008 DFS(分散ファイルシステム)でのアクセスベースの列挙 その2

    前回の続きです。前回はこちら。

    【Management】Windows Server 2008 DFS(分散ファイルシステム)でのアクセスベースの列挙 その1

    「アクセスベースの列挙」により共有フォルダ配下の不必要なフォルダを見せないようにすることができます。

    同じようなことはDFS(分散ファイルシステム)でも可能ですが、方法が異なります。

    例えば、以下のようなDFS名前空間が定義されているとします。

    図2

    図の右側(\\FileSV1)が物理的な共有フォルダの構造です。それぞれのフォルダにはNTFSのアクセス権が設定されており、社員のアクセスが正しく制御されているとします。「一般社員用」フォルダ、「幹部社員用」フォルダともに「アクセスベースの列挙」が設定されていれば、その配下にあるアクセス権の無いフォルダは一覧にも表示されません。

    DFS名前空間にマッピングしたのが、図の左側です。

    一般社員が DFS名前空間  \\Contoso.jp\営業部 にアクセスしたとします。

    デフォルトの状態では、フォルダ一覧には「一般社員用」「幹部社員用」共に表示されますが、NTFSのアクセス権により幹部社員用フォルダにアクセスしようとすれば「アクセスが拒否されました」というエラーが発生します。

    では、DFS名前空間にもアクセスベースの列挙を適用し、「幹部社員用」フォルダが表示されないようにするにはどうしたらよいかといえば、dfsutil.exe コマンドを使用します。

    dfsutil.exe property ABDE enable \\contoso.jp\営業部

    ABDE は、Access Based Directory Enumlation の略であり、Enabled によって DFS名前空間ルート「\\contoso.jp\営業部」のアクセスベースの列挙機能を有効にしています。ちなみに、ABDE Enabled は、DFS名前空間ルートのみに設定できます。

    これに加え、さらに以下のコマンドで DFS名前空間内のアクセス権を設定する必要があります。

    dfsutil.exe property acl deny \\contoso.jp\営業部\幹部社員用 "contoso\一般社員グループ":F

    このコマンドでは、DFS名前空間「営業部」内の「幹部社員用」というエントリに対して、「contosoドメインの一般社員グループに所属するメンバー」からの一切のアクセス権(F)を拒否(Deny)しました。

    これにより、一般社員が \\contoso.jp\営業部 に接続しても、「幹部社員用」フォルダは一覧に表示されなくなります。

    幹部社員がアクセスした場合はどうかといえば、両方のフォルダが参照できます。「幹部社員用」フォルダ配下については、従来通り、NTFSのACLに定義されているアクセス権に沿ってアクセスベースの列挙が適用されます。つまり、dfsutil を使用しなくても、課長には「部長フォルダ」は表示されませんし、部長には「統括部長フォルダ」は表示されません。

  • 【IDM】MSMQ を使って確実なユーザー登録を行う その9 ~ スクリプトをルールに登録する

    今年の営業日も残り少なくなってきました。私がいるオフィスも、心なしか人が少ないような...いや確実に少ない。みなさん、年末年始は休めそうですか?私は...うーん...びみょーです。

    #これまでの投稿一覧は、この投稿の最下段に掲載してあります。

    ということで、今回は、その7 で完成させたスクリプトをルールに登録しましょう。

    MSMQのインストールと環境設定がまだという方は、その2その3 をご覧ください。

    以下のような構成になっていればOKです。[Inputキュー] と [Errorキュー] が作成してあり、トリガーは [Inputキュー] のみに関連付けられています。

    msmq_settings13

    msmq_settings14

    msmq_settings15 

    スクリプトをルールに登録するには、規則のプロパティから [規則の操作] タブを開きます。今回は、事前に rule1 という規則が作成してありますので、こいつのプロパティを開きます。

    [規則の操作] タブの中にある [スタンドアロンの実行可能ファイル(EXE)を起動する] をチェックし、実行可能ファイルのパスとして、VBSファイルのホストプログラムである CScript.exe をフルパスで指定します。

    C:\Windows\System32\cscript.exe

    msmq_settings11

    次に、[パラメータ] ボタンをクリックし、起動パラメータを指定します。

    既に何らかのパラメータが指定されている場合には、すべて削除してしまってください。今回は使いません。ここでは、CScript.exe のパラメータとして、作成したVBSファイルを指定します。

    このとき、パラメータの種類として、「文字列リテラル」を選択し、VBSファイルのフルパスを「リテラル値」に記載します。今回は、作成したスクリプトをReceiveInputQueue.vbs という名前で保存してあります。

    以下の図を参考にしてください。

    msmq_settings12

    これで、ルールの設定は完了です。

    以降、新しいメッセージがInputキューに入ってくるたびに、ここで指定したルールが起動されます。

    そして、ADへのユーザー登録に問題が発生すれば、メッセージは Errorキュー に移動されます。

    次回は、Errorキュー に移動されたメッセージを定期的に Inputキューに戻す処理について考察してみます。

    ---

    これまでの投稿は以下の通りです。

  • 【ライトニングトーク ネタ】パフォーマンスを見る

    #表示がおかしかったので修正しました。失礼しました。 

    12月2日に福岡で開催されたTFセミナーでは、お申し込みされた方が少なく、PASSJの河端さんだけでした。そこで、わたくし安納と、Developper Evangelist の大野もLTに参戦いたしました。

    私はと言えば、5分におさまりきらず、最後は無理やりまとめてしまいました。が、実はちょっとだけやり残してしまいました。そこで、この場をお借りして、LTトークを行います。5分で読んでください。

    <LT開始>

    スライド1

    みなさんこんにちは、マイクロソフトの安納です。今回は、「パフォーマンスを見る」方法についてご紹介します。

    スライド2

    みなさんは、普段、どのような方法でパフォーマンスを見ているでしょう?

    スライド3

    もっとも手軽なツールが、タスクマネージャーですね。CPUとメモリの状態を手っ取り早く把握するにはこれで十分です。

    スライド4

    次に挙げられるのがリソースモニターです。これはWindows Vistaから実装された機能で、CPUやメモリだけでなく、ディスクやネットワークのパフォーマンスを見るのにも活用できます。タスクマネージャーと違い、グラフを見ながら個々のプロセスを確認することができるところがすぐれています。リソースモニターはパフォーマンスモニタの一部として実装されており、コマンドプロンプトから起動する際には perfmon /res と入力します。

    スライド5

    さて、次は、すこしなじみのない方法かもしれません。

    WMICコマンドです。WMIはご存じでしょうか?Windows Management Instrumentationの略で、Windows Management サービス という名称で実装されています。VBScript や PowerShell をはじめとして、さまざまなプログラム言語からWMIをコールすることで、OSの状態やハードウェアの情報、レジストリ、ユーザーアカウント、などなどなど、とにかく多くの情報を収集することができるだけでなく、情報の設定も可能です。

    WMIを使用してパフォーマンス情報を取得することもできます。スライドに示したのは、システムのプロセス情報を取得した例です。「NODE」は参照したいコンピュータ名、「PROCESS」はプロセスに関する情報を取得することを示しています。PROCESS の部分を他のエイリアスに変更することで、その他の情報を取得することができます。どのようなエイリアスが用意されているかは WMIC /? でヘルプを参照してみてください。「List Brief」は表示形式を指定しており、「概要の表示」を意味しています。

    スライドにはWMICコマンドの実行結果例を示しています。タスクマネージャと同様の情報が出力されていることがお分かりいただけるでしょう。

    スライド6

    パフォーマンスを参照する場合、全ページのように1回限りの情報ではあまり意味がありません。繰り返し表示して、カウンターの推移を見たいと思うのが人情ってものです。

    WMICには、さまざまなスイッチが用意されており、繰り返し表示するには「/Every」を使用します。

    また特定の情報に絞って取得したい場合には、「get WorkingSetSize」のように取得したい属性名を指定したり、Where句によって特定のプロセスを指定することができます。

    ここに示したコマンド例を実際に実行すると、次のようになります。

    image

    この例では、1秒ごとに、Explorer.exe の使用メモリ、CPUの使用時間を取得しています。画面に表示するだけでなく、c:\tmp\perf.txtにも保存されています。

    スライド7

    WMICの面白ところは、パフォーマンスカウンタのクラスを直接指定することで、パフォーマンスモニタと同じレベルの細かな情報を取得することができるところです。

    今回は詳しくお話する時間がありませんので、「WMI Win32 Classes」で検索してみてください。MSDNライブラリ内の情報がヒットします。

    スライド8

      さて、1つ大御所が抜けていますね。そうです、パフォーマンスモニターです。パフォーマンスといえばパフォーマンスモニター。これを知らずしてパフォーマンスを語ることはできません。

    なので詳しい使い方等の説明は省きますが、Windows VistaやWindows Server 2008によってカウンタの数も増え、より使い勝手が良くなりました。特定のカウンタのグラフを太字にして目立たせるなんてこともできます。

    スライド9

    もう無いだろう...と思ってますか?いえいえ、もう1つご紹介したい機能があります。それは、Internet Explorer に System Monitor Control を読み込んで使用する方法です。

    ここに示すようなHTMLを記述するだけで、Internet Explorerからパフォーマンス情報を参照することができるのです。

    ie

    実際にIEで表示したのがこの画面です。

    どうでしょう?パフォーマンスモニターと全く同じ画面ですよね。これはどういうことか?つまり、パフォーマンスモニタ自身が System Monitor Control でできているということなのですね。

    え?「さっきのHTMLをメモしたいから見せてくれ」って?
    安心してください。

    (本番では ここで4分50秒)

    スライド10

    手で書く必要は無いのです。パフォーマンスモニターのグラフ画面を右クリックして「設定を保存」を選択していただければ、現時点のカウンタの情報を含めHTMLに保存することができるのです。

    この方法を使用すれば、例えばお客様に「これと、これと、これと、あれと、これ のカウンタを見てください」などと面倒なお願いをすることなく、メールでHTMLファイルを送ってダブルクリックしてもらえば済むんです。

    非常に便利な機能ですので是非とも使ってみてください。

    ということでございまして、ちょうど5分です。

    ご清聴ありがとうございました。

  • 【IDM】MSMQ を使って確実なユーザー登録を行う その8 ~ MSMQトリガーのクセを理解する

    さてもう一息ですね。第8回です。

    #これまでの投稿一覧はこの投稿の最下段に書いておきます。

    前回作成したスクリプトをキューのルールとして登録する前に、MSMQ運用に必要な知識について書いておきます。知識というよりも、クセですね。

    具体的には、何らかの原因によってスタックしてしまったメッセージを処理する方法です。これを知らないと、MSMQトリガーの運用は、結構困ります。

    -----

    MSMQトリガーに何らかの問題が発生したためルールが実行されなかったとします。

    この場合、メッセージはスクリプトによって処理されず、いつまでも以下のような状態でキューに残ってしまう可能性があります。

    例えば、スクリプトに不備があり、メッセージの送信が正常に行われなかった、などといったことが考えられます。

    msmq_custom01

    赤でくくった部分に注目してください。testuser001 ~ testuser020 までのユーザーが Inputキューに登録されていることがわかります。

    この状態で、MSMQが正常に戻った、もしくはスクリプトの不備修正が完了したとします。つまり、トリガーが正常に動作する状態になったと仮定します。

    ここに新たなメッセージが5件(testuser021 - 025)入ってきました。さて、どうなるでしょう???

    Receive の処理を理解していればわかりますよね。以下のように、古いものから処理され、後から入ってきたキューは後回しにされます。

    msmq_custom02

    このことから、「新しいメッセージが入ってこない限りトリガーが起動しない」ということが容易に想像できます。

    #古いメッセージから処理するかどうかは、環境設定およびスクリプトの作り方次第です。
    #今回はReceiveを使用したので古いものから順番に処理されています。

    これでは困るのでなんとかしたい。そんなときは、サービス一覧にある Message Queue Triggers サービスを再起動すれば、最も古いメッセージから順番にルールが実行されます。

    ここで覚えておいていただきたいのは、Message Queue Triggers サービスは Message Queue サービスとは分離されているので、停止してもメッセージが一時的に受け取れなくなるといった弊害は発生しません。

    これを知っていると、例えば、「実際の登録は明日の午前0時に開始したい」なんてことが実現できます。つまり、事前に Message Queue Triggers サービス停止した状態でメッセージを登録しておき、午前0時に起動してあげればよいわけです。

    もう一つ、スタックしたメッセージを処理する方法として、スクリプトを手動で実行するという手も考えられます。

    まとめると、以下の通りです。

    スタックしたメッセージを処理するには、

    • 新しいメッセージを登録してトリガーを起動する
    • Message Queue Triggers サービスを再起動する
    • メッセージを処理するスクリプトを手動で実行する

    のいずれかを実行する必要があります。

    是非とも覚えておいてください。

    ----

    これまでの投稿は以下の��りです。

  • 【IDM】MSMQ を使って確実なユーザー登録を行う その5 ~ メッセージの中身を読み取る

    いまさらですが、「忘れられた日本人」という本がおもしろくてたまりません。民俗学なんて高尚な話はひとまずおいといても、面白いです。そして思うことは、はたして自分が80歳になったとき、人に語って聞かせる話を持っているだろうか...Message Queue の話をする老人はやだなぁ。

    ということで、MSMQを使ってユーザー登録するシリーズです。

    前回までの投稿は以下の通りです。

    前回はCSVファイルから読み取ったレコードをメッセージとしてキューに登録する手順について書きました。

    今回は、キューに登録されたメッセージを読み取る方法と、メッセージを別のキューに移動する方法について解説いたします。

    ここで、全体の流れをおさらいしておきます。

    ① CSVファイル から MSMQの[Inputキュー]に登録

    ② トリガーが起動しルールが適用される
    └ キューからメッセージを読み取ってADにユーザー登録
    └┬ 成功したらメッセージは廃棄
    └ 失敗したらメッセージを [Errorキュー] に移動

    ③ [Errorキュー] に格納されているメッセージを定期的に[Inputキュー]に移動

    ① については前回解説しました。

    今回は、② について解説します。

    CSVファイルからInputキューにメッセージが登録されると、メッセージ1件の登録につき1回、トリガーが起動します。

    トリガーには「ルール」が関連付けられており、「ルール」には実行するスクリプトを関連付けておきます。

    模式的に書けばこんな感じです。

    [キュー]-[トリガー]-[ルール]
    └ 実行するスクリプト

    このあたりの解説は、以下に書かれていますので、もし忘れてしまった方はおさらいしてくださいませ。

    【IDM】MSMQ を使って確実なユーザー登録を行う その3 ~ MSMQ の環境設定

    今回作成するスクリプトは、ルールに関連づけられるスクリプトですが、ひとまず一般的なスクリプトを作りましょう。ルール用の微調整はあとから行うことにします。

    ■キューからメッセージを読み取る

    キューからメッセージを読み取るには、Peek もしくは Receive を使用します。ただし、Peek の場合には読んだ後のメッセージはそのままですが、Receiveではキューからメッセージが取り出されるため、結果としてキューから削除されます。

    さて、今回はどちらがよいでしょう。

    もちろん、Receive がよいのです。

    成功しても失敗しても、メッセージは Inputキューから一旦削除しなければなりませんから、最初から Receive で受け取った方が効率的です。

    なお、Receive の方法は1通りではなく、いくつか用意されています。関連するメソッドを以下に羅列します。それぞれが何をするかは見ての通りですね(といって面倒な解説を避けるのがライターの常套手段だったりもします....笑)。

    今回使用するのは Receive メソッドです。これは、常に最も古いメッセージを受信します。もちろん、受信したあとはメッセージは削除されますから、次に Receive するときには2番目に古いメッセージを受信することになります。

    以下は、InputキューからReceiveでメッセージを受け取るスクリプトです。

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30

    Const MQ_RECEIVE_ACCESS  = 1 
    Const MQ_SEND_ACCESS     = 2 
    Const MQ_PEEK_ACCESS     = 32 
    Const MQ_ADMIN_ACCESS    = 128
    Const MQ_DENY_NONE           = 0 
    Const MQ_DENY_RECEIVE_SHARE  = 1 

    set objQueueInfo_Input = CreateObject("MSMQ.MSMQQueueInfo")
    set objMsgQueue_Src = CreateObject("MSMQ.MSMQQueue")
    set objMessage = CreateObject("MSMQ.MSMQMessage")
    set objManagement = CreateObject("MSMQ.MSMQManagement")

    objManagement.Init "Junichia03",,"DIRECT=OS:junichia03\private$\Input"
    objQueueInfo_Input.Formatname = "DIRECT=OS:junichia03\private$\Input"
    Set objMsgQueue_Src  = objQueueInfo_Input.Open(MQ_Receive_ACCESS ,MQ_DENY_NONE)

    If objManagement.MessageCount > 0 then 
        wscript.echo objManagement.MessageCount & " 件のメッセージがあります" 
        Set objMessage = objMsgQueue_Src.Receive() 
        arrBody = Split(objMessage.Body,",")
        strUserName = arrBody(0)
        strPassword = arrBody(1)
        strHomeDir  = arrBody(2) 

        Wscript.Echo "ユーザー名:" & strUserName
        Wscript.Echo "パスワード:" & strPassword
        Wscript.Echo "ホームパス:" & strHomeDir
    Else 
        Wscript.echo "メッセージがありません"
    End If

    簡単に解説します。

    11行目 MSMQ.MSMQManagement は、キューのステータスを参照するためのオブジェクトです。このスクリプトでは、キューに格納されているメッセージの数を参照するために使用しています。ここで作成したインスタンスを使用して、13行目では参照したいキューを指定し、18行目でメッセージ数を取得しています。

    19行目 メッセージを受信しているのがこの行です。Receiveを使用しています。取得したメッセージはMSMQ.MSMQMessage 形式になります。
    20行目ではメッセージのBODYプロパティを使用してメッセージの内容を取り出し、Splitで分割しています。

    このスクリプトを実行した結果例が以下になります。

    Receive

    最初に前回使用したスクリプトを使用してCSVからキューにメッセージを登録しています。

    次に、上のスクリプトを ReceiveInputQueue.vbs という名前で保存して実行しています。1回実行すると、キューの中の一番古いメッセージが取り出され、キューから削除されます。

    プロンプト上に残りメッセージ数を表示しているので注意してみてください。

    2回目の実行では、残りメッセージが減っていることがわかります。

    長くなってしまったので、次の投稿でADへの登録を組み込みます。

  • 【IDM】MSMQ を使って確実なユーザー登録を行う その6 ~ ADにユーザーを登録する

    MSMQでユーザーを登録するシリーズです。もうすこしで完結します。

    前回はキューに蓄積されたメッセージを受信する方法について解説しました。

    今回は、受信した情報をActive Directoryに登録します。

    「ADに登録するスクリプトなんて、いまさら解説されても...」という方、いらっしゃいますよね。まぁ、そうおっしゃらずに、ちょっとご覧ください。

    まずは、スクリプトの全体像から。長くてすいません。

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92

    Err.Clear

    Const MQ_RECEIVE_ACCESS  = 1 
    Const MQ_SEND_ACCESS     = 2 
    Const MQ_PEEK_ACCESS     = 32 
    Const MQ_ADMIN_ACCESS    = 128
    Const MQ_DENY_NONE           = 0 
    Const MQ_DENY_RECEIVE_SHARE  = 1 

    Set objRootDSE      = GetObject("LDAP://RootDSE")
    strDomainPath       = objRootDSE.Get("DefaultNamingContext")
    strContainerADsPath = "LDAP://" & "CN=Users," & strDomainPath
    Set objContainer    = GetObject(strContainerADsPath)

    Set objConnection = CreateObject("ADODB.Connection")
    objConnection.Open "Provider=ADsDSOObject;"
    Set objCommand = CreateObject("ADODB.Command")
    objCommand.ActiveConnection = objConnection


    set objQueueInfo_Input = CreateObject("MSMQ.MSMQQueueInfo")
    set objMsgQueue_Src = CreateObject("MSMQ.MSMQQueue")
    set objMessage = CreateObject("MSMQ.MSMQMessage")

    set objManagement = CreateObject("MSMQ.MSMQManagement")

    objManagement.Init "Junichia03",,"DIRECT=OS:junichia03\private$\Input"

    objQueueInfo_Input.Formatname = "DIRECT=OS:junichia03\private$\Input"

    Set objMsgQueue_Src  = objQueueInfo_Input.Open(MQ_Receive_ACCESS ,MQ_DENY_NONE)

    If objManagement.MessageCount > 0 then 

        On Error Resume Next 

        wscript.echo objManagement.MessageCount & " 件のメッセージがあります" 

        Set objMessage = objMsgQueue_Src.Receive() 

        arrBody = Split(objMessage.Body,",")
        strUserName = Trim(arrBody(0))
        strPassword = Trim(arrBody(1))
        strHomeDir  = Trim(arrBody(2)) 

        Wscript.Echo "ユーザー名:" & strUserName
        Wscript.Echo "パスワード:" & strPassword
        Wscript.Echo "ホームパス:" & strHomeDir 

        objCommand.CommandText = _
            "<LDAP://" & strDomainPath & ">;" & _
            "(&(objectCategory=person)(objectClass=user)" & _
            "(sAMAccountName=" & strUserName & "));" & _
            "DistinguishedName, sAMAccountName;" & _
            "subtree"
        Set objRecordSet = objCommand.Execute 

        If NOT objRecordSet.EOF then
            Set objNewUser = GetObject("LDAP://" & objRecordSet.Fields("DistinguishedName"))
        Else
            Set objNewUser = objContainer.Create("user", "CN=" & strUserName)
            objNewUser.Put "sAMAccountName", strUserName
            objNewUser.SetInfo()
        End If
     

         Call ErrorHandle(1,err.Number, err.Description) 

        objNewUser.HomeDirectory = strHomeDir
        objNewUser.SetInfo() 

         Call ErrorHandle(2, err.Number, err.Description) 

        objNewUser.SetPassword(strPassword) 

         Call ErrorHandle(3, err.Number, err.Description)

    Else 

        Wscript.echo "メッセージがありません"

    End If

    Sub ErrorHandle(errPosition, errNumber, errDescription) 

        Select Case errNumber
            Case 0 

            Case Else
                Wscript.Echo errPosition & "," & errNumber & "," & errDescription
                Wscript.Quit(1)
        End Select

    End Sub

    ADSIを使用したユーザー登録スクリプトは巷にあふれているので、さほど苦労することは無いでしょう。

    ただ、エラーハンドリングまで考えていることは意外と少ないようです。

    今回の目的を思い出して下さい。登録に失敗した場合には Errorキューにメッセージを移動しなければなりません。つまり、エラーハンドリングをきちんとしないとならないのです。

    しかしながら、誠に残念ですが VBScript はエラー処理が苦手です。苦手などというレベルでは無いかもしれません。ほとんど出来ないと言っても過言ではないでしょう。使えるエラー処理といえば、On Error Resume Next と Err オブジェクトくらいです。

    だからといって、「PowerShell に移行します」なんて暴挙を許してよいのでしょうか?

    もちろん良いのです。が、あえて苦労してみるのも楽しいもんです。

    さて、今回のような「ユーザー登録に関する一連の処理」をスクリプト化する場合、考慮事項がたくさんあります。経験されている方は良くご存じでしょう。代表的な考慮事項を以下に示します。

    1. 既にユーザーがいる場合にはどうしたらよいか?(ID重複かどうかの判断)
    2. 属性の設定過程でエラーが発生した場合にはどうしたらよいか?(例えば値の形式不一致やパスワードポリシー不一致等)

    1.については、よーく考えておきましょう。まじですよ。本当に考えておかないとひどい目にあいます。というのも、ユーザーを新規に登録したいタイミングと、ユーザーの属性を上書きしたいタイミングってのは同じ場合が多いのです。

    人事異動の季節、「新規ユーザー一覧」と「既存ユーザー一覧」を分けて処理すれば確実ですが、実際のところ、そんなリストが人事部から出てくるかどうか。たいていは、同じリストに新旧ユーザーが混在してシステム部門に提示されるのではないでしょうか。下手すれば、ユーザーIDさえ人事部門から出てこない場合もあります(この場合にはシステム部門でIDを付加する作業が必要です)。

    となると、処理は一通りじゃ済まないことが容易に想像できます。

    既にユーザーが存在するかどうか調べ、存在しない場合に「新規に作成する」という処理を行わなければエラーになることは見えています。

    さらに、既に存在する場合、リストに書かれた属性で上書きしてしまっても良いかどうかを判断する必要もあります。もし��したらIDが重複してしまっているかもしれませんので、重複では無いことを保証する処理も必要になるかもしれません(フルネームや入社年度、社員番号等のチェックで回避する例も多いです)。

    さらに、さらに、既に存在する原因が「登録処理をやり直したから」なんて場合も考えられます。

    2.についてですが、入力となるCSVファイルの作成ミス等で間違えた値が入っている可能性があります。日付形式が全角で入力されていたり、数字にアルファベットが含まれていたり...。完全にミスを防ぐことはできませんから、登録時にはそれなりの対策が必要です。

    対策といっても「空白をトリミング」したり「全角を半角に変換」したりするのは、正直、スクリプトで対応すべきではないと考えています。やはり、入力データに正しい値を入れてもらうよう、ソース側を修正すべきです。

    じゃ、どんな対策を考えるのかというと、エラーが起きたときに、何をするかという点です。次に進むのか、そこで処理を止めるのか。

    これ、ルールをしっかり決めておかないと、かなーり、やっかいです。

    なんとなく処理が全部終わったからといって安心していたら、途中の「ホームディレクトリを設定している行」だけがエラーになっていた!なんてことはよくあります。

    入力データの問題で再度処理を流すにしても、エラーが発生したユーザーを抽出して...なんてことをやると、とてもじゃありませんが、二次的なミスを犯す可能性が高くなります。ましてや、別の新しいスクリプトを作って対応なんて言語道断...ってこともありませんが、極力避けたいですね。

    「1種類のスクリプトを何度流しても問題が無いような作り」であることが望ましいです。

    以上のような考慮事項をすべて洗い出すと、きりがありません。パッケージを適用する場合にはこんな心配は必要ないのですが、今回のようにスクリプトを自作する場合には、以下のようなルールにしておくとよいでしょう。

    • スクリプトは1種類しか使わない
    • クラス化などを考慮せず、常に上から下に処理が流れるように
    • 処理の流れを事前に決めておき、エラーが発生したらそこで処理終了
    • どこでエラーが発生したか、わかるようにログを残す

    とにかくシンプルにすることが重要です。

    ということで、スクリプトを見てみましょう。

    34行目。言わずと知れた、Resume Next です。エラーが起きてもマイペンライ!っていう意味です(あれ?違うか?)。もしエラーが発生した場合には、これを捕捉しなければなりません。そのためには、エラーが発生した瞬間に処理が止まってしまっては困ります。

    65,70,74行目。エラーが発生したら処理をそこで止めてしまうために、エラーを判断する部分をFunction(82ー92行目)として共通化しています。Function の中では、、エラー番号が0であれば処理を継続し、そうでなければ スクリプトを終わらせています。このスクリプトでは、「ユーザーオブジェクトの取得」「ホームディレクトリ属性の設定」「パスワードの設定」それぞれの処理の後でエラー番号を判定しています。

    88行目では、エラーの内容を Wscript.Echo でコンソール上に出力していますが、FileSystemObjectを使用してログファイルに吐き出すと後から確認できてよいでしょう。

    で、ほんとは...こういう外部関数で処理を抜けてしまうというのは美しくないのですがね...わかっちゃいるんですが、メインに処理をごちゃごちゃ書くと混乱するしメンテも大変だし、スクリプトなので大目に見てほしいなぁと...。

    49ー63行目。キューから読み取ったユーザーIDを使ってADを検索し、

    • ヒットすれば当該ユーザーを取得
    • ヒットしなければ新規にユーザー作成

    しています。

    このスクリプトでは、「ユーザーIDの重複」=「ユーザー属性の上書き」であるとしました。

     

    ということで、これでほぼスクリプトが完成しました。

    次回(たぶん最終回)は、「エラーが発生したらキューを移動する」処理を実装し、MSMQのルールにスクリプトを登録しましょう。

  • 【IDM】MSMQ を使って確実なユーザー登録を行う その7 ~ キューを移動する

    明日23日が休みだってことに、いま気付きました。

    MSMQでユーザー登録シリーズです。で、すいません。最終回じゃないです。

    今回はエラーとなったメッセージをErrorキューに移動します。

    これは非常に簡単です。

    単に、Send で Errorキューに送るだけです。InputにSendしたときとまったく同じですね。

    以下の赤く示した部分が、前回から追記したコードで、メッセージをSendしているのが94行目です。今回は、特に難しいところは無いはずです。

    アレンジするとすれば、キューの移動部分でしょうか。今回は、エラーが発生したメッセージを一律 再実行を想定して Errorキュー に移動していますが、エラーの種類によってキューを分けるのも良いかもしれません。

    たとえば、「登録に失敗したユーザーについては即効で対応する必要がある」ということで、登録失敗専用のキューを作成しておき、キューにメッセージが投稿されたらその都度メールを送信するなどといった処理が考えられます。

    ということで、ひとまず、AD登録用スクリプトについては、これで完成です。

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91 
    92
    93
    94
    95
    96
    97
    98
    99

    Err.Clear

    Const MQ_RECEIVE_ACCESS  = 1 
    Const MQ_SEND_ACCESS     = 2 
    Const MQ_PEEK_ACCESS     = 32 
    Const MQ_ADMIN_ACCESS    = 128
    Const MQ_DENY_NONE           = 0 
    Const MQ_DENY_RECEIVE_SHARE  = 1 

    Set objRootDSE      = GetObject("LDAP://RootDSE")
    strDomainPath       = objRootDSE.Get("DefaultNamingContext")
    strContainerADsPath = "LDAP://" & "CN=Users," & strDomainPath
    Set objContainer    = GetObject(strContainerADsPath)

    Set objConnection = CreateObject("ADODB.Connection")
    objConnection.Open "Provider=ADsDSOObject;"
    Set objCommand = CreateObject("ADODB.Command")
    objCommand.ActiveConnection = objConnection

    set objQueueInfo_Input = CreateObject("MSMQ.MSMQQueueInfo")
    set objQueueInfo_Error = CreateObject("MSMQ.MSMQQueueInfo")

    set objMsgQueue_Src = CreateObject("MSMQ.MSMQQueue")
    set objMsgQueue_Dst = CreateObject("MSMQ.MSMQQueue")

    set objMessage = CreateObject("MSMQ.MSMQMessage")

    set objManagement = CreateObject("MSMQ.MSMQManagement")

    objManagement.Init "Junichia03",,"DIRECT=OS:junichia03\private$\Input"

    objQueueInfo_Input.Formatname = "DIRECT=OS:junichia03\private$\Input"
    objQueueInfo_Error.Formatname = "DIRECT=OS:junichia03\private$\Error"

    Set objMsgQueue_Src  = objQueueInfo_Input.Open(MQ_Receive_ACCESS ,MQ_DENY_NONE)
    Set objMsgQueue_Dst  = objQueueInfo_Error.Open(MQ_SEND_ACCESS ,MQ_DENY_NONE)

    If objManagement.MessageCount > 0 then 

        On Error Resume Next 

        wscript.echo objManagement.MessageCount & " 件のメッセージがあります" 

        Set objMessage = objMsgQueue_Src.Receive() 

        arrBody = Split(objMessage.Body,",")
        strUserName = Trim(arrBody(0))
        strPassword = Trim(arrBody(1))
        strHomeDir  = Trim(arrBody(2)) 

        Wscript.Echo "ユーザー名:" & strUserName
        Wscript.Echo "パスワード:" & strPassword
        Wscript.Echo "ホームパス:" & strHomeDir 

        objCommand.CommandText = _
            "<LDAP://" & strDomainPath & ">;" & _
            "(&(objectCategory=person)(objectClass=user)" & _
            "(sAMAccountName=" & strUserName & "));" & _
            "DistinguishedName, sAMAccountName;" & _
            "subtree"
        Set objRecordSet = objCommand.Execute 

        If NOT objRecordSet.EOF then
            Set objNewUser = GetObject("LDAP://" & objRecordSet.Fields("DistinguishedName"))
        Else
            Set objNewUser = objContainer.Create("user", "CN=" & strUserName)
            objNewUser.Put "sAMAccountName", strUserName
            objNewUser.SetInfo()
        End If 

         Call ErrorHandle(1,err.Number, err.Description) 

        objNewUser.HomeDirectory = strHomeDir
        objNewUser.SetInfo() 

         Call ErrorHandle(2, err.Number, err.Description) 

        objNewUser.SetPassword(strPassword) 

         Call ErrorHandle(3, err.Number, err.Description)

    Else 

        Wscript.echo "メッセージがありません"

    End If

    Sub ErrorHandle(errPosition, errNumber, errDescription) 

        Select Case errNumber
            Case 0 

            Case Else
                objMessage.Send(objMsgQueue_Dst)
                Wscript.Echo errPosition & "," & errNumber & "," & errDescription
                Wscript.Quit(1)
        End Select

    End Sub

    さて、このスクリプトをキューのルールとして登録するのですが、その前にMSMQ トリガーの大切な性質(クセ)について解説しておかなければなりません。

    これについては次回に(ひきのばしているわけではないのです。すいません。)。

  • 【パネリスト決定】 - 1/17 失敗しない分散ID管理 パネルディスカッション

    多くの方々はクリスマス・イブの夜をさぞかしロマンチックに過ごすのでしょうね。いいですね。せいぜい明日遅刻しないでくださいね。

    さて、既にお知らせしたとおり、1月17日 に開催される Tech Fielders セミナー「失敗しない分散ID管理」では、業界のエキスパートをお呼びしてパネルディスカッションを行います。

    そのパネルディスカッションにご協力いただける各界のエキスパートが決定いたしましたので、自己紹介文と共にご紹介いたします。

    (順不同にて失礼いたします)

    エクスジェン・ネットワークス株式会社 川 淳一

    エクスジェン・ネットワークス は 2000年8月の創業以来、LDAPサーバをID情報のマスタDBとして利用するID統合管理ツール「LDAPManager」を製造、販売している、パッケジソフトメーカーです。「LDAPManager」は、お客様が本当に必要な機能に的を絞り、年一度のバージョンアップによる機能強化を重ねることで、『低価格で、無理がない、無駄がない』、ID統合管理ツールを目指しております。日本で唯一のID統合管理専業パッケジソフトメーカーの代表として当日はID統合管理システム構築のポイントについて、皆様と議論できることを楽しみにしています。

    日本アイ・ビー・エム株式会社 前島 鷹(たかまさ)

    Microsoft MVP for Data Center Management - System Center Configuration Manager
    日本アイ・ビー・エムにて、IAサーバーを中心としたインフラ環境の設計・構築に従事。近年は特に、Windowsサーバー/クライアント環境のシステム管理・監視、セキュリティ、サーバー仮想化などの分野を専門としている。

    サン・マイクロシステムズ株式会社 佐藤 理(きみまさ)

    サン・マイクロシステムズ株式会社 ソフトウェア・ビジネス統括本部で、アイデンティティ管理製品のプリセールス・エンジニアを担当。
    2001年にサンに入社。ISP をサポートするSEを経て、2002年よりプロフェッショナルサービスにてアイデンティティ管理製品の導入コンサルティング、設計、構築などを行なうコンサルタントとして活動。
    2006年より現職。コンサルタントとしての現場経験を生かして製品プロモーションから顧客への提案に至るまで幅広く活動中。
    私生活では二児の父として子育てに奮闘中。
    今回のセミナーへの参加では、休日を犠牲にしてセミナーに参加する熱意のある方との懇親会が今から楽しみ。

    株式会社野村総合研究所 達雄

    基盤ソリューション事業本部 基盤ソリューション事業一部 主任システムコンサルタント
    1998 年から 2008 年まで、サン・マイクロシステムズ (株) にてアイデンティティ管理分野のプリセールス・エンジニアおよびビジネス開発を歴任。2008 年、(株) 野村総合研究所に入社し、Uni-ID を中心とするアイデンティティ・ソリューションの企画を担当 (現職)。内部統制から OpenID まで、寄稿・講演多数。独立行政法人 情報処理推進機構 情報セキュリティ技術動向調査タスク・グループ委員 (アイデンティティ管理技術)。

    いやー、いまから楽しみで仕方ありません。まさに、お年玉企画といっても過言ではないでしょう。

    参加されるみなさんからもご質問を受けたいと思いますので、当日をお楽しみに!

    あ、そうそう。ライトニング・トークへのお申し込みもお待ちしております!

  • 【英語】日本語IEの「ネットワーク接続が存在しないときは、ダイヤルする」、英語版では?

    マイクロソフト ランゲージポータル ってご存知ですか?
    http://www.microsoft.com/language/ja/jp/search.mspx

    image

    このサイトでは、「各国のMS製品で使われている用語」と「英語版」との対応を検索することができます。

    たとえば、こんなシチュエーションがあったとしましょう。

    Internet Explorer のプロパティにある「ネットワーク接続が存在しないときは、ダイヤルする」という設定をグループポリシーで行ったにもかかわらず、どうもうまくいかない。

    何か情報が無いかなぁとおもってWEBで「ネットワーク接続が存在しないときは、ダイヤルする」を検索しても何もヒットしない。

    英語でもいいから、とにかく何か情報がほしい!

    だけど、英語の設定画面でどう記載されているのかわからない!!きゃーっ。

    そんなときは、ランゲージポータル を使いましょう。

    日本語で検索する場合には、必ず「訳語から検索」をチェックしてください。

    逆に、英語を日本語に直すときにはチェックははずします。

    チェックを入れて「ネットワーク接続が存在しないときは、ダイヤルする」を検索すると以下のような結果が得られます。

    image

    ということで、正解は「Dial whenever a network connection is not present」です。

    ちなみに、Windows Live の翻訳サイトを使用すると、以下のような結果となります。

    「To dial would not have network connectivity」

    もちろん、このような文章はIEでは使われていませんので、トラブルシューティングの際には役に立ちません。

    Windows Live の翻訳サイトに「マイクロソフト用語で翻訳する」みたいな機能があると面白いですし、検索時に「マイクロソフト用語で翻訳してから検索する」的な使い方ができるとうれしいですね。>偉い人

  • 【Management】より高度な PowerShell スクリプティング をバーチャルラボで習得

    バーチャルラボはご存知ですよね。

    マイクロソフトのサーバーに用意された仮想環境を使用して、実際に手元のコンピュータで動いているかのように製品を触ることができるサービスです。

    マイクロソフト TechNet バーチャルラボ

    英語版で恐縮なのですが、PowerShell 関連のラボが2件公開されているのでご紹介します。スクリプトの学習なので、あまり英語云々は気にならないです。

    • Advanced Windows PowerShell Scripting
    • Managing Windows Vista with Windows PowerShell

    ■Advanced Windows PowerShell Scripting

    その名の通り、PowerShellのより高度な機能(のきっかけとなる技術)を習得するためのラボで、以下のような演習からなっています。知っていればどうってこと無い内容かもしれませんが、そこにたどり着くまでにあちこちのサンプルを探しまくるよりは、このラボを90分体験して習得してしまったほうが効率的です。超お勧めです。

    image

    • Exercise 1 Creating Advanced Scripts with Windows PowerShell
      この演習では、PowerShellを使うに当たって必須の技術であるにもかかわらず、意外と「あれっ?」と思うような事項を学習します。
      ー 変数の使い方
      ースクリプトブロックの使い方
      ーFunctionの使い方
    • Exercise 2 Using Windows PowerShell with WMI
      タイトル通り、WMI(この演習ではネットワークカードへのアクセス方法)を使用して、より幅広い情報にアクセスする手法を学びます。1つの例でアクセスの方法さえ覚えてしまえば、あとはその応用でいくらでも幅を広げられます。そのキーとなるのが Win32_ で始まるクラス名であり、その一覧はここ(MSDN)に書かれています。
    • Exercise 3 Scripting with .NET Objects
      .NET Framework を直接呼び出す方法について学習します。この演習では、ダイアログボックスを作って表示しています。
    • Exercise 4 Converting VBScript to Windows PowerShell
      VBScript で動いているスクリプトは PowerShell への移行できるということを学びます。ここでは、プロセス一覧をファイルに保存するスクリプトを VBSとPS1で見比べることができます。特に「移行のコツ」について触れられてはおりませんが、同じ処理を実施するスクリプトを見比べることからコツがつかめるかな..と思っております。
    • Exercise 5 Using Windows PowerShell with Active Directory Domain Services
      Active Directoryを操作する方法について学習します。ここでは、以下の演習を行っています。
      ー ADに登録されているユーザー一覧をCSVファイルに保存する方法
      ー ユーザーのパスワードをリセットする方法
    • Exercise 6 Using Windows PowerShell to Manage Windows Server 2008 Server Core
      PowerShell を使用して、リモートから WinRM 2.0 を通した Server Core 管理の手法について学習します。

    ■Managing Windows Vista with Windows PowerShell

    Windows VistaのメンテナンスをPowerShellで行うための手法を学習するためのラボです。パイプの使い方や、出力結果のフィルタリングなど、PowerShell の特徴的な使い方についても学習することができるため、初心者にもお勧めです。

    • Exercise 1 Use Windows PowerShell for Windows Vista-Based Desktop Maintenance
      WMIを使用してVistaのデスクトップ管理を行う手法を学びます。同時に、スクリプト結果のフィルタリングの方法についても学習できます。
      ー デスクトップ、BIOS、CPUにアクセスして、コンピュータの構成一覧を出力する
      ー インストールされているソフトウェアと修正一覧を出力する
      ー MSI ファイルを使用してソフトウェアをインストールする
      ー 複数のコンピュータに繰り返し同様の処理(ソフトウェアのイントール)を行う
      ー schtasksコマンドを使用してタスクスケジューラを管理する
    • Exercise 2 Manage Windows Vista Event Logs, Devices, and Services
      ー イベントログの検索
      ー サービスの一覧や状態取得、サービス停止
      ー レジストリの参照、書き込み方法
      ー WMIを使用したプラグアンドプレイ デバイスの一覧取得
    • Exercise 3 Troubleshoot Windows Vista
      Vistaのトラブルシューティングに役立てるための各種情報収集の方法について学びます。
      ー プロセスの一覧取得
      ー プロセスの停止
      ー ディスクスペースの空き容量取得
      ー ネットワークアダプター情報の取得
      ー 現在のアドレス解放と、DHCPサーバーへのアドレスリース依頼

    もっと基本的なことから学びたいという方には、ご安心ください、日本語版が用意されています。

  • 【Management】PRO(ピー・アール・オー) ってご存知ですか?

    仮想マシンを操作するサンプルスクリプトが無いかなぁと思っていたところ、面白いサンプルがあったのでご紹介します。

    これは、SCVMM 2008 と OpsMgr 2007 の連携機能である PRO(Performance and Resource Optimization)によって生成されるスクリプトです。

    スクリプトはこちら

    スクリプトの中では、get-vmmserver や get-vmhost、Get-VMHostRating、Move-VM など、仮想マシンを管理するのに有用なコマンドレットが使われていますので、大いに参考になるかとおもいます。

    ときに、PROって...ご存じですか?直訳すれば「パフォーマンスとリソースの最適化」です。ちょっとだけ概要をご紹介しておきます。

    まずは前提知識として...
    もうおなじみだと思いますが、仮想マシンを集中管理するのが System Center Virtual Machine Manager 2008 ですね。そして、物理���仮想問わず、ネットワーク上のサーバーやクライアントの監視を行うのが System Center Operations Manager 2007 です。

    さて、あるホストに複数の仮想マシンが稼働している状態を考えてください。ホストの全体のCPU使用率が上昇し、この状態が続くと業務に影響が出てしまうかもしれないっ!

    そんなときに、あなたならどうしますか?

    1. 負荷が高いということは資源がよくつかわれているということなので逆に安心する
    2. せっかくの機会なのでベンチマークテストを行う
    3. Windows 神社で祈ってみる
    4. 止めても問題のない仮想マシンを停止する。様子を見て、また起動する。
    5. VMM2008を使用して仮想マシンを別のホストに移動する

    心情的には 2.だったりもしますが、そうも言ってられません。現実的には、4. か 5. ですよね。

    で、この作業を手で行ってもよいのですが、いつもあなたがその場にいるとは限りません。

    じゃ、どうするか?といえば、「自動化」しておけばよいわけです。

    幸いにも、SCVMMはPowerShellスクリプトから操作することができますし、OpsMgrはCPUの負荷状況を監視することができます。この2つが組み合わされば、なんか自動化できそうな気がしてきませんか?してきます。

    手作りで上記のような自動化の仕組みを作りこむことも可能ですが、VMM2008 + OpsMgr2007(SP1)を組み合わせると、標準機能でコレが実現できてしまいます。コレ=PRO ということです。

    PROを使用すると、OpsMgr側で検出したアラートを SCVMM が受け取り、その状況に適したスクリプトが生成され、実行されます。これによって、適切なホストに仮想マシンが移動されたり、仮想マシン自身のリソースの再設定が行われたりします。

    結果だけ聞くと至極単純な話なのですが、いざこれを手作りしようとすると結構面倒だったりもしますね。GUIだって作らなければならないし。

    実は、PROに関するお話を、12月11日 @IT仮想化ソリューションセミナーで行います。時間が50分ということで、スクリプトの詳細な解説まではとてもできませんので、そのあたりはBLOGで補足していきたいと思います。

  • 【週末TFセミナー】失敗しない分散 ID 管理 ~ ILM "2" のワークフローを使用したユーザー ID 管理の自動化

    来る1月17日(土曜日)、新宿のマイクロソフト本社セミナールームにて、「失敗しない分散 ID 管理 ~ ILM "2" のワークフローを使用したユーザー ID 管理の自動化」という週末セミナーを開催します。私、安納が講師となります。

    お申し込みは以下から
    http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032398306&Culture=ja-JP

    同時にライトニングトーク出場者も募集です
    http://www.microsoft.com/japan/powerpro/community/LT/default.mspx
    ※ID管理に特化したお話をしてくださる方、大募集!

    これは、11月17日に開催した 「ID管理の自動化 Update」を踏襲したもので、セミナーに寄せられたご質問やご意見を反映したものとなります。前回お時間が無くてお見せできなかったデモもご覧いただきます。

    そのため、お時間を少し長めにとらせていただき、かつ業界全体の取り組みを把握していただくためにパネルディスカッションも予定しています。もちろん、懇親会はいつも通り。

    セッション :10:30-15:15  (昼食休憩12:30-13:30)
    パネルディスカッション:15:30-16:30
    ライトニングトーク :16:40-17:40
    懇親会 :17:40-18:40

    パネルディスカッションの参加企業は現在調整中ですが、決定次第発表いたします。

    どうぞよろしくお願いいたします。

  • PRO で生成されるスクリプト(サンプル)

    $hostName = 'JUNICHIA03.example64.jp'; $serverName = 'SCVMM.example64.jp'; $ProtipId = '23B785AC-2C4C-4C8A-A7DB-2E54A5E9A475';
     $vmErrorCode = '1';

     function new-array { $args } 

     function FailGenericError { Set-PROTip -PROTipId $args[0] -LastError $args[1] -TipStatus Failed; } 

     function FailHostNotFound { $params = new-array '{2D6FA041-3A11-C4A4-0870-43D3DA2A350E}' $args[1];
     Set-PROTip -PROTipId $args[0] -LastErrorOpsMgrString $params -TipStatus Failed; } 

     function FailNoVMFound {
     switch($args[1]) { 
     1 { $params = new-array '{7909730C-BD3A-9639-75A4-C2CAB421E365}' $args[2]; } 
     2 { $params = new-array '{75DE3243-067A-7A38-369A-72E5516D3427}' $args[2]; } } 
     Set-PROTip -PROTipId $args[0] -LastErrorOpsMgrString $params -TipStatus Failed; }

     function FailNoVMToMigrate {
     $params = new-array '{2BFEAC02-0B20-13B6-868E-90DBD1BE9325}' $args[1];
     Set-PROTip -PROTipId $args[0] -LastErrorOpsMgrString $params -TipStatus Failed; } 

     function FailNoHostToMigrateTo {
     $params = new-array '{D33420DA-D858-F885-7C6E-B60F5EF4C990}' $args[1];
     Set-PROTip -PROTipId $args[0] -LastErrorOpsMgrString $params -TipStatus Failed; } 

     function FailInvalidErrorCode { $params = new-array '{CA516E68-8046-9013-25D6-15B8A512BD0C}';
     Set-PROTip -PROTipId $args[0] -LastErrorOpsMgrString $params -TipStatus Failed; } 

     function Main {
      $Error.Clear(); 
     $serverObj = get-vmmserver -computerName $serverName;
     if( $Error.Count -ne 0) { FailGenericError $ProtipId $Error[0]; return; } 

      Set-PROTip -PROTipId $ProtipId -TipStatus Running; 
     $hostobj = get-vmhost -computername $hostName -vmmserver $serverObj; 
     if( $hostobj -eq $null ) { FailHostNotFound $ProtipId $hostName; return; } 

     $allvms = $hostobj | Get-VM; 
     if(($hostobj.VMs -eq $null) -or ($hostobj.VMs.Count -eq 0)) { FailNoVMFound $ProtipId $vmErrorCode $hostName; return; } 

     $candidateVMs = @(); 
     foreach( $cVM in $hostobj.VMs | where { $_.Status -eq 'Running' }  | where { $_.ExcludeFromPRO -ne $TRUE} ) { $candidateVMs = $candidateVMs + $cVM; } 

     if($candidateVMs.Count -eq 0) { FailNoVMToMigrate $ProtipId $hostName; return; }  

     switch($vmErrorCode) {
     1 { foreach( $tVM in ($candidateVMs | sort PerfCPUUtilization -Descending) ) {  $selectedVM = $tVM;  break;  }  if( $selectedVM.PerfCPUUtilization -eq 0 ) { FailNoVMFound $ProtipId $vmErrorCode $hostName; return; }  } 
     2 { foreach( $tVM in ($candidateVMs | sort Memory -Descending) ) {  $selectedVM = $tVM;  break;  } if( $selectedVM.Memory -eq 0 ){  FailNoVMFound $ProtipId $vmErrorCode $hostName; return; }  }  default { FailInvalidErrorCode $ProtipId; return;  }  }   $isQuickMigration = $false;  $hostList = @(); $allhosts = Get-VMHost -VMHostGroup $hostobj.VMHostGroup;   if(($hostobj.HostCluster -ne $null ) -and ($hostobj.HostCluster.Nodes.Count -ne 1)){  foreach ( $tmpHost in  $hostobj.HostCluster.Nodes ) {  if( $tmpHost.Name -ne $hostobj.Name ) {  $hostList = $hostList + $tmpHost;  $isQuickMigration = $true;   }  }  }  else {  foreach ( $tmpHost in  $hostobj.VMHostGroup.Hosts ) {  if( $tmpHost.Name -ne $hostobj.Name ) {  $hostList = $hostList + $tmpHost;  }  }  }  if(($hostList -eq $null) -or ($hostList.Count -eq 0)) { FailNoHostToMigrateTo $ProtipId $hostName; return; } 

    $vmHostRatings = @(); $vmHostRatings = $vmHostRatings + ( @(Get-VMHostRating -VM $selectedVM -VMHost $hostList -IsMigration -UseDefaultPath) | Sort-Object -property Rating -descending | where { $_.Rating -ne 0 } ); 

     if ( $vmHostRatings.Count -eq $null) { FailNoHostToMigrateTo $ProtipId $hostName; return; } 

     $selectedVMHost = $hostList | where { ($_.Name -eq $vmHostRatings[0].VMHost.Name) };

     if($selectedVMHost -eq $null) { FailNoHostToMigrateTo $ProtipId $hostName; return; }

     $Error.Clear(); 
     if($isQuickMigration) { Move-VM -VM $selectedVM -VMHost $selectedVMHost -PROTipId $ProtipId;  }  else { 
    $defaultPaths = @($selectedVMHost.VMPaths | where { $_.StartsWith($vmHostRatings[0].PreferredVolume) -eq 1 }); 
     if($defaultPaths[0] -eq $null) { FailNoHostToMigrateTo $ProtipId $hostName; return; } 

     Move-VM -VM $selectedVM -VMHost $selectedVMHost -Path $defaultPaths[0] -PROTipId $ProtipId;  } 

     if( $Error.Count -ne 0) { FailGenericError $ProtipId $Error[0]; return; } 

     Set-PROTip -PROTipId $ProtipId -TipStatus Resolved; }

     Main;

  • 【IDM】ILM'2' 日本語ページが公開!

    女優の Y.T さんが結婚という報道がされてますね。ふーん。そうですか。全然興味ないですけどね...(涙)。

    ということで、全国1000万のILMファンの皆様、大変お待たせいたしました。

    ついに、ILM'2' 日本語サイトが公開されました。

    Identity Lifecycle Manager (ILM) “2”
    http://www.microsoft.com/japan/windowsserver/ilm2/default.mspx

    まだ情報は英語なのですが、これからバンバン日本語情報が掲載される予定です。

    管理者は見た!~AD と ILM 一家の秘密~ ともども、一層のご愛顧を。

    弊社、ILM 担当SEの山崎も張り切っておりますので、ILM”2”元年となる2009年もよろしくお願いいたします。

    ...とすっかり今年の仕事が終わったようなことを描いていますが、休めるかどうかさえ微妙な状況...あぁ....

     

  • 【IDM】一足早いお年玉 TechNet Magazine 2009年1月号は Identity 特集

    こんばんは。なんか、年末が近づくと、そわそわします。そういえば小学生の頃のこと、そわそわと落ち着きが無いと、「ギョウチュウがいるのか!」と思いっきりひっぱたかれた記憶があります。何度も何度も。だから、電車の中で落ち着かない人を見かけると、つい、ギョウチュウを疑ってしまいます。

    さて、ご存じ TechNet Magazine のご紹介です。

    まだ日本語化されていないコンテンツで恐縮なのですが、既に英語版の TechNet Magazine では 2009年 1月号 がリリースされています。

    1月号の特集は ID の整合性 で、Identity Lifecycle Manager 2 の紹介記事 が取り上げられています。

    この記事でILM が気になった方、是非とも1月17日のセミナーにご参加ください。

    単なる紹介記事とはいえ、正月早々、縁起が良いですね。

    そろそろ「厄」を心配しなければならないのですが、これで祓えました。ラッキーです。

    ちなみに、こちらも日本語化が進んでいる最中ですが、LinuxやMACとの相互互換性に関する記事が 2008年12月号に掲載されています。すべての記事が Interop です。超面白いので、是非ともお読みになってください。

    TechNet Magazine 2008年12月号

  • 【極秘】Dick と 田辺さんと 私の知られざる関係

    同僚の田辺の blog に Sxip Identity の Dick Hardt 氏が Microsoft に入社する旨の記事が投稿されました。

    “Identity 2.0” の Dick Hardt 氏が Microsoft に

    さて、ここで問題です。

    実は、Dick、田辺、安納 には知られざる共通点があります。

    それは何でしょう?

    ・・・正解は、

    興奮すると、うっすら、栃木訛りが出てしまうんです。 

    あと、シジミの味噌汁を飲むとカレーライスが食べたくなるんです。 

    嘘です。

    Dick Hardt といえば Active State。

    Active State と言えば、PerlScript (短絡的?)。

    ということで、正解は、こちら

    なんと、1998年に開催された オライリー社主宰の Perl Conference で出会っていたんですね。

    きっと、スピーカー控え室で、10年後の再開を約束したはずなんです(妄想)。

    でも、僕はこのとき、Larry Wall に夢中で Dick と田辺に気づいていませんでした。