USB and device history from Amcache: InventoryDeviceContainer and InventoryDevicePnp

Beyond PE binaries, Amcache's modern schema records every device Windows enumerated. Two sub-keys matter for this: Root\InventoryDeviceContainer and Root\InventoryDevicePnp. Together they give analysts one of the cleanest answers to "what hardware has ever touched this machine?" that Windows offers.

This page is the practical guide to USB and peripheral investigations using Amcache. What each key records, how to read them together, and the limits.

For the broader artefact reference, see the Amcache complete reference. For the surrounding schema, see Amcache registry structure.

Amcache vs the traditional sources#

Historically, USB device history on Windows came from:

  • HKLM\SYSTEM\CurrentControlSet\Enum\USB. Every USB device Windows enumerated.
  • HKLM\SYSTEM\CurrentControlSet\Enum\USBSTOR. USB mass-storage specifically.
  • setupapi.dev.log (C:\Windows\INF\setupapi.dev.log). Driver install log with timestamps.
  • Per-user NTUSER.DAT for mount-point history.

Those remain authoritative for USB mass storage in particular. Amcache adds a parallel view that is often faster to parse and richer in friendly names:

Source Best for
Enum\USB / USBSTOR (registry hives) Authoritative device history, especially mass storage.
setupapi.dev.log Driver-install timestamps for first connect.
NTUSER.DAT mount points Per-user mount and last-connect data.
Amcache InventoryDeviceContainer Friendly names, vendor / model, paired/connected state.
Amcache InventoryDevicePnp PnP enumeration per interface.

In a triage context, Amcache is faster. One hive parse and you have a tabular view of every device with friendly names. For evidence, you want all the sources, not just Amcache.

InventoryDeviceContainer#

The user-facing view. One sub-key per "device container" Windows tracks. A logical device, not a low-level interface. Each entry has:

Field Meaning
FriendlyName Display name Windows assigns: "Brother HL-L2350DW", "SanDisk Cruzer Glide", "Logitech BRIO".
Manufacturer Vendor string.
ModelName Model identifier from the device.
ModelNumber Model number, if separate.
Categories Device categories: Printer, Storage, Display, Network, Bluetooth, MultimediaDevice, ...
DiscoveryMethod How Windows enumerated it: DeviceEnumeration, Manual, BluetoothPairing, ...
IsConnected 1 if connected at last inventory.
IsPaired 1 if paired (Bluetooth specifically).
IsActive 1 if Windows considers it currently active.
Icon Path to the device's icon resource.
KeyLastWriteTimestamp When the record was last updated. Closest thing to "last seen".

The cleanest "what hardware has been connected here?" table Windows exposes. Friendly names, categories, and a last-update timestamp per device, in one CSV after AmcacheParser.

InventoryDevicePnp#

The technical view. One sub-key per device interface the PnP manager enumerated. Where InventoryDeviceContainer lists "Brother HL-L2350DW" once, InventoryDevicePnp may list the printer's USB interface, its print interface, and any virtual interfaces it exposed.

Field Meaning
InstanceId PnP instance identifier, e.g. USB\VID_05E0&PID_1701\ABC123.
BusReportedDescription What the device told Windows it was.
DeviceClass Driver class GUID.
DeviceId PnP device ID.
Manufacturer Vendor string.
Model Model string.
Service Driver service.
DriverName Driver file backing the device.
KeyLastWriteTimestamp When the PnP record was last updated.

InstanceId is the join key between InventoryDeviceContainer and InventoryDevicePnp. Take an InstanceId from one and find the matching row in the other.

Reading the two together#

A clean pattern for "every device with friendly name, category, and PnP instance":

$containers = Import-Csv .\HOST_amcache_DeviceContainers.csv
$pnps    = Import-Csv .\HOST_amcache_DevicePnps.csv
 
