using System; using System.Collections.Generic; using System.Diagnostics.Eventing.Reader; namespace Microsoft.Win32.TaskScheduler { /// /// Historical event information for a task. /// public sealed class TaskEvent : IComparable { internal TaskEvent(EventRecord rec) { this.EventId = rec.Id; this.EventRecord = rec; this.Version = rec.Version; this.TaskCategory = rec.TaskDisplayName; this.OpCode = rec.OpcodeDisplayName; this.TimeCreated = rec.TimeCreated; this.RecordId = rec.RecordId; this.ActivityId = rec.ActivityId; this.Level = rec.LevelDisplayName; this.UserId = rec.UserId; this.ProcessId = rec.ProcessId; this.TaskPath = rec.Properties.Count > 0 ? rec.Properties[0].Value.ToString() : null; } /// /// Gets the activity id. /// public Guid? ActivityId { get; internal set; } /// /// Gets the event id. /// public int EventId { get; internal set; } /// /// Gets the underlying . /// public EventRecord EventRecord { get; internal set; } /// /// Gets the level. /// public string Level { get; internal set; } /// /// Gets the op code. /// public string OpCode { get; internal set; } /// /// Gets the process id. /// public int? ProcessId { get; internal set; } /// /// Gets the record id. /// public long? RecordId { get; internal set; } /// /// Gets the task category. /// public string TaskCategory { get; internal set; } /// /// Gets the task path. /// public string TaskPath { get; internal set; } /// /// Gets the time created. /// public DateTime? TimeCreated { get; internal set; } /// /// Gets the user id. /// public System.Security.Principal.SecurityIdentifier UserId { get; internal set; } /// /// Gets the version. /// public byte? Version { get; internal set; } /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// public override string ToString() { return EventRecord.FormatDescription(); } /// /// Compares the current object with another object of the same type. /// /// An object to compare with this object. /// /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the other parameter.Zero This object is equal to other. Greater than zero This object is greater than other. /// public int CompareTo(TaskEvent other) { int i = this.TaskPath.CompareTo(other.TaskPath); if (i == 0) { i = this.ActivityId.ToString().CompareTo(other.ActivityId.ToString()); if (i == 0) i = Convert.ToInt32(this.RecordId - other.RecordId); } return i; } } /// /// An enumerator over a task's history of events. /// public sealed class TaskEventEnumerator : IEnumerator, IDisposable { private EventRecord curRec; private EventLogReader log; internal TaskEventEnumerator(EventLogReader log) { this.log = log; } /// /// Gets the element in the collection at the current position of the enumerator. /// /// /// The element in the collection at the current position of the enumerator. /// public TaskEvent Current { get { return new TaskEvent(curRec); } } /// /// Gets the element in the collection at the current position of the enumerator. /// /// /// The element in the collection at the current position of the enumerator. /// object System.Collections.IEnumerator.Current { get { return this.Current; } } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { log.CancelReading(); log.Dispose(); log = null; } /// /// Advances the enumerator to the next element of the collection. /// /// /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. /// /// /// The collection was modified after the enumerator was created. /// public bool MoveNext() { return (curRec = log.ReadEvent()) != null; } /// /// Sets the enumerator to its initial position, which is before the first element in the collection. /// /// /// The collection was modified after the enumerator was created. /// public void Reset() { log.Seek(System.IO.SeekOrigin.Begin, 0L); } internal void Seek(EventBookmark bookmark, long offset = 0L) { log.Seek(bookmark, offset); } internal void Seek(System.IO.SeekOrigin origin, long offset) { log.Seek(origin, offset); } } /// /// Historical event log for a task. Only available for Windows Vista and Windows Server 2008 and later systems. /// public sealed class TaskEventLog : IEnumerable { private EventLogQuery q; /// /// Initializes a new instance of the class. /// /// The task path. This can be retrieved using the property. /// Thrown when instantiated on an OS prior to Windows Vista. public TaskEventLog(string taskPath) : this(".", taskPath) { } /// /// Initializes a new instance of the class. /// /// Name of the machine. /// The task path. This can be retrieved using the property. /// The domain. /// The user. /// The password. /// Thrown when instantiated on an OS prior to Windows Vista. public TaskEventLog(string machineName, string taskPath, string domain = null, string user = null, string password = null) { const string queryString = "" + " " + " " + " " + ""; Initialize(machineName, string.Format(queryString, taskPath), true, domain, user, password); } /// /// Initializes a new instance of the class that looks at all task events from a specified time. /// /// The start time. /// Name of the task. /// Name of the machine (optional). /// The domain. /// The user. /// The password. public TaskEventLog(DateTime startTime, string taskName = null, string machineName = null, string domain = null, string user = null, string password = null) { int[] numArray = new int[] { 100, 0x66, 0x67, 0x6b, 0x6c, 0x6d, 0x6f, 0x75, 0x76, 0x77, 120, 0x79, 0x7a, 0x7b, 0x7c, 0x7d }; System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append("*[System[("); for (int i = 0; i < numArray.Length; i++) { sb.Append("EventID="); sb.Append(numArray[i]); if ((i + 1) < numArray.Length) sb.Append(" or "); } sb.Append(") and TimeCreated[@SystemTime>='"); sb.Append(System.Xml.XmlConvert.ToString(startTime, System.Xml.XmlDateTimeSerializationMode.RoundtripKind)); sb.Append("']]"); if (!string.IsNullOrEmpty(taskName)) sb.AppendFormat("and EventData[Data[@Name=\"TaskName\"]=\"{0}\"]", taskName); sb.Append("]"); Initialize(machineName, sb.ToString(), false, domain, user, password); } private void Initialize(string machineName, string query, bool revDir, string domain = null, string user = null, string password = null) { if (System.Environment.OSVersion.Version.Major < 6) throw new NotSupportedException("Enumeration of task history not available on systems prior to Windows Vista and Windows Server 2008."); System.Security.SecureString spwd = null; if (password != null) { spwd = new System.Security.SecureString(); int l = password.Length; foreach (char c in password.ToCharArray(0, l)) spwd.AppendChar(c); } q = new EventLogQuery("Microsoft-Windows-TaskScheduler/Operational", PathType.LogName, query) { ReverseDirection = revDir }; if (machineName != null && machineName != "." && !machineName.Equals(Environment.MachineName, StringComparison.InvariantCultureIgnoreCase)) q.Session = new EventLogSession(machineName, domain, user, spwd, SessionAuthentication.Default); } /// /// Gets the total number of events for this task. /// public long Count { get { using (EventLogReader log = new EventLogReader(q)) { long seed = 64L, l = 0L, h = seed; while (log.ReadEvent() != null) log.Seek(System.IO.SeekOrigin.Begin, l += seed); bool foundLast = false; while (l > 0L && h >= 1L) { if (foundLast) l += (h /= 2L); else l -= (h /= 2L); log.Seek(System.IO.SeekOrigin.Begin, l); foundLast = (log.ReadEvent() != null); } return foundLast ? l + 1L : l; } } } /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can be used to iterate through the collection. /// public IEnumerator GetEnumerator() { return GetEnumerator(false); } /// /// Returns an enumerator that iterates through the collection. /// /// if set to true [reverse]. /// /// A that can be used to iterate through the collection. /// public IEnumerator GetEnumerator(bool reverse) { q.ReverseDirection = !reverse; return new TaskEventEnumerator(new EventLogReader(q)); } /// /// Returns an enumerator that iterates through a collection. /// /// /// An object that can be used to iterate through the collection. /// System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } }