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();
}
}
}