$containers | ForEach-Object {
  $c = $_
  $pnp = $pnps | Where-Object { $_.InstanceId -eq $c.InstanceId } | Select-Object -First 1
  [pscustomobject]@{
    FriendlyName = $c.FriendlyName
    Categories  = $c.Categories
    Manufacturer = $c.Manufacturer
    InstanceId  = $c.InstanceId
    BusDesc   = $pnp.BusReportedDescription
    Service   = $pnp.Service
    IsConnected = $c.IsConnected
    LastSeen   = $c.KeyLastWriteTimestamp
  }
} | Sort-Object LastSeen -Descending

Per-device table that is dramatically easier to scan than raw Enum\USB exports.

USB mass-storage focus#

For the classic "did a USB drive connect on $DATE?" question, filter to storage categories:

Import-Csv .\HOST_amcache_DeviceContainers.csv |
 Where-Object {
  $_.Categories -match 'Storage|Disk|USB.*Mass'
 } |
 Select FriendlyName, ModelName, Manufacturer, IsConnected, KeyLastWriteTimestamp |
 Sort-Object KeyLastWriteTimestamp -Descending

For each surviving row, cross-reference with Enum\USBSTOR for the authoritative serial number and first/last-connect timestamps. Amcache gives you a fast triage view. USBSTOR gives you evidence-grade detail.

Investigative use cases#

Insider-threat data-exfiltration triage#

You suspect an employee copied data to a USB drive before resigning. The Amcache device list gives a chronological view of every storage device the host has seen, typically over many months.

Pattern:

  1. From DeviceContainers.csv, filter to storage categories.
  2. Sort by KeyLastWriteTimestamp descending.
  3. Identify any device whose last-seen time falls in the suspicion window.
  4. Pivot to USBSTOR for the serial number, then to NTUSER.DAT mount-point history for that serial to confirm the user account that mounted it.
  5. Cross-reference with filesystem access timestamps for files of interest in the same window. Add recycle bin, browser history, and LNK files for completeness.

Unauthorised peripheral connection#

For environments where peripherals are policy-restricted (printers, audio devices, networked storage), Amcache's InventoryDeviceContainer is a quick scan for non-compliant devices:

Import-Csv .\HOST_amcache_DeviceContainers.csv |
 Where-Object {
  $_.Manufacturer -notmatch '^(YourCompany|YourApprovedVendor)' -and
  $_.Categories  -match 'Printer|Display'
 } |
 Select FriendlyName, Manufacturer, Categories, KeyLastWriteTimestamp

Tune the allowlist to your environment.

Bluetooth pairing history#

DiscoveryMethod = BluetoothPairing rows show every device paired over Bluetooth with friendly names. Useful for "did the user pair their phone / personal headset / personal keyboard?" questions in regulated environments.

Identifying counterfeit or unknown devices#

A row in DevicePnps.csv with generic BusReportedDescription ("USB Device", "Unknown Device") and blank Manufacturer, paired with a DeviceContainers.csv row that has no FriendlyName, is often a malicious or counterfeit HID device. BadUSB pen-test tools, unbranded keyboard emulators, malicious data cables.

Limits and caveats#

KeyLastWriteTimestamp is not "first connect"#

It is "last update". For a device that connects regularly you see recent timestamps. For a device that connected once a year ago you see the year-old timestamp. For first-connect timestamps, parse setupapi.dev.log.

Not every device leaves an Amcache entry#

Devices that connect and immediately disconnect between appraiser runs may never be inventoried. For short-window USB investigations (seconds to minutes), setupapi.dev.log and USBSTOR are more reliable.

Friendly names are vendor-controlled#

FriendlyName is whatever the device tells Windows it is. A malicious USB can claim to be "Microsoft Wireless Mouse" and Windows displays that. Pair with BusReportedDescription and physical inspection.

Some categories are noisy#

InventoryDeviceContainer records virtual devices, software audio endpoints, and platform-internal devices alongside real peripherals. Filter on Categories and on whether IsPaired or Manufacturer is set to cut the noise.

Further reading#

Related posts

Back to all posts