v26.7.23.1393
Pre-release
Pre-release
Immutable
release. Only release title and notes can be modified.
All changes since the last stable release (v26.7.10.1209).
Highlights
- Event timeline histogram — a toggleable timeline strip above the event table plots event volume over time and doubles as a navigator: WPA-style cursor-anchored zoom and pan, a Scope lens that drills the table into the visible time window (with undo), and Group by dimensions that split each bar into stacked bands — severity, source, event ID, task category, opcode, log, Logon Type, Ticket Encryption Type, process image, and an update/servicing Error Code dimension with curated HRESULT labels. In-view Find (Ctrl+F) matches show as markers along the top. It's hidden by default, update scenarios turn it on, and your choice is remembered. See Event Timeline Histogram below.
- Channel readiness & in-app channel enablement — scenarios and the live-logs menu now show each channel's real state — present, enabled, or access-denied (detected via a native Win32 channel-access probe) — so a scenario that needs an unreadable channel is flagged instead of failing on launch. When EventLogExpert is already running elevated, a required-but-disabled channel gets an Enable channel button that turns it on in place; non-elevated users get an honest "restart as administrator" hint. See Channel Readiness below.
- Find in the current view with Ctrl+F — an incremental, in-view Find bar searches the events you're already looking at and highlights matches as you type, with an inline match count, prev/next navigation (buttons, Enter / Shift+Enter, F3 / Shift+F3, with wrap-around), and Match case / Match whole word options. It searches the visible columns plus the always-on
Description, scrolls the current match into view, and in grouped mode expands a collapsed group to reveal a hidden match (then re-collapses it once you move on). See Find in View below. - Details Pane reader view — the Details Pane gains a Details | XML tab strip. The Details tab decodes an event's structured Event Data / User Data into named fields (arrays one per line, a hex preview for binary, muted placeholders for empty values), adds inline explanations for common values (a Logon Type decoder and a small curated Security-Auditing glossary), and offers per-field, per-section, and whole-event copy. The pane was re-laid-out into a metadata rail — identity, Level severity, and a correlation block — beside the message and data payload, and its header and tab bar were merged into a single row. See Details Pane below.
- Severity shown by shape, not just color — every level now has a distinct icon shared by the event table and the Details Pane (Critical = filled octagon, Error = circle, Warning = triangle, Information = info-circle, Verbose = hollow circle), so severity stays legible for color-vision differences and in Windows high-contrast / forced-colors mode. See Details Pane below.
- Filter lenses — transient, reversible narrowing — a new lens stack layers temporary narrowing on top of your filters without touching the saved filter or exports. From an event's right-click menu: Show Related by Activity ID, Show Events Sharing Related Activity ID, Show Parent Activity, and Show Events Near This Time (a centered ±30s … ±1h window). Active lenses appear as removable breadcrumb chips above the table, Esc pops the top lens, and a lens clears itself automatically when you close the log it came from. See Filter Lenses below.
- Launch a scenario against a folder of exported logs — point a scenario at a folder of exported
.evtxfiles and it opens the files whose channels the scenario targets, matched by channel name — so a curated triage scenario works against logs collected from another machine, not just the channels present on the local host. See Scenarios below. - Opcode and Related Activity ID event fields — events now expose their Opcode (resolved to its name, matching Event Viewer's precedence) and Related Activity ID. Both show in the reader view and are available as filter properties with value suggestions in the Basic filter editor. See Opcode & Related Activity ID below.
- Multi-value filtering (any-of / none-of) — Basic filter rows gain operator-aware multi-select matching, so one row can match any of several values or exclude all of them, including on named Event Data and User Data fields via Contains-Any. Empty values are handled safely so a stray blank can't quietly turn a filter into a match-all, and several built-in scenarios were refactored onto these collapsed multi-value rows. See Multi-Value Filtering below.
- Redesigned status bar — the status bar was rebuilt into a structured left / right layout: the active source and thousands-separated counts ("1,234 events", "200 of 1,234 shown" when narrowed, "3 selected" for a multi-select) plus a read-only Filtered indicator on the left; transient loading / failed / live-channel / resolver activity on the right. It also fixes a screen-reader defect where the entire bar re-announced on every count tick. See Status Bar below.
- Sharper threat-hunting and update-triage scenarios — the built-in LOLBin and encoded-PowerShell scenarios were moved off brittle
Description-text matching onto precise Event Data fields (NewProcessName,CommandLine), and the Windows Update / servicing triage scenarios were fixed and extended (servicing outcomes, reboot/crash correlation). See Scenarios below.
Features
- An event timeline histogram above the table (View → Timeline) with cursor-anchored zoom, pan, a Scope drill-down lens, undo, and Group by dimensions — see Event Timeline Histogram below.
- Group the timeline by severity, source, event ID, task category, opcode, log, Logon Type, Ticket Encryption Type, process image, or update/servicing Error Code (labeled with the hex HRESULT plus a curated CBS/WU symbol when known).
- Channel readiness in the scenario detail view, the empty-state dashboard, and the live-logs menu — per-channel present / enabled / access-denied status tags, with an inline "requires elevation" hint on denied live channels — see Channel Readiness below.
- Enable a disabled channel in place from the scenario dashboard when running elevated, with a confirmation that the change is persistent and machine-wide — see Channel Readiness below.
- In-view Find (Ctrl+F) in the event table, with incremental highlighting, match count, wrap-around prev/next, and Match case / Match whole word toggles — see Find in View below.
- A Details | XML tab strip in the Details Pane; the Details tab decodes named Event Data / User Data fields, previews binary as hex, and explains common values (Logon Type, a Security-Auditing glossary) — see Details Pane below.
- Per-field, per-section, and whole-event copy from the Details Pane reader view.
- Distinct severity shape icons shared by the event table and the Details Pane (Critical / Error / Warning / Information / Verbose), so the two can't drift — see Details Pane below.
- The Details Pane header and tab bar merged into one row (the reader tab is now labeled Details), reclaiming a row of vertical space — see Details Pane below.
- A reversible filter lens stack driven from the event context menu: Show Related by Activity ID, Show Events Sharing Related Activity ID, Show Parent Activity, and Show Events Near This Time — see Filter Lenses below.
- A lens breadcrumb above the event table with per-lens remove chips, a Clear all action, and scoped Esc-to-pop. Time-range lens chips include the date when the window spans more than one day.
- Launch a scenario from a folder of exported
.evtxfiles, matching each file's channel to the scenario — see Scenarios below. - Opcode and Related Activity ID event fields, resolved and filterable, with value suggestions in the Basic filter editor — see Opcode & Related Activity ID below.
- Operator-aware multi-select filtering (contains-any / none-of) on scalar, Event Data, and User Data fields, with a round-trip-stable Advanced-text form — see Multi-Value Filtering below.
- A structured status bar with a left/right split, thousands-separated counts, a read-only Filtered indicator, and a fixed screen-reader announcement model — see Status Bar below.
- Built-in threat-hunting and update-triage scenarios refined onto precise Event Data fields, plus a new proxied-execution LOLBin scenario — see Scenarios below.
- A single log's table defaults to Date/Time order while the timeline is shown and Record ID order while it's hidden.
- Automatic WinGet publishing — stable releases now publish to the Windows Package Manager automatically (via
wingetcreate), sowingetpicks up new versions; the single multi-architecture.msixbundlecovers both x64 and Arm64.
Event Timeline Histogram
- A timeline histogram strip sits above the event table and plots event volume over time for the loaded view. It's hidden by default, update scenarios turn it on (and auto-select a relevant Group by dimension), and you can toggle it yourself from View → Timeline — your last choice is remembered across launches.
- WPA-style navigation — cursor-anchored wheel zoom, shift-wheel or scrollbar pan,
+/−/ Fit toolbar buttons, and keyboard arrows /+/−/ Home. The default view fits the whole event span; zooming narrows the window, reveals a thin scrollbar that matches the app, and pins the window, while live-tail re-anchors to the latest events. - Scope lens (drill-down) — the Scope button (or Enter while the timeline is focused) narrows the log table to the visible time window through the same filter-lens stack as the other lenses; double-click resets. Zoom is visual navigation only; Scope is the explicit filter action, kept visually distinct. An Undo button (and right-click) walks back through the zoom-window history.
- Group by a dimension to split each bar into stacked bands: severity (Error / Warning / Normal), source, event ID, task category, opcode, log, Logon Type, Ticket Encryption Type, process image, or Error Code. Bands use the log-table highlight palette (softened to pastels), a forced-colors hatch fallback, and clickable legend toggles, with an overflow Other bucket for the long tail beyond the top categories.
- Error Code groups update and servicing failures by their HRESULT — reading
Microsoft-Windows-WindowsUpdateClienterrorCode(including high-bitwin:HexInt32codes such as0x800F0823that sign-extend to a negativeInt32) andMicrosoft-Windows-Servicingcodes from both EventData and theCbsPackageChangeState/ErrorCode/CbsUpdateChangeState/ErrorCodeUserData paths. Each band is labeled with the 8-digit hex plus a curated CBS/WU symbol when known (for example0x800F081F CBS_E_SOURCE_MISSING), and the same curated label now also appears in the Details Pane field explanation. - Find-hit markers — while in-view Find (Ctrl+F) is active, its matches are drawn as triangles along the top of the timeline.
- Timeline-aware sort — with a single log open and no explicit column sort, the table follows Date/Time order while the timeline is shown (so it reads in the same direction as the time axis) and Record ID order while it's hidden. Combined views and explicit user sorts are unchanged.
- Accessibility — the timeline is a focusable region whose label summarizes the whole loaded view (total events, time range, group breakdown); pan and zoom update a debounced live status with the current window's count, range, and breakdown, and keyboard bin-cursor navigation announces the focused bin — including a "spike" cue for a statistically anomalous bar, which preserves the meaning of the removed colored spike outline. Zoom depth is capped to the browser's layout limit and Escape is advertised.
Find in View
- Ctrl+F opens a floating Find bar over the current event view; Esc closes it, restores grid focus, and lands the cursor on the current match. Find is a read-only overlay — it never dispatches a filter, lens, sort, or selection change, it only reads the view to derive matches.
- Incremental, debounced search as you type, across the enabled columns plus the always-on
Descriptionof the current view. - The match count shows inline as
N/M, with prev / next navigation from the bar buttons, Enter / Shift+Enter, and F3 / Shift+F3 — all wrap around, with a screen-reader announcement on wrap. - Match case and Match whole word toggles in an options tray. Whole-word uses VS Code's word-boundary rule, so it stays correct for Event IDs, GUIDs, and hyphenated provider names, and queries with punctuation edges (
.NET,-Auditing) remain findable. - The current match's cells get highlighter-yellow inline marks; every matching row gets a neutral inset ring (weight-encoded — 2px on the current row, 1px on the others), with a forced-colors / high-contrast outline fallback.
- Group-aware navigation — Find expands a collapsed group to reveal a match and re-collapses the groups it opened once you navigate away, relinquishing ownership when you bulk- or context-toggle groups yourself.
- Match marks are rendered XSS-safe (Blazor-escaped segments, never raw markup) and capped per cell against a pathological hit count. Global Ctrl+F routes through a singleton coordinator to the currently mounted pane, so it stays correct across WebView reloads.
Details Pane
- A Details | XML tab strip replaces the single XML view. The Details tab (formerly "Reader") decodes an event's structured Event Data and User Data into named fields, renders arrays one value per line, previews binary values as hex, and shows muted placeholders for empty or null fields.
- Inline explanations annotate common values: a Logon Type decoder and a small, curated Security-Auditing glossary explain what a value means without leaving the pane.
- Copy at every level — per field, per section, and the whole event.
- The pane was redesigned into a two-region layout: a metadata rail (event identity, Level severity, a correlation block, and a collapsible System section) beside a payload region (the provider Message, a multi-column Event Data grid, and User Data). It collapses to a single column when the pane is narrow, uses uniform two-size typography, stacks field rows so long field names never truncate, and packs Event Data into at most three columns.
- The header bar and the Details / XML tab bar were merged into one row, reclaiming a row of vertical space; when the pane is collapsed it shows a small "Details" label and caret so it stays identifiable.
- Severity by shape, not just color — every level has a distinct icon shared by the event table and the Details Pane: Critical = filled octagon, Error = circle, Warning = triangle, Information = info-circle, Verbose = hollow circle (Critical and Verbose previously had no icon at all). A single shared
SeverityIconmap drives both surfaces, so the table and pane can't drift, and the icons stay legible on selected / highlighted rows and in forced-colors mode. - Correlation buttons — Show related events and Show parent activity — reuse the same filter-lens commands the row context menu drives (see Filter Lenses).
- The pane stays closed until you click an event, restoring the earlier committed behaviour.
Filter Lenses
- A filter lens is a transient, reversible narrowing layer applied on top of your persistent filter. Lenses live only in derived state — they never mutate your saved filters, the filter pane, or exports — so you can zoom in, look around, and pop back out cleanly.
- Show Related by Activity ID narrows the view to events that share the clicked event's Activity ID. Events with no Activity ID are correctly hidden rather than leaked.
- Show Events Sharing Related Activity ID narrows to events that share this event's Related Activity ID (siblings of the same parent/correlation activity).
- Show Parent Activity jumps to the parent activity's events — those whose Activity ID equals this event's Related Activity ID — with a distinct "Parent Activity = {guid}" chip.
- Show Events Near This Time is a context-menu submenu offering five centered windows — ±30s, ±1m, ±5m, ±15m, ±1h — that narrow the table to
[TimeCreated − d, TimeCreated + d]with inclusive bounds, so the clicked event always stays in view. The chip reads, for example,Near 2:03:22 PM ±5m; window math is done in UTC while the chip anchor renders in the grid's display timezone. (Day-scale browsing remains the persistent date range's job.) - Active lenses show as breadcrumb chips above the event table, each with its own remove control, plus a Clear all action and scoped Esc-to-pop. A time-range chip includes the date when its window spans more than one day, so a multi-day scope reads unambiguously.
- Lifecycle — a lens auto-clears when you close the log it originated from (tab close or close-all); ordinary filter-driven reloads never clear it. The "Show..." (transient lens) verb is kept deliberately distinct from the persistent "Exclude Events Before/After" items so the two don't get confused.
Opcode & Related Activity ID
- Two Windows event fields now flow all the way through the reader, resolver, and columnar store to the resolved event: Opcode (its name) and Related Activity ID (a GUID), each preserving the null-vs-present distinction through columnar rehydration.
- Opcode is resolved to its display name using the provider's opcode table first, then the standard WinMeta opcodes, then a numeric placeholder — matching Event Viewer's precedence.
- Both are filterable (as the Opcode and Related Activity ID properties) with value suggestions in the Basic filter editor, and both appear in the Details Pane reader view.
Multi-Value Filtering
- Basic filter rows gain operator-aware multi-select matching: one row can match any of a set of values (contains-any) or exclude all of them (none-of). Support is gated per field, so a property only offers the operators it can meaningfully use.
- Multi-select works on scalar fields and on named Event Data / User Data fields via Contains-Any, and the built-in scenario catalog was refactored to use these collapsed Contains-Any rows instead of many single-value rows.
- The filters round-trip cleanly through the Advanced-text form, so a multi-value row survives edit, save, and re-open unchanged.
- Empty values are handled safely. Null or empty needles are stripped from Contains / NotContains comparisons (an empty needle would otherwise match every event), a filter whose values are all empty can't be saved, and the empty value is excluded from GUID-valued multi-select filters.
- Importing a filter that contains empty-value multi-Contains comparisons now prompts Normalize / Import as-is / Cancel instead of silently importing a match-all filter, with clearer warning and removal-message wording and a de-duplicated filter-set name in the removal report.
Status Bar
- The status bar was rebuilt into a structured left / right layout:
- Left (persistent, silent): the active source (channel name, file base name, "All logs (N)", or group name), the counts ("1,234 events", or "200 of 1,234 shown" when narrowed, plus "3 selected" for a multi-select), and a read-only Filtered indicator whose tooltip names the mechanism ("Filter active" / "N lenses" / "Filter + N lenses").
- Right (transient): loading, failed, live-channel, and resolver activity.
- Lens-aware counts — the "shown" gate reads the composed applied filter (base intersected with lenses), so a lens-only narrowing correctly reports "M of N shown", while the tooltip still distinguishes the persistent filter.
- Accessibility fix — the old bar was a single live region that re-announced its entire contents on every count tick. Now the root region is silent (counts and source update without announcing), a single visually-hidden
role="status"region carries only a coarse, transition-only label (loading / load error / buffer full / continuously updating), the unthrottled "New Events: N" counter isaria-live="off", and a load error takes priority over "Loading" so a failure is announced even while another log is still loading.
Scenarios
- Launch from a folder of exported logs — a scenario can now open a folder of exported
.evtxfiles, matching each file's channel to the scenario and opening the matches in a fresh filtered view. This works for channels that aren't present on the local host (for example, logs collected from another machine). The folder scan runs off the UI thread and is fully cancellable. - The built-in LOLBin and encoded-PowerShell threat scenarios were retired from brittle
Description-text matching in favor of precise Event Data-field scenarios that match onNewProcessNameandCommandLine. - A new proxied-execution LOLBin scenario matches on
CommandLine, and encoded-PowerShell coverage now includes the-encabbreviation. - Update-triage scenarios fixed and extended — the servicing-outcomes view now keys on the real Servicing events (which log at Information, so the prior
Level=Errorfilter matched nothing), and the reboot/crash correlation view was corrected and extended. Update scenarios also turn the timeline on and pre-select a relevant Group by dimension. - Softer highlight colors — scenario row-highlight colors were retuned to a pastel palette (also used by the timeline's grouped bands) so multi-filter color-coding is easier on the eyes.
- Scenario comparisons that would resolve to no values are now rejected rather than applied as an empty (match-all) comparison.
Channel Readiness
- For every channel a scenario references, the app now determines presence, enablement, and accessibility — including access-denied detection via a native Win32 channel-access probe — and surfaces that state wherever you launch logs.
- Status tags appear in the scenario detail view, the empty-state dashboard, and the live-logs menu. A scenario with any required channel that's degraded (access-denied, not present, or failed) is treated as non-launchable, the same as a missing log.
- Access-denied live channels stay clickable in the menu and, when you pick one, surface an inline "Log requires elevation" alert that points you to relaunch as administrator (there is no in-app elevation or relaunch-as-admin path).
- Enable a disabled channel in place — when EventLogExpert is already running elevated, a required-but-disabled channel gets an Enable channel button that turns it on through the native channel-config write path (
EvtOpenChannelConfig→ setEnabled→EvtSaveChannelConfig), without an elevated helper, IPC, or relaunch. Non-elevated users instead get an honest hint to restart as administrator. - Safety — the enable action is fail-closed (a failed or non-Boolean read is never treated as "disabled"), the Application / System / Security channels are excluded (Windows forbids toggling their Enabled), and a confirmation names the channel and warns that the change is persistent and machine-wide (and, for analytic/debug channels, that records may be cleared). After a successful enable, the full channel-readiness set is re-fetched rather than a single-channel reprobe.
Reliability
- Fixed an unsafe-publication data race in the columnar event store's
EventColumnViewkey index. The lazily-built lookup is now published with aVolatile.Read+Interlocked.CompareExchange(matching the store's other caches) instead of a bare??=, so a concurrent reader on a weak-memory CPU (Arm64) can't observe the reference before the dictionary's writes are visible. The build is idempotent, so a benign build-race is harmless. Added direct sort-kernel tie-break regression tests alongside the fix. - Dependency and security updates — mitigated CVE-2026-54570 (AngleSharp mutation-XSS, pulled in transitively through the bUnit test dependency) and refreshed the existing CVE-2025-6965 SQLite override, alongside the NSubstitute 6.0 test-framework upgrade and routine framework/package bumps; the solution reports no vulnerable packages.
- Saves are written atomically — the file-save path now writes to a temporary file in the destination folder and commits with an atomic move, rather than an in-place replace with documented partial-failure states, so an interrupted save can't leave a truncated file or delete the original.
- Background I/O across the app now shares a single parallelism limit, and import classification runs in a single pass over the entries.
Bug Fixes
- File and folder pickers work when running elevated — File → Open, File → Open Folder, and every Save previously failed with a
COMException (0x80004005)when EventLogExpert ran elevated, because the WinRT picker's broker path is unavailable to elevated callers. Every picker now routes through the procedural Win32 dialogs, so open, open-folder, and save work for standard-user, unpackaged-elevated, and MSIX-packaged-elevated processes alike. - Live-tail "Load New Events" now renders the new row immediately — clicking View → Load New Events (with continuous updates off) cleared the "New Events" count but didn't show the new row until a full reload. The display view is now rebuilt after the new events are ingested, so the row appears at once; this also removes a one-event lag on the continuous-update live-tail path.
- The modal prompt now preserves the value you typed when you take the dialog's secondary action, instead of discarding it.
- An empty value in a multi-select filter can no longer turn the filter into an unintended match-all — empty needles are normalized out, all-empty filters can't be saved, and empty-value imports prompt before applying.
- The empty-value import removal report no longer lists a filter-set name more than once.