is the event log index unique

2019-09-05 09:18发布

问题:

I am getting the information from the event log in windows with this:

private void button1_Click(object sender, EventArgs e)
{
  EventLog eventLog;
  eventLog = new EventLog();
  eventLog.Log = "Security";;
  eventLog.Source = "Security-Auditing";
  eventLog.MachineName = "SERVER";

  var count = 0;
  foreach (EventLogEntry log in eventLog.Entries.Cast<EventLogEntry>().Where(log => log.InstanceId == 4625))
  {
    Console.Write("eventLogEntry.Index: {0}{1}", log.Index, Environment.NewLine);
    SaveRecord(log);
    count++;
  }
}

I am trying to capture all of the invalid logins to my server and then add an entry after x amount of times of invalid attempts.

I am looping through the event log and getting the information without issue but how do I know what the last record that I stopped reading at? When the log gets more information, I need to restart reading again but I need a starting point.

I was thinking I could use the Index on the EventLogEntry but I cannot find any information on it. The ones I have on my machine as 6 digit numbers.

How reliable is that? Should I be going off something else? Should I clear that log after I read it instead?

Thanks for your input!

======= WHAT I DID ========

With Apokal's help, here is what I did:

/// <summary>
/// Returns all events in the windows event log that match the passed in criteria.
/// If nothing is passed in then it will return all events where the a user attemtped
/// to log into the the machine and gave an invalid username or password.
/// </summary>
/// <param name="eventLogMachineName">The machine where the event log is at.</param>
/// <param name="cutoffdatetime">Date and time of the cut off for the list.</param>
/// <param name="eventLogName">'Log Name' in the event log. This is the folder that the events reside in.</param>
/// <param name="eventLogSource">Event log 'Source'.</param>
/// <param name="instanceId">Filters to a specific 'Event Id' in the event log.</param>
/// <returns></returns>
public static IEnumerable<EventLogEntry> GetEventLogs(string eventLogMachineName,
                                                      DateTime cutoffdatetime,
                                                      string eventLogName = "Security",
                                                      string eventLogSource = "Security-Auditing",
                                                      int instanceId = 4625)
{
  var eventLog = new EventLog {Log = eventLogName, Source = eventLogSource, MachineName = eventLogMachineName};
  return from EventLogEntry log in eventLog.Entries
         where log.InstanceId == instanceId &&
               log.TimeGenerated > cutoffdatetime
         select log;
}

And I call it like this:

private void button1_Click(object sender, EventArgs e)
{
  var lastcheckdatetime = Properties.Settings.Default.LastCheckDate;
  if (lastcheckdatetime < (DateTime.Now.AddDays(-30)))
  {
    lastcheckdatetime = DateTime.Now.AddDays(-7);
  }
  var log = EventLogClass.GetEventLogs("TGSERVER", lastcheckdatetime);
  Properties.Settings.Default.LastCheckDate = DateTime.Now;
  Properties.Settings.Default.Save();

  var count = 0;
  foreach (EventLogEntry l in log)
  {
    Console.WriteLine("---------------------");
    Console.Write("eventLogEntry.Index: {0}{1}", l.Index, Environment.NewLine);
    Console.Write("eventLogEntry.TimeGenerated: {0}{1}", l.TimeGenerated, Environment.NewLine);
    count++;
  }
}

回答1:

From me experience and little research Index property shows the index of event that was written beginning from the creation of event log.

But there are several things that you missed.

First, you have to remember that event logs have limited size. For example, imagine "Security" log can hold only 1000 entries (the actual size in mb shown in eventlog properties, if you look in eventvwr.msc). So when, event log is full there are 3 ways:

  1. Write new events over old ones. In this case, remembering the last readed event index is not good. because the event pointed by that index could be simply overwritten.
  2. Make an archive. In this case, remembered index can now point event that is in archive, not in current .evtx file of the eventlog
  3. Do not write new events, manualy clear event log. I don't think this is interesting, because you want an automated tool.

So, one could set eventlog to be archived and remember the last index of event. Then when reading again eventlog, first get the oldest recored of current event log file:

EventLog log = new System.Diagnostics.EventLog("Security");
int oldestIndex = log.Entries[(int)eli.OldestRecordNumber].Index;

Then compare oldestIndex with yours lastReadedIndex and if lastReadedIndex < oldestIndex you first have to read archives, and only than read the current event log file.

All archives are stored by default in the same directory where the current event log file exists (.evtx). Archives can be easily readed by using EventLogReader class. Try to look at EventRecord and it's RecordId property, I think it's the same as Index property of the EventLogEntry class (can't check at the moment).

Another approach is to remember the time, when event was written, and use it as starting point for searching new events, in case Index and RecordId wouldn't help.

Good luck!