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.DATfor 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 -DescendingPer-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 -DescendingFor 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:
- From
DeviceContainers.csv, filter to storage categories. - Sort by
KeyLastWriteTimestampdescending. - Identify any device whose last-seen time falls in the suspicion window.
- Pivot to
USBSTORfor the serial number, then toNTUSER.DATmount-point history for that serial to confirm the user account that mounted it. - 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, KeyLastWriteTimestampTune 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#
- Microsoft's PnP enumeration documentation.
- USBDeview and similar tools for
Enum\USBSTORparsing comparisons.
Related#
Related posts
- Volatility and Amcache: extracting the hive from memory images
When you only have a RAM dump, Volatility extracts the in-memory copy of Amcache.hve. Hand off to AmcacheParser. The cases where this is the only option.
- RegRipper amcache plugin: what it does and when to use it
RegRipper's amcache plugin produces a plain-text Amcache report. Useful when you're already running RegRipper across other hives or need narrative output. Use AmcacheParser when you need CSV.
- AmcacheParser output columns explained: every CSV field decoded
Field-by-field reference for AmcacheParser's CSV output. FileId, PathHash, ProgramId, LinkDate, BinFileVersion, IsPeFile, and every other column, with the pivots that matter.
- AmcacheParser download guide: official sources, mirrors, and verification
Where to get AmcacheParser. Get-ZimmermanTools, direct download, KAPE, Velociraptor. Plus checksum verification and the air-gapped install pattern.