public ColomaEvent( string branch, uint build, KBRevision mostRecentKb, string machineName, string deviceId, string userName, string logName, string level, long id, DateTime timeCreated, string source, string Message) { this.branch = branch; this.Build = build; this.MostRecentKb = mostRecentKb; this.machineName = machineName; this.deviceId = deviceId; this.userName = userName; this.Logname = logName; this.level = level; this.TimeCreated = timeCreated; this.source = source; this.message = Message; this.instanceid = id; }
private static Dictionary<string, KBRevision> QueryUpdates() { Dictionary<string, KBRevision> installedUpdates = new Dictionary<string, KBRevision>(); try { // TODO: Use a different WMI client that doesn't require WinRM CimSession cimSession = CimSession.Create("localhost"); IEnumerable<CimInstance> enumeratedInstances = cimSession.EnumerateInstances(@"root\cimv2", "Win32_QuickFixEngineering"); foreach (CimInstance cimInstance in enumeratedInstances) { DateTime date; if (!DateTime.TryParse(cimInstance.CimInstanceProperties["InstalledOn"].Value.ToString(), CultureInfo.CurrentCulture.DateTimeFormat, DateTimeStyles.AssumeUniversal, out date)) { long time; if (!long.TryParse("0x" + cimInstance.CimInstanceProperties["InstalledOn"].Value.ToString(), out time)) // This may only be needed for Win7... { continue; } date = DateTime.FromFileTimeUtc(time); } KBRevision rev = new KBRevision(); rev.Kb = cimInstance.CimInstanceProperties["HotFixID"].Value.ToString(); rev.InstallDate = date; installedUpdates[rev.Kb] = rev; } } catch (Exception) { // This probably means WinRM is not enabled. The MI .Net interface uses WinRM to communicate with WMI // The user would need to run "winrm quickconfig" to setup the winrm service and firewall exceptions } return installedUpdates; }
private static void AddLogToList(List<ColomaEvent> list, DateTime dt, Dictionary<string, KBRevision> installedUpdates) { // this retrieves the build.revision and branch for the current client WindowsVersion.WindowsVersionInfo wvi = new WindowsVersion.WindowsVersionInfo(); WindowsVersion.GetWindowsBuildandRevision(wvi); FirstBuild firstBuildEvent = new FirstBuild { index = 0, build = wvi.build }; KBRevision currentKb = new KBRevision(); uint currentBuild = wvi.build; Guid servicingProvider = new Guid("BD12F3B8-FC40-4A61-A307-B7A013A069C1"); string structuredQuery = string.Format(System.Globalization.CultureInfo.InvariantCulture, Coloma.structuredQueryTemplate, dt.ToUniversalTime()); EventLogQuery query = new EventLogQuery(null, PathType.LogName, structuredQuery); query.ReverseDirection = false; EventLogReader reader = new EventLogReader(query); // The Event Log can only return a maximum of 2 MB at a time, but it does not actually limit itself to this when collecting <BatchSize> events. // If the number of requested events exceeds 2 MB of event data an exception will be throw (System.Diagnostics.Eventing.Reader.EventLogException: The data area passed to a system call is too small). // Since an event is at most 64 KB, 30 events is a conservative limit to ensure the 2 MB limit is never crossed. // Setting a smaller batch size does have a small performance impact, but not enough to notice in this scenario. reader.BatchSize = 30; EventRecord entry; while ((entry = reader.ReadEvent()) != null) { var entryTimeCreated = entry.TimeCreated ?? DateTime.Now; var entryMachineName = entry.MachineName; var entryLogName = entry.LogName; var entryId = entry.Id; var entryProviderName = entry.ProviderName; string entryLevelDisplayName = ""; try { entryLevelDisplayName = entry.LevelDisplayName; } catch { if (entry.Level != null) entryLevelDisplayName = ((StandardEventLevel) entry.Level).ToString(); } string entryMessage = CleanUpMessage(entry.FormatDescription()); if (entryMessage == null && entry.Properties.Count > 0) { string entryProperties = String.Join(", ", entry.Properties.Select(p => String.Format("'{0}'", p.Value))); entryMessage = String.Format(Coloma.descNotFoundMsgTemplate, entryId, entryProviderName, entryProperties); } if (entryId == 2 && entry.ProviderId.HasValue && entry.ProviderId.Value == servicingProvider) { if (entry.Properties.Count == 5 && entry.Properties[2].Value.ToString() == "Installed") { string kb = entry.Properties[0].Value.ToString(); KBRevision KBRev; if(installedUpdates.TryGetValue(kb, out KBRev)) { // Update InstallDate with a more precise time KBRev.InstallDate = entryTimeCreated; KBRev.FoundInSetupLog = true; currentKb = KBRev; } else { currentKb = new KBRevision { InstallDate = entryTimeCreated, Kb = kb, FoundInSetupLog = true }; installedUpdates.Add(kb, new KBRevision(currentKb)); } } } else if (entryId == 6009 && entry.ProviderName == "EventLog") { if (firstBuildEvent.index == 0 && entry.Properties.Count == 5) { uint.TryParse(entry.Properties[1].Value.ToString(), out currentBuild); // If the boot event indicates an earlier build, remember it so we can set all the prior events to this build number if (firstBuildEvent.build != currentBuild) { firstBuildEvent.index = list.Count + 1; firstBuildEvent.build = currentBuild; } // Else the event indicates no build number change, so don't bother checking later boot events either else { firstBuildEvent.index = -1; } } // This event doesn't go into the log file continue; } list.Add(new ColomaEvent(wvi.branch, currentBuild, currentKb, entryMachineName, DeviceId, Environment.UserName, entryLogName, entryLevelDisplayName, entryId, entryTimeCreated, entryProviderName, entryMessage)); } IEnumerable<KBRevision> orderedUpdates = installedUpdates.Select(kb => kb.Value).OrderBy(kb => kb.InstallDate); IEnumerable<KBRevision> missingUpdates = orderedUpdates.Where(kb => !kb.FoundInSetupLog); IEnumerator<KBRevision> currentMissingEnum = missingUpdates.GetEnumerator(); currentMissingEnum.MoveNext(); IEnumerator<KBRevision> nextInstalled = orderedUpdates.GetEnumerator(); nextInstalled.MoveNext(); DateTime nextInstallTime = DateTime.Now; Action getNextInstallTime = new Action(() => { if (nextInstalled.Current != null && currentMissingEnum != null && currentMissingEnum.Current != null) { do { if (nextInstalled.Current.Kb == currentMissingEnum.Current.Kb) { if (nextInstalled.MoveNext()) { nextInstallTime = nextInstalled.Current.InstallDate; // Install times from WMI only include the date, so skip ahead to the next install that falls on a later date or has a more precise time from a setup event while (!nextInstalled.Current.FoundInSetupLog && nextInstallTime >= currentMissingEnum.Current.InstallDate && nextInstallTime < currentMissingEnum.Current.InstallDate.AddDays(1)) { if (nextInstalled.MoveNext()) { nextInstallTime = nextInstalled.Current.InstallDate; } else { nextInstallTime = DateTime.Now; break; } } } else { nextInstallTime = DateTime.Now; break; } break; } } while (nextInstalled.MoveNext()); } }); getNextInstallTime(); int fixupsRemaining = (firstBuildEvent.index > 0 ? 1 : 0) + (missingUpdates.Any() ? 1 : 0); foreach (var evt in list) { if (fixupsRemaining == 0) { break; } // If there was a EventLog 6009 event with a different build number, go back and set all the events before it to have that build number // This is highly unlikely to ever happen under the current OS-swap upgrade mechanism because the logs get cleared during each upgrade if (firstBuildEvent.index > 0) { firstBuildEvent.index--; if (firstBuildEvent.index <= 0) { fixupsRemaining--; } else { evt.Build = firstBuildEvent.build; } } // If there are installed KBs found via WMI that were not in the Setup log, go back and set all the events between the KB installation time // and the next KB installation time to use this KB number. if (currentMissingEnum != null && currentMissingEnum.Current != null) { if (evt.TimeCreated >= currentMissingEnum.Current.InstallDate && evt.TimeCreated < nextInstallTime) { evt.MostRecentKb = new KBRevision(currentMissingEnum.Current); // Since the installations times from WMI are only accurate to the day, append a * to the KB name for any events that fall on that day, to indicate uncertainty. if (evt.TimeCreated >= evt.MostRecentKb.InstallDate && evt.TimeCreated < evt.MostRecentKb.InstallDate.AddDays(1)) { evt.MostRecentKb.Kb += "*"; } } else if (evt.TimeCreated >= nextInstallTime) { if (currentMissingEnum.MoveNext()) { getNextInstallTime(); } else { currentMissingEnum = null; fixupsRemaining--; } } } } }
public KBRevision(KBRevision other) { this.Kb = other.Kb; this.InstallDate = other.InstallDate; this.FoundInSetupLog = other.FoundInSetupLog; }