Registry Parser
All articles

FeatureUsage taskbar telemetry: the RegRipper featureusage plugin

8 min read

FeatureUsage is one of the quieter wins in modern Windows DFIR. It is a set of taskbar-interaction counters that Windows 10 1903 and later keep in the user's NTUSER.DAT, and the RegRipper featureusage plugin pulls them out as flat key-value pairs. It will not tell you when something ran, but it will tell you that a specific user clicked, switched to, or launched a specific application from the taskbar, and roughly how often. On a machine where UserAssist has been thinned out and Prefetch is disabled, FeatureUsage is sometimes the artifact still standing.

Where it lives

The data sits under the user's NTUSER.DAT at:

HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FeatureUsage

Under that root, Windows maintains a handful of subkeys, each counting a different kind of taskbar interaction:

  • AppLaunch: an app was launched from the taskbar.
  • AppBadgeUpdated: a taskbar badge (notification overlay) was updated for an app.
  • AppSwitched: focus switched to an app via its taskbar button.
  • ShowJumpView: the app's jump list was opened (right-click on a taskbar button).
  • TrayButtonClicked: a system tray / notification-area button was clicked.

The exact set of subkeys present varies by build, and not every subkey exists on every hive — they are created lazily as the behaviours occur. If a user never opened a jump list, there is no ShowJumpView key.

In each of these subkeys, the layout is the same: every value name is an application identity and every value data is an integer counter. The name is generally the application's AppUserModelID (AppID) for store and shell-integrated apps, and a file path for ordinary desktop executables. So a value might be Microsoft.WindowsTerminal_8wekyb3d8bbwe!App with data 9, or C:\Program Files\Mozilla Firefox\firefox.exe with data 41. The counter is a cumulative tally of how many times that interaction happened for that AppID.

What the plugin actually reads

A point worth being precise about, because it shapes what you can claim. The implementation behind this site's feature_usage plugin reads exactly one subkey:

Software\Microsoft\Windows\CurrentVersion\Explorer\FeatureUsage\AppLaunch

It enumerates the values there and emits two columns, Application and Launches — the value name as the AppID/path and the value data rendered as the launch count. That is the highest-signal subkey for an execution timeline: a non-zero AppLaunch count is a direct statement that this user launched that application from the taskbar.

RegRipper's upstream featureusage.pl is broader: it walks the FeatureUsage root and reports the other subkeys as separate sections. If your investigation hinges on a switch-versus-launch distinction, read the additional subkeys directly. The mechanics are identical for all of them — name is the AppID, data is a counter — so a generic value dump over the whole FeatureUsage tree gives you everything.

What each counter actually proves

These are interaction counters, not a process-execution log, and the distinction matters when you write it up.

  • AppLaunch is the closest thing here to an execution record. It increments when the user starts the app from a taskbar button. A count of N means the taskbar launched that app N times for this user. This is genuine execution evidence with attribution baked in.
  • AppSwitched increments when the user clicks a taskbar button to bring an already-running app to the foreground. This proves the app was running and the user interacted with it, but the increment is not itself a launch. An app can have a high AppSwitched count and a low or zero AppLaunch count if it was started some other way (autostart, a launcher, the Start menu before pinning) and then repeatedly clicked.
  • ShowJumpView counts right-click jump-list opens. Evidence of intent and familiarity more than execution.
  • TrayButtonClicked counts notification-area clicks. Useful for background/tray-resident apps that may never appear under AppLaunch.
  • AppBadgeUpdated is the noisiest and least about user action — badge updates are driven by the app, not the click. Treat it as corroboration that an app was active, not as user behaviour.

The headline interpretation: a value in FeatureUsage proves taskbar-driven interaction with that application by the user who owns this hive. Like UserAssist, it lives in NTUSER.DAT, so attribution is unambiguous — the user is whoever owns the profile.

The thing it does not have: timestamps

FeatureUsage stores counters, full stop. There is no per-entry FILETIME, no last-interaction timestamp inside the value data. If you want recency, you read the LastWrite time of the subkey — for example the LastWrite on AppLaunch. That tells you when some value in that subkey last changed, which is the most recent taskbar launch of any app, not the most recent launch of a specific one.

