none
windows7 シャットダウン時のイベントログ取得エラーについて RRS feed

  • 質問

  • お世話になっております。

    windows7 pro 32bit の端末向けに,  visual C++ で windows サービスプログラムを開発しています。
    EvtSubscribe() を使ってイベントログ出力を検出し、ログに残す仕組みを構築しました。
    検出するイベントIDを絞っていて、 ログオン( 4624 )  と ログオフ ( 4647 ) の2つにしています。

    端末ログイン状態から、シャットダウンを行った際にうまくログオフイベントが拾えない場合があり
    ご相談させていただきます。

    ■ 事象
    シャットダウン時なのでログオフイベントが出力されるのですが、そのイベントを EvtSubscribe() で
    検出し、パラメーターで指定したコールバック関数が呼ばれるのですが、コールバック関数の引数 EVT_SUBSCRIBE_NOTIFY_ACTION では
    EvtSubscribeActionError が格納されており、GetLastError() の結果は RPC_S_CALL_CANCELLED ( 0x71A ) でした。
    エラーのため、ログオフのイベントが拾えず、次回電源ONになってサービスが起動した際に拾えていました。
    ※100%この事象が起こるわけではなく、正しくログオフイベントを拾える場合もあります。
     拾えた場合は、サービス停止を5秒延長して別サーバーにログを送ってからサービスを停止しています。

    イベントログを見ると、
      (1)   RecordID:45554   EventID: 1100   ソース:Eventlog   内容: イベントログサービスがシャットダウンされました
        (2)   RecordID:45555   EventID: 4647   ソース:Security-Auditing  内容:ユーザー開始のログオフ:・・・
    という順番で記録されていました。
    ※ 記録された時刻は (2)->(1) の順番なのですが、RecordID は (1) -> (2) の順番になっています。

    ■ 原因(想定)
    イベントログの記録から、イベントログサービスが停止したあと?にログオフイベントが発生して、
    開発したサービスプログラムでも拾えずに RPC_S_CALL_CANCELLED になっていたと考えております。

    ■ 対応案
    シャットダウン時にどうにかしてログオフイベントを拾って別サーバーに送ってから電源OFFにさせたいです。
    そのため、イベントログサービスの停止の順番を制御し、開発したサービスよりも後ろにすればよいかと
    考えたのですが、そのようなことが可能でしょうか。
    また他に何か良い方法があれば助言頂きたく、どうぞよろしくお願い致します。

    2019年9月16日 15:34

回答

  • jzkey さま

    返信遅くなり大変申し訳ございません。
    ご教示頂いた通り、サービスがシャットダウン通知を受け取った際に、待つだけではなくて
    能動的に取得すればイベントログは取得できるかもしれません。

    ただ、プログラムの修正規模が大きそうなのと、カットオーバーまで時間があまりなかったため、
    別の手段で解決しました。助言頂きありがとうございました。

    別の手段ですが、

     ドメインポリシーのシャットダウンスクリプトに、timeout 5 を実行するバッチを登録する

    という方法です。

    本対応を行う事で、ユーザーログオフ から サービスの停止処理開始 までの間に5秒の間を設ける事が
    できまして、

     ユーザーログオフ(5秒待機が開始)→ ログオフイベントの生成 → サービスがログオフイベントを検出して取得・ファイルに出力(ここまで5秒かからないため、全ての処理が正常に終了)→ 5秒経過後に、サービスの停止処理開始

    となりました。

    ひとまずこちらで様子を見て頂く事になりました。ありがとうございます。

    • 回答としてマーク supao 2019年10月17日 8:58
    2019年10月17日 8:58

すべての返信

  • シャットダウンはタイミングがいろいろ面倒くさくなるので、別途扱った方がよいのでは。
    サービスというのであれば、RegisterServiceCtrlHandlerExあたりを登録しておいて、SERVICE_CONTROL_PRESHUTDOWNを拾って処理するとか。

    ただし、むやみにシャットダウンを延長すると、「services should use this feature only if it is absolutely necessary to avoid data loss or significant recovery time at the next system start」とあるように、要するに「今すぐ電源を切りたいのに、ネットワーク/サーバが死んでるのでシャットダウンできない」的な事態になるとは思います。


    jzkey

    2019年9月16日 22:43
  • シャットダウン時にどうにかしてログオフイベントを拾って別サーバーに送ってから電源OFFにさせたい

    シャットダウン時にネットワークが生きている(ネットワークドライバ他、関連サービスが停止前)というのは確認済みでしょうか?

    個人的にはシャットダウン時にネットワーク通信を行うのは非現実的と思います。

    2019年9月16日 23:20
  • jzkey さま

    ありがとうございます。
    シャットダウン時にサービスから能動的にイベントログを拾ったりはしていないため、
    PRESHUTDOWNを拾ってもイベントログが拾えない問題は解決しないと考えております。

    EvtSubscribe() の実行がエラーになり、ログオフイベントが検出できないことが問題と
    考えておりまして、エラーにならないように、イベントログサービスの終了を遅くできないか?を調べておりました。

    2019年9月17日 1:37
  • 佐祐理さま

    ありがとうございます。

    確かにおっしゃる通りネットワークをあまり気にしておりませんでした。

    ただ、正常にログオフイベントが拾えた場合は転送までうまくいっていまして、
    ネットワークは問題無いかと考えています。

    2019年9月17日 1:38
  • ?? シャットダウン通知があなたのサービズに届いたのであれば、それはログオフであるわけで、別途イベントログを改めて待つ必要は無い、と申し上げたつもりですが。

    jzkey

    2019年9月17日 2:16
  • supaoさん、こんにちは。フォーラムオペレーターのHarukaです。
    MSDNフォーラムにご投稿くださいましてありがとうございます。

    Windowsの一部であるシステムイベント通知サービステクノロジーを使用できます。
    https://docs.microsoft.com/en-us/windows/win32/sens/system-event-notification-service-portal?redirectedfrom=MSDN

    ログオン/ログオフイベント(およびリモートセッション接続などの他のイベント)を提供するISensLogon2インターフェイスがあります。
    https://docs.microsoft.com/en-us/windows/win32/api/sensevts/nn-sensevts-isenslogon2?redirectedfrom=MSDN

    下記のコードサンプルをご参照いただければと思います。
    https://stackoverflow.com/a/16395444/10611792

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


    MSDN/ TechNet Community Support Haruka

    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、
    ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年9月18日 8:14
    モデレータ
  • jzkey さま

    返信遅くなり大変申し訳ございません。
    ご教示頂いた通り、サービスがシャットダウン通知を受け取った際に、待つだけではなくて
    能動的に取得すればイベントログは取得できるかもしれません。

    ただ、プログラムの修正規模が大きそうなのと、カットオーバーまで時間があまりなかったため、
    別の手段で解決しました。助言頂きありがとうございました。

    別の手段ですが、

     ドメインポリシーのシャットダウンスクリプトに、timeout 5 を実行するバッチを登録する

    という方法です。

    本対応を行う事で、ユーザーログオフ から サービスの停止処理開始 までの間に5秒の間を設ける事が
    できまして、

     ユーザーログオフ(5秒待機が開始)→ ログオフイベントの生成 → サービスがログオフイベントを検出して取得・ファイルに出力(ここまで5秒かからないため、全ての処理が正常に終了)→ 5秒経過後に、サービスの停止処理開始

    となりました。

    ひとまずこちらで様子を見て頂く事になりました。ありがとうございます。

    • 回答としてマーク supao 2019年10月17日 8:58
    2019年10月17日 8:58
  • Haruka さま

    返信遅くなり申し訳ございません。

    教えて頂いたサイトについてですが、こういった技術がある事を知りませんでした。
    大変勉強になりました。ありがとうございます。

    基本的にはCOMは使用しないでコーディングしておりまして、
    (お恥ずかしい話ですがCOMの使い方があまり分かっていないのが正直なところです)
    時間もあまり無かったため、別に投稿したシャットダウンスクリプトでひとまず様子を見ることになりました。

    ご教示頂きありがとうございます。

    2019年10月17日 9:01