WMIを使用して特定の日付に発生したセキュリティイベントログを取得します。イベントログのフィルタ条件に日時を指定する場合は、UTC時間を指定する必要があることに注意します。

確認環境

  • 動作環境:Windows Server 2003
  • 開発環境:Visual Studio 2008 Professional
  • .NET 2.0

参考リンク

イベントログをWMI経由で取得するための参考リンク集 
-  WMI .NET コードのディレクトリ 
http://msdn.microsoft.com/ja-jp/library/bb404665.aspx 
- WMI Reference 
http://msdn.microsoft.com/en-us/library/aa394572.aspx 
- Event Log Provider 
http://msdn.microsoft.com/en-us/library/aa390413(VS.85).aspx 
- Win32_NTLogEvent Class 
http://msdn.microsoft.com/en-us/library/aa394226(VS.85).aspx

1. セキュリティイベントログを取得する

Visual Studio でコンソールプロジェクトを新規作成し、参照の追加でSystem.Management.dllを参照に加えます。

1.1 Win32_NTLogEvent クラスの作成

Event Log Provider を使用してイベントログを取得すると、Win32_NTLogEvent クラスが返されます。そのため、処理がしやすいように.NET 側でWin32_NTLogEvent クラスを作成します。詳細は冒頭の参考リンク参照。

/// <summary>
/// Win32_NTLogEvent Classを定義した.NET用のクラス
/// http://msdn.microsoft.com/en-us/library/aa394226(VS.85).aspx
/// </summary>
public class Win32_NTLogEvent
{
    public UInt16 Category { get; set; }
    public string CategoryString { get; set; }
    public string ComputerName { get; set; }
    public byte[] Data { get; set; }
    public UInt16 EventCode { get; set; }
    public UInt32 EventIdentifier { get; set; }
    public byte EventType { get; set; }
    public string[] InsertionStrings { get; set; }
    public string Logfile { get; set; }
    public string Message { get; set; }
    public UInt32 RecordNumber { get; set; }
    public string SourceName { get; set; }
    public DateTime TimeGenerated { get; set; }
    public DateTime TimeWritten { get; set; }
    public string Type { get; set; }
    public string User { get; set; }
    public Win32_NTLogEvent(ManagementObject managementObject)
    {
        this.Category = (UInt16)managementObject.GetPropertyValue("Category");
        this.CategoryString = (string)managementObject.GetPropertyValue("CategoryString");
        this.ComputerName = (string)managementObject.GetPropertyValue("ComputerName");
        this.Data = (byte[])managementObject.GetPropertyValue("Data");
        this.EventCode = (UInt16)managementObject.GetPropertyValue("EventCode");
        this.EventIdentifier = (UInt32)managementObject.GetPropertyValue("EventIdentifier");
        this.EventType = (byte)managementObject.GetPropertyValue("EventType");
        this.InsertionStrings = (string[])managementObject.GetPropertyValue("InsertionStrings");
        this.Logfile = (string)managementObject.GetPropertyValue("Logfile");
        this.Message = (string)managementObject.GetPropertyValue("Message");
        this.RecordNumber = (UInt32)managementObject.GetPropertyValue("RecordNumber");
        this.SourceName = (string)managementObject.GetPropertyValue("SourceName");
        this.TimeGenerated = ManagementDateTimeConverter.ToDateTime(managementObject.GetPropertyValue("TimeGenerated") as string);
        this.TimeWritten = ManagementDateTimeConverter.ToDateTime(managementObject.GetPropertyValue("TimeWritten") as string);
        this.Type = (string)managementObject.GetPropertyValue("Type");
        this.User = (string)managementObject.GetPropertyValue("User");
    }
    public override string ToString()
    {
        StringBuilder builder = new StringBuilder();
        builder.Append("Category=" + Category);
        builder.Append("CategoryString=" + CategoryString);
        builder.Append("Message=" + Message);
        return builder.ToString();
    }
}

 

1.2 Win32_NTLogEvent の取得

取得する日付を指定してセキュリティのログファイルからイベントログを取得するサンプルを示します。取得する日時はUTC時間を指定する必要があります。コメントに書いてあるとおり、ユーザ名、パスワードを指定すると現在の実行ユーザ以外の資格情報を使用してログを取得できます。

class Program
{
    /// 
    /// セキュリティイベントログを取得する。
     /// 
    /// 
    static void Main(string[] args)
    {
        ConnectionOptions option = new ConnectionOptions();
        option.EnablePrivileges = true; 
        option.Impersonation = ImpersonationLevel.Impersonate;
        // 資格情報に実行中のユーザ以外をしていする
         // 場合に設定
         //option.Username = "Administrator";
        //option.Password = "password";

        ManagementScope scope = new ManagementScope();
        scope.Path.Path = @"\root\cimv2";
        scope.Path.NamespacePath = @"\root\cimv2";
        scope.Path.Server = "localhost"; // 取得するノード名を指定
        scope.Options = option;

        string filter = GetFilter(DateTime.Today);
        SelectQuery selectQuery = new SelectQuery("Win32_NTLogEvent", filter);

        ManagementObjectSearcher searchar = new ManagementObjectSearcher(scope, selectQuery);

        int logcount = 0;
        foreach (ManagementObject mo in searchar.Get())
        {
            Win32_NTLogEvent eventLog = new Win32_NTLogEvent(mo);
            Console.WriteLine(eventLog.ToString());
            ++logcount;
        }
        Console.WriteLine("ログ数" + logcount.ToString());
        Console.ReadLine();
    }
    /// 
    /// 指定された日付(ローカル日時)の発生したセキュリティログイベントを取得する。
     /// 時間はUTC時間に変換する必要がある。
     /// 
    /// 
    /// 
    public static string GetFilter(DateTime logDate)
    {
        DateTime utcStartTime = logDate.ToUniversalTime();
        DateTime utcEndTime = logDate.AddDays(1).ToUniversalTime();
        return string.Format("Logfile='{0}' AND TimeGenerated >= '{1}' AND TimeGenerated < '{2}'", "Security", utcStartTime.ToString(), utcEndTime.ToString());
    }
}

WMIを使用すると、System.Diagnostics.EventLog クラスを使用するよりも柔軟性が高い検索を行えます。

2. まとめ

説明は以上です。間違い、指摘点等がありましたらご指摘ください。