So you can say "the most recent taskbar app launch on this profile was at the AppLaunch key's LastWrite," but you cannot, from FeatureUsage alone, say which app that final increment belonged to. Anyone telling you FeatureUsage gives per-app last-run times is reading it wrong, or has conflated it with another artifact. This is the same trap UserAssist sets in reverse: UserAssist has the per-entry timestamp and is often cleared; FeatureUsage survives clearing but has no per-entry time. They cover each other's blind spots.

Why it matters on modern systems

The reason to care is timing. FeatureUsage arrived in 1903 (2019) and is on by default. It is not in the usual list of artifacts that privacy tools and anti-forensics scripts wipe — those still target UserAssist, Recent, and the MRUs. Prefetch is frequently disabled on servers. AmCache and Shimcache are powerful but system-wide and weak on attribution. In that landscape FeatureUsage is a per-user execution-ish artifact that is both present and overlooked.

The per-user nature is the value. When you find firefox.exe with an AppLaunch count of 41 in jdoe's NTUSER.DAT, you are not guessing who used Firefox. Counts also give you a coarse intensity read: an app with a launch count of 1 is a different story from one with a count of 200. High counts are the user's daily drivers; a count of 1 or 2 on an unusual binary in a writable path is worth a pivot.

Pairing with UserAssist and BAM

FeatureUsage is a complement, never a replacement. The pairings that work:

  • With UserAssist. Both are per-user, both count launches, both live in NTUSER.DAT. UserAssist gives you the per-entry last-run FILETIME, run count, and focus time but covers Explorer/Start/Run launches and is a common cleanup target. FeatureUsage gives you taskbar-specific launches and switches and survives that cleanup but has no per-entry time. An app present in UserAssist and FeatureUsage is strongly corroborated. An app in FeatureUsage but missing from a suspiciously empty UserAssist is a flag that UserAssist was wiped — the surviving FeatureUsage counter is your witness.
  • With BAM/DAM. BAM (Background Activity Moderator) gives you a per-executable last-execution timestamp under a per-user SID, sourced from a SYSTEM hive. That is the timestamp FeatureUsage lacks. If FeatureUsage says "this user launched evil.exe from the taskbar some number of times" and BAM says "evil.exe last ran at 02:14 UTC for this SID," you have count plus time plus attribution across two independent hives. That correlation is hard to dismiss.

A clean three-way reconstruction: FeatureUsage AppLaunch confirms the user clicked it, UserAssist gives focus time and a last-run time, BAM cross-checks the last execution from a different hive. Three artifacts, two hives, one consistent story.

Tools

  • RegRipper's featureusage plugin (source). Walks the FeatureUsage subkeys and prints each as AppID-and-count. Read the source if you need to know which subkeys a given version enumerates.
  • Eric Zimmerman's Registry Explorer / RECmd, which will show the FeatureUsage subtree directly and let you read each subkey's LastWrite.
  • The parser on this site surfaces the AppLaunch counters in its execution view; you can analyze NTUSER.DAT in your browser without standing up a separate toolchain. For the full subkey breakdown, the broader RegRipper plugins reference covers where each one fits.

Whatever tool you use, surface the value data, not just the names — the count is half the evidence — and grab the subkey LastWrite separately, because that is the only timestamp FeatureUsage will ever give you.

Edge cases worth knowing

AppIDs are not always paths. Store apps and shell-integrated apps appear as AppUserModelIDs like Microsoft.WindowsTerminal_8wekyb3d8bbwe!App. You need to resolve those to a friendly name yourself; the registry does not do it for you. Do not assume a non-path value means "no real app."

Counts only go up in the live hive. FeatureUsage is monotonic and you see only the snapshot at acquisition time. If you have VSS snapshots, pull NTUSER.DAT from each and diff the counts — that turns a single number into a rough activity curve.

AppSwitched without AppLaunch is not "never ran." It means the app ran but was not started from the taskbar. Cross-check Prefetch, AmCache, or BAM before concluding anything about how a binary started. FeatureUsage tells you about taskbar behaviour, not about every code path that launched the process — the same discipline UserAssist demands.

FeatureUsage will not anchor a timeline on its own; it has no timestamps to anchor with. What it does is place a named application under a named user's taskbar, with a count, on a build of Windows where the louder artifacts may be missing or scrubbed. Pair it with UserAssist for focus and recency and with BAM for last-execution time, and the counters become a sturdy third leg.