using System; using System.Collections.Generic; using System.Diagnostics.Eventing.Reader; using JetBrains.Annotations; // ReSharper disable MemberCanBePrivate.Global // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global namespace Microsoft.Win32.TaskScheduler { /// /// Changes to tasks and the engine that cause events. /// public enum StandardTaskEventId { /// Task Scheduler started an instance of a task for a user. /// For detailed information, see the documentation for Event ID 100 on TechNet. JobStart = 100, /// Task Scheduler failed to start a task for a user. /// For detailed information, see the documentation for Event ID 101 on TechNet. JobStartFailed = 101, /// Task Scheduler successfully finished an instance of a task for a user. /// For detailed information, see the documentation for Event ID 102 on TechNet. JobSuccess = 102, /// Task Scheduler failed to start an instance of a task for a user. /// For detailed information, see the documentation for Event ID 103 on TechNet. JobFailure = 103, /// Task Scheduler failed to log on the user. /// For detailed information, see the documentation for Event ID 104 on TechNet. LogonFailure = 104, /// Task Scheduler failed to impersonate a user. /// For detailed information, see the documentation for Event ID 105 on TechNet. ImpersonationFailure = 105, /// The a user registered the Task Scheduler a task. /// For detailed information, see the documentation for Event ID 106 on TechNet. JobRegistered = 106, /// Task Scheduler launched an instance of a task due to a time trigger. /// For detailed information, see the documentation for Event ID 107 on TechNet. TimeTrigger = 107, /// Task Scheduler launched an instance of a task due to an event trigger. /// For detailed information, see the documentation for Event ID 108 on TechNet. EventTrigger = 108, /// Task Scheduler launched an instance of a task due to a registration trigger. /// For detailed information, see the documentation for Event ID 109 on TechNet. ImmediateTrigger = 109, /// Task Scheduler launched an instance of a task for a user. /// For detailed information, see the documentation for Event ID 110 on TechNet. Run = 110, /// Task Scheduler terminated an instance of a task due to exceeding the time allocated for execution, as configured in the task definition. /// For detailed information, see the documentation for Event ID 111 on TechNet. JobTermination = 111, /// Task Scheduler could not start a task because the network was unavailable. Ensure the computer is connected to the required network as specified in the task. /// For detailed information, see the documentation for Event ID 112 on TechNet. JobNoStartWithoutNetwork = 112, /// The Task Scheduler registered the a task, but not all the specified triggers will start the task. Ensure all the task triggers are valid. /// For detailed information, see the documentation for Event ID 113 on TechNet. TaskRegisteredWithoutSomeTriggers = 113, /// Task Scheduler could not launch a task as scheduled. Instance is started now as required by the configuration option to start the task when available, if the scheduled time is missed. /// For detailed information, see the documentation for Event ID 114 on TechNet. MissedTaskLaunched = 114, /// Task Scheduler failed to roll back a transaction when updating or deleting a task. /// For detailed information, see the documentation for Event ID 115 on TechNet. TransactionRollbackFailure = 115, /// Task Scheduler saved the configuration for a task, but the credentials used to run the task could not be stored. /// For detailed information, see the documentation for Event ID 116 on TechNet. TaskRegisteredWithoutCredentials = 116, /// Task Scheduler launched an instance of a task due to an idle condition. /// For detailed information, see the documentation for Event ID 117 on TechNet. IdleTrigger = 117, /// Task Scheduler launched an instance of a task due to system startup. /// For detailed information, see the documentation for Event ID 118 on TechNet. BootTrigger = 118, /// Task Scheduler launched an instance of a task due to a user logon. /// For detailed information, see the documentation for Event ID 119 on TechNet. LogonTrigger = 119, /// Task Scheduler launched an instance of a task due to a user connecting to the console. /// For detailed information, see the documentation for Event ID 120 on TechNet. ConsoleConnectTrigger = 120, /// Task Scheduler launched an instance of a task due to a user disconnecting from the console. /// For detailed information, see the documentation for Event ID 121 on TechNet. ConsoleDisconnectTrigger = 121, /// Task Scheduler launched an instance of a task due to a user remotely connecting. /// For detailed information, see the documentation for Event ID 122 on TechNet. RemoteConnectTrigger = 122, /// Task Scheduler launched an instance of a task due to a user remotely disconnecting. /// For detailed information, see the documentation for Event ID 123 on TechNet. RemoteDisconnectTrigger = 123, /// Task Scheduler launched an instance of a task due to a user locking the computer. /// For detailed information, see the documentation for Event ID 124 on TechNet. SessionLockTrigger = 124, /// Task Scheduler launched an instance of a task due to a user unlocking the computer. /// For detailed information, see the documentation for Event ID 125 on TechNet. SessionUnlockTrigger = 125, /// Task Scheduler failed to execute a task. Task Scheduler is attempting to restart the task. /// For detailed information, see the documentation for Event ID 126 on TechNet. FailedTaskRestart = 126, /// Task Scheduler failed to execute a task due to a shutdown race condition. Task Scheduler is attempting to restart the task. /// For detailed information, see the documentation for Event ID 127 on TechNet. RejectedTaskRestart = 127, /// Task Scheduler did not launch a task because the current time exceeds the configured task end time. /// For detailed information, see the documentation for Event ID 128 on TechNet. IgnoredTaskStart = 128, /// Task Scheduler launched an instance of a task in a new process. /// For detailed information, see the documentation for Event ID 129 on TechNet. CreatedTaskProcess = 129, /// The Task Scheduler service failed to start a task due to the service being busy. /// For detailed information, see the documentation for Event ID 130 on TechNet. TaskNotRunServiceBusy = 130, /// Task Scheduler failed to start a task because the number of tasks in the task queue exceeds the quota currently configured. /// For detailed information, see the documentation for Event ID 131 on TechNet. TaskNotStartedTaskQueueQuotaExceeded = 131, /// The Task Scheduler task launching queue quota is approaching its preset limit of tasks currently configured. /// For detailed information, see the documentation for Event ID 132 on TechNet. TaskQueueQuotaApproaching = 132, /// Task Scheduler failed to start a task in the task engine for a user. /// For detailed information, see the documentation for Event ID 133 on TechNet. TaskNotStartedEngineQuotaExceeded = 133, /// Task Engine for a user is approaching its preset limit of tasks. /// For detailed information, see the documentation for Event ID 134 on TechNet. EngineQuotaApproaching = 134, /// Task Scheduler did not launch a task because launch condition not met, machine not idle. /// For detailed information, see the documentation for Event ID 135 on TechNet. NotStartedWithoutIdle = 135, /// A user updated Task Scheduler a task /// For detailed information, see the documentation for Event ID 140 on TechNet. TaskUpdated = 140, /// A user deleted Task Scheduler a task /// For detailed information, see the documentation for Event ID 141 on TechNet. TaskDeleted = 141, /// A user disabled Task Scheduler a task /// For detailed information, see the documentation for Event ID 142 on TechNet. TaskDisabled = 142, /// Task Scheduler woke up the computer to run a task. /// For detailed information, see the documentation for Event ID 145 on TechNet. TaskStartedOnComputerWakeup = 145, /// Task Scheduler failed to subscribe the event trigger for a task. /// For detailed information, see the documentation for Event ID 150 on TechNet. TaskEventSubscriptionFailed = 150, /// Task Scheduler launched an action in an instance of a task. /// For detailed information, see the documentation for Event ID 200 on TechNet. ActionStart = 200, /// Task Scheduler successfully completed a task instance and action. /// For detailed information, see the documentation for Event ID 201 on TechNet. ActionSuccess = 201, /// Task Scheduler failed to complete an instance of a task with an action. /// For detailed information, see the documentation for Event ID 202 on TechNet. ActionFailure = 202, /// Task Scheduler failed to launch an action in a task instance. /// For detailed information, see the documentation for Event ID 203 on TechNet. ActionLaunchFailure = 203, /// Task Scheduler failed to retrieve the event triggering values for a task . The event will be ignored. /// For detailed information, see the documentation for Event ID 204 on TechNet. EventRenderFailed = 204, /// Task Scheduler failed to match the pattern of events for a task. The events will be ignored. /// For detailed information, see the documentation for Event ID 205 on TechNet. EventAggregateFailed = 205, /// Task Scheduler is shutting down the a task engine. /// For detailed information, see the documentation for Event ID 301 on TechNet. SessionExit = 301, /// Task Scheduler is shutting down the a task engine due to an error. /// For detailed information, see the documentation for Event ID 303 on TechNet. SessionError = 303, /// Task Scheduler sent a task to a task engine. /// For detailed information, see the documentation for Event ID 304 on TechNet. SessionSentJob = 304, /// Task Scheduler did not send a task to a task engine. /// For detailed information, see the documentation for Event ID 305 on TechNet. SessionSentJobFailed = 305, /// For a Task Scheduler task engine, the thread pool failed to process the message. /// For detailed information, see the documentation for Event ID 306 on TechNet. SessionFailedToProcessMessage = 306, /// The Task Scheduler service failed to connect to a task engine process. /// For detailed information, see the documentation for Event ID 307 on TechNet. SessionManagerConnectFailed = 307, /// Task Scheduler connected to a task engine process. /// For detailed information, see the documentation for Event ID 308 on TechNet. SessionConnected = 308, /// There are Task Scheduler tasks orphaned during a task engine shutdown. /// For detailed information, see the documentation for Event ID 309 on TechNet. SessionJobsOrphaned = 309, /// Task Scheduler started a task engine process. /// For detailed information, see the documentation for Event ID 310 on TechNet. SessionProcessStarted = 310, /// Task Scheduler failed to start a task engine process due to an error. /// For detailed information, see the documentation for Event ID 311 on TechNet. SessionProcessLaunchFailed = 311, /// Task Scheduler created the Win32 job object for a task engine. /// For detailed information, see the documentation for Event ID 312 on TechNet. SessionWin32ObjectCreated = 312, /// The Task Scheduler channel is ready to send and receive messages. /// For detailed information, see the documentation for Event ID 313 on TechNet. SessionChannelReady = 313, /// Task Scheduler has no tasks running for a task engine, and the idle timer has started. /// For detailed information, see the documentation for Event ID 314 on TechNet. SessionIdle = 314, /// A task engine process failed to connect to the Task Scheduler service. /// For detailed information, see the documentation for Event ID 315 on TechNet. SessionProcessConnectFailed = 315, /// A task engine failed to send a message to the Task Scheduler service. /// For detailed information, see the documentation for Event ID 316 on TechNet. SessionMessageSendFailed = 316, /// Task Scheduler started a task engine process. /// For detailed information, see the documentation for Event ID 317 on TechNet. SessionProcessMainStarted = 317, /// Task Scheduler shut down a task engine process. /// For detailed information, see the documentation for Event ID 318 on TechNet. SessionProcessMainShutdown = 318, /// A task engine received a message from the Task Scheduler service requesting to launch a task. /// For detailed information, see the documentation for Event ID 319 on TechNet. SessionProcessReceivedStartJob = 319, /// A task engine received a message from the Task Scheduler service requesting to stop a task instance. /// For detailed information, see the documentation for Event ID 320 on TechNet. SessionProcessReceivedStopJob = 320, /// Task Scheduler did not launch a task because an instance of the same task is already running. /// For detailed information, see the documentation for Event ID 322 on TechNet. NewInstanceIgnored = 322, /// Task Scheduler stopped an instance of a task in order to launch a new instance. /// For detailed information, see the documentation for Event ID 323 on TechNet. RunningInstanceStopped = 323, /// Task Scheduler queued an instance of a task and will launch it as soon as another instance completes. /// For detailed information, see the documentation for Event ID 324 on TechNet. NewInstanceQueued = 324, /// Task Scheduler queued an instance of a task that will launch immediately. /// For detailed information, see the documentation for Event ID 325 on TechNet. InstanceQueued = 325, /// Task Scheduler did not launch a task because the computer is running on batteries. If launching the task on batteries is required, change the respective flag in the task configuration. /// For detailed information, see the documentation for Event ID 326 on TechNet. NoStartOnBatteries = 326, /// Task Scheduler stopped an instance of a task because the computer is switching to battery power. /// For detailed information, see the documentation for Event ID 327 on TechNet. StoppingOnBatteries = 327, /// Task Scheduler stopped an instance of a task because the computer is no longer idle. /// For detailed information, see the documentation for Event ID 328 on TechNet. StoppingOffIdle = 328, /// Task Scheduler stopped an instance of a task because the task timed out. /// For detailed information, see the documentation for Event ID 329 on TechNet. StoppingOnTimeout = 329, /// Task Scheduler stopped an instance of a task as request by a user . /// For detailed information, see the documentation for Event ID 330 on TechNet. StoppingOnRequest = 330, /// Task Scheduler will continue to execute an instance of a task even after the designated timeout, due to a failure to create the timeout mechanism. /// For detailed information, see the documentation for Event ID 331 on TechNet. TimeoutWontWork = 331, /// Task Scheduler did not launch a task because a user was not logged on when the launching conditions were met. Ensure the user is logged on or change the task definition to allow the task to launch when the user is logged off. /// For detailed information, see the documentation for Event ID 332 on TechNet. NoStartUserNotLoggedOn = 332, /// The Task Scheduler service has started. /// For detailed information, see the documentation for Event ID 400 on TechNet. ScheduleServiceStart = 400, /// The Task Scheduler service failed to start due to an error. /// For detailed information, see the documentation for Event ID 401 on TechNet. ScheduleServiceStartFailed = 401, /// Task Scheduler service is shutting down. /// For detailed information, see the documentation for Event ID 402 on TechNet. ScheduleServiceStop = 402, /// The Task Scheduler service has encountered an error. /// For detailed information, see the documentation for Event ID 403 on TechNet. ScheduleServiceError = 403, /// The Task Scheduler service has encountered an RPC initialization error. /// For detailed information, see the documentation for Event ID 404 on TechNet. ScheduleServiceRpcInitError = 404, /// The Task Scheduler service has failed to initialize COM. /// For detailed information, see the documentation for Event ID 405 on TechNet. ScheduleServiceComInitError = 405, /// The Task Scheduler service failed to initialize the credentials store. /// For detailed information, see the documentation for Event ID 406 on TechNet. ScheduleServiceCredStoreInitError = 406, /// Task Scheduler service failed to initialize LSA. /// For detailed information, see the documentation for Event ID 407 on TechNet. ScheduleServiceLsaInitError = 407, /// Task Scheduler service failed to initialize idle state detection module. Idle tasks may not be started as required. /// For detailed information, see the documentation for Event ID 408 on TechNet. ScheduleServiceIdleServiceInitError = 408, /// The Task Scheduler service failed to initialize a time change notification. System time updates may not be picked by the service and task schedules may not be updated. /// For detailed information, see the documentation for Event ID 409 on TechNet. ScheduleServiceTimeChangeInitError = 409, /// Task Scheduler service received a time system change notification. /// For detailed information, see the documentation for Event ID 411 on TechNet. ScheduleServiceTimeChangeSignaled = 411, /// Task Scheduler service failed to launch tasks triggered by computer startup. Restart the Task Scheduler service. /// For detailed information, see the documentation for Event ID 412 on TechNet. ScheduleServiceRunBootJobsFailed = 412, /// Task Scheduler service started Task Compatibility module. /// For detailed information, see the documentation for Event ID 700 on TechNet. CompatStart = 700, /// Task Scheduler service failed to start Task Compatibility module. Tasks may not be able to register on previous Window versions. /// For detailed information, see the documentation for Event ID 701 on TechNet. CompatStartFailed = 701, /// Task Scheduler failed to initialize the RPC server for starting the Task Compatibility module. Tasks may not be able to register on previous Window versions. /// For detailed information, see the documentation for Event ID 702 on TechNet. CompatStartRpcFailed = 702, /// Task Scheduler failed to initialize Net Schedule API for starting the Task Compatibility module. Tasks may not be able to register on previous Window versions. /// For detailed information, see the documentation for Event ID 703 on TechNet. CompatStartNetscheduleFailed = 703, /// Task Scheduler failed to initialize LSA for starting the Task Compatibility module. Tasks may not be able to register on previous Window versions. /// For detailed information, see the documentation for Event ID 704 on TechNet. CompatStartLsaFailed = 704, /// Task Scheduler failed to start directory monitoring for the Task Compatibility module. /// For detailed information, see the documentation for Event ID 705 on TechNet. CompatDirectoryMonitorFailed = 705, /// Task Compatibility module failed to update a task to the required status. /// For detailed information, see the documentation for Event ID 706 on TechNet. CompatTaskStatusUpdateFailed = 706, /// Task Compatibility module failed to delete a task. /// For detailed information, see the documentation for Event ID 707 on TechNet. CompatTaskDeleteFailed = 707, /// Task Compatibility module failed to set a security descriptor for a task. /// For detailed information, see the documentation for Event ID 708 on TechNet. CompatTaskSetSdFailed = 708, /// Task Compatibility module failed to update a task. /// For detailed information, see the documentation for Event ID 709 on TechNet. CompatTaskUpdateFailed = 709, /// Task Compatibility module failed to upgrade existing tasks. Upgrade will be attempted again next time 'Task Scheduler' service starts. /// For detailed information, see the documentation for Event ID 710 on TechNet. CompatUpgradeStartFailed = 710, /// Task Compatibility module failed to upgrade NetSchedule account. /// For detailed information, see the documentation for Event ID 711 on TechNet. CompatUpgradeNsAccountFailed = 711, /// Task Compatibility module failed to read existing store to upgrade tasks. /// For detailed information, see the documentation for Event ID 712 on TechNet. CompatUpgradeStoreEnumFailed = 712, /// Task Compatibility module failed to load a task for upgrade. /// For detailed information, see the documentation for Event ID 713 on TechNet. CompatUpgradeTaskLoadFailed = 713, /// Task Compatibility module failed to register a task for upgrade. /// For detailed information, see the documentation for Event ID 714 on TechNet. CompatUpgradeTaskRegistrationFailed = 714, /// Task Compatibility module failed to delete LSA store for upgrade. /// For detailed information, see the documentation for Event ID 715 on TechNet. CompatUpgradeLsaCleanupFailed = 715, /// Task Compatibility module failed to upgrade existing scheduled tasks. /// For detailed information, see the documentation for Event ID 716 on TechNet. CompatUpgradeFailed = 716, /// Task Compatibility module failed to determine if upgrade is needed. /// For detailed information, see the documentation for Event ID 717 on TechNet. CompatUpgradeNeedNotDetermined = 717, /// Task scheduler was unable to upgrade the credential store from the Beta 2 version. You may need to re-register any tasks that require passwords. /// For detailed information, see the documentation for Event ID 718 on TechNet. VistaBeta2CredstoreUpgradeFailed = 718, /// A unknown value. Unknown = -2 } /// /// Historical event information for a task. This class wraps and extends the class. /// /// /// For events on systems prior to Windows Vista, this class will only have information for the TaskPath, TimeCreated and EventId properties. /// [PublicAPI] public sealed class TaskEvent : IComparable { internal TaskEvent([NotNull] EventRecord rec) { EventId = rec.Id; EventRecord = rec; Version = rec.Version; TaskCategory = rec.TaskDisplayName; OpCode = rec.OpcodeDisplayName; TimeCreated = rec.TimeCreated; RecordId = rec.RecordId; ActivityId = rec.ActivityId; Level = rec.LevelDisplayName; UserId = rec.UserId; ProcessId = rec.ProcessId; TaskPath = rec.Properties.Count > 0 ? rec.Properties[0]?.Value?.ToString() : null; DataValues = new EventDataValues(rec as EventLogRecord); } internal TaskEvent([NotNull] string taskPath, StandardTaskEventId id, DateTime time) { EventId = (int)id; TaskPath = taskPath; TimeCreated = time; } /// /// Gets the activity id. This value is null for V1 events. /// public Guid? ActivityId { get; internal set; } /// /// An indexer that gets the value of each of the data item values. This value is null for V1 events. /// /// /// The data values. /// public EventDataValues DataValues { get; } /// /// Gets the event id. /// public int EventId { get; internal set; } /// /// Gets the underlying . This value is null for V1 events. /// public EventRecord EventRecord { get; internal set; } /// /// Gets the from the . /// /// /// The . If not found, returns . /// public StandardTaskEventId StandardEventId { get { if (Enum.IsDefined(typeof(StandardTaskEventId), EventId)) return (StandardTaskEventId)EventId; return StandardTaskEventId.Unknown; } } /// /// Gets the level. This value is null for V1 events. /// public string Level { get; internal set; } /// /// Gets the op code. This value is null for V1 events. /// public string OpCode { get; internal set; } /// /// Gets the process id. This value is null for V1 events. /// public int? ProcessId { get; internal set; } /// /// Gets the record id. This value is null for V1 events. /// public long? RecordId { get; internal set; } /// /// Gets the task category. This value is null for V1 events. /// 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. This value is null for V1 events. /// public System.Security.Principal.SecurityIdentifier UserId { get; internal set; } /// /// Gets the version. This value is null for V1 events. /// public byte? Version { get; internal set; } /// /// Gets the data value from the task specific event data item list. /// /// The name of the data element. /// Contents of the requested data element if found. null if no value found. [Obsolete("Use the DataVales property instead.")] public string GetDataValue(string name) => DataValues?[name]; /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// public override string ToString() => EventRecord?.FormatDescription() ?? TaskPath; /// /// 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 = string.Compare(TaskPath, other.TaskPath, StringComparison.Ordinal); if (i == 0 && EventRecord != null) { i = string.Compare(ActivityId.ToString(), other.ActivityId.ToString(), StringComparison.Ordinal); if (i == 0) i = Convert.ToInt32(RecordId - other.RecordId); } return i; } /// /// Get indexer class for data values. /// public class EventDataValues { private readonly EventLogRecord rec; internal EventDataValues(EventLogRecord eventRec) { rec = eventRec; } /// /// Gets the value of the specified property name. /// /// /// The value. /// /// Name of the property. /// Value of the specified property name. null if property does not exist. public string this[string propertyName] { get { var propsel = new EventLogPropertySelector(new[] {$"Event/EventData/Data[@Name='{propertyName}']"}); try { var logEventProps = rec.GetPropertyValues(propsel); return logEventProps[0].ToString(); } catch { } return null; } } } } /// /// An enumerator over a task's history of events. /// public sealed class TaskEventEnumerator : IEnumerator { private EventRecord curRec; private EventLogReader log; internal TaskEventEnumerator([NotNull] 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 => 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 => 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() => (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); } /// /// Seeks the specified bookmark. /// /// The bookmark. /// The offset. public void Seek(EventBookmark bookmark, long offset = 0L) { log.Seek(bookmark, offset); } /// /// Seeks the specified origin. /// /// The origin. /// The offset. public 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. /// /// Many applications have the need to audit the execution of the tasks they supply. To enable this, the library provides the TaskEventLog class that allows for TaskEvent instances to be enumerated. This can be done for single tasks or the entire system. It can also be filtered by specific events or criticality. /// public sealed class TaskEventLog : IEnumerable { private const string TSEventLogPath = "Microsoft-Windows-TaskScheduler/Operational"; private static readonly bool IsVistaOrLater = Environment.OSVersion.Version.Major >= 6; /// /// 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([CanBeNull] string taskPath) : this(".", taskPath) { Initialize(".", BuildQuery(taskPath), true); } /// /// 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([NotNull] string machineName, [CanBeNull] string taskPath, string domain = null, string user = null, string password = null) { Initialize(machineName, BuildQuery(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, 102, 103, 107, 108, 109, 111, 117, 118, 119, 120, 121, 122, 123, 124, 125 }; Initialize(machineName, BuildQuery(taskName, numArray, startTime), false, domain, user, password); } /// /// Initializes a new instance of the class. /// /// Name of the task. /// The event ids. /// The start time. /// Name of the machine (optional). /// The domain. /// The user. /// The password. public TaskEventLog(string taskName = null, int[] eventIDs = null, DateTime? startTime = null, string machineName = null, string domain = null, string user = null, string password = null) { Initialize(machineName, BuildQuery(taskName, eventIDs, startTime), true, domain, user, password); } /// /// Initializes a new instance of the class. /// /// Name of the task. /// The event ids. /// The levels. /// The start time. /// Name of the machine (optional). /// The domain. /// The user. /// The password. public TaskEventLog(string taskName = null, int[] eventIDs = null, int[] levels = null, DateTime? startTime = null, string machineName = null, string domain = null, string user = null, string password = null) { Initialize(machineName, BuildQuery(taskName, eventIDs, startTime, levels), true, domain, user, password); } internal static string BuildQuery(string taskName = null, int[] eventIDs = null, DateTime? startTime = null, int[] levels = null) { const string queryString = "" + " " + " " + " " + ""; const string OR = " or "; const string AND = " and "; System.Text.StringBuilder sb = new System.Text.StringBuilder("*"); if (eventIDs != null && eventIDs.Length > 0) { if (sb.Length > 1) sb.Append(AND); sb.AppendFormat("({0})", string.Join(OR, Array.ConvertAll(eventIDs, i => $"EventID={i}"))); } if (levels != null && levels.Length > 0) { if (sb.Length > 1) sb.Append(AND); sb.AppendFormat("({0})", string.Join(OR, Array.ConvertAll(levels, i => $"Level={i}"))); } if (startTime.HasValue) { if (sb.Length > 1) sb.Append(AND); sb.AppendFormat("TimeCreated[@SystemTime>='{0}']", System.Xml.XmlConvert.ToString(startTime.Value, System.Xml.XmlDateTimeSerializationMode.RoundtripKind)); } if (sb.Length > 1) { sb.Insert(1, "[System[Provider[@Name='Microsoft-Windows-TaskScheduler'] and "); sb.Append(']'); } if (!string.IsNullOrEmpty(taskName)) { if (sb.Length == 1) sb.Append('['); else sb.Append("]" + AND + "*["); sb.AppendFormat("EventData[Data[@Name='TaskName']='{0}']", taskName); } if (sb.Length > 1) sb.Append(']'); return string.Format(queryString, sb); } private void Initialize(string machineName, string query, bool revDir, string domain = null, string user = null, string password = null) { if (!IsVistaOrLater) 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(); foreach (char c in password) spwd.AppendChar(c); } Query = new EventLogQuery(TSEventLogPath, PathType.LogName, query) { ReverseDirection = revDir }; if (machineName != null && machineName != "." && !machineName.Equals(Environment.MachineName, StringComparison.InvariantCultureIgnoreCase)) Query.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(Query)) { 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; } } } /// /// Gets or sets a value indicating whether this is enabled. /// /// /// true if enabled; otherwise, false. /// public bool Enabled { get { if (!IsVistaOrLater) return false; using (var cfg = new EventLogConfiguration(TSEventLogPath, Query.Session)) return cfg.IsEnabled; } set { if (!IsVistaOrLater) throw new NotSupportedException("Task history not available on systems prior to Windows Vista and Windows Server 2008."); using (var cfg = new EventLogConfiguration(TSEventLogPath, Query.Session)) { if (cfg.IsEnabled != value) { cfg.IsEnabled = value; cfg.SaveChanges(); } } } } /// /// Gets or sets a value indicating whether to enumerate in reverse when calling the default enumerator (typically with foreach statement). /// /// /// true if enumerates in reverse (newest to oldest) by default; otherwise, false to enumerate oldest to newest. /// [System.ComponentModel.DefaultValue(false)] public bool EnumerateInReverse { get; set; } /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can be used to iterate through the collection. /// IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(EnumerateInReverse); /// /// Returns an enumerator that iterates through the collection. /// /// if set to true reverse. /// /// A that can be used to iterate through the collection. /// [NotNull] public TaskEventEnumerator GetEnumerator(bool reverse) { Query.ReverseDirection = !reverse; return new TaskEventEnumerator(new EventLogReader(Query)); } /// /// 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() => GetEnumerator(false); internal EventLogQuery Query { get; private set; } } }