トップ回答者
windows7 シャットダウン時のイベントログ取得エラーについて

質問
-
お世話になっております。
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にさせたいです。
そのため、イベントログサービスの停止の順番を制御し、開発したサービスよりも後ろにすればよいかと
考えたのですが、そのようなことが可能でしょうか。
また他に何か良い方法があれば助言頂きたく、どうぞよろしくお願い致します。
回答
-
jzkey さま
返信遅くなり大変申し訳ございません。
ご教示頂いた通り、サービスがシャットダウン通知を受け取った際に、待つだけではなくて
能動的に取得すればイベントログは取得できるかもしれません。ただ、プログラムの修正規模が大きそうなのと、カットオーバーまで時間があまりなかったため、
別の手段で解決しました。助言頂きありがとうございました。別の手段ですが、
ドメインポリシーのシャットダウンスクリプトに、timeout 5 を実行するバッチを登録する
という方法です。
本対応を行う事で、ユーザーログオフ から サービスの停止処理開始 までの間に5秒の間を設ける事が
できまして、ユーザーログオフ(5秒待機が開始)→ ログオフイベントの生成 → サービスがログオフイベントを検出して取得・ファイルに出力(ここまで5秒かからないため、全ての処理が正常に終了)→ 5秒経過後に、サービスの停止処理開始
となりました。
ひとまずこちらで様子を見て頂く事になりました。ありがとうございます。
- 回答としてマーク supao 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
-
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までお気軽にお問い合わせください。~ -
jzkey さま
返信遅くなり大変申し訳ございません。
ご教示頂いた通り、サービスがシャットダウン通知を受け取った際に、待つだけではなくて
能動的に取得すればイベントログは取得できるかもしれません。ただ、プログラムの修正規模が大きそうなのと、カットオーバーまで時間があまりなかったため、
別の手段で解決しました。助言頂きありがとうございました。別の手段ですが、
ドメインポリシーのシャットダウンスクリプトに、timeout 5 を実行するバッチを登録する
という方法です。
本対応を行う事で、ユーザーログオフ から サービスの停止処理開始 までの間に5秒の間を設ける事が
できまして、ユーザーログオフ(5秒待機が開始)→ ログオフイベントの生成 → サービスがログオフイベントを検出して取得・ファイルに出力(ここまで5秒かからないため、全ての処理が正常に終了)→ 5秒経過後に、サービスの停止処理開始
となりました。
ひとまずこちらで様子を見て頂く事になりました。ありがとうございます。
- 回答としてマーク supao 2019年10月17日 8:58