USB storage forensics in Win10 #1 - Events

Having information about USB devices connected to a system can be essential for some investigations and analyses. Most of the removable storages used nowadays are USB pen drives so knowing how to identify and investigate these is crucial. The main purpose of USB drive forensic analysis is to identify the connected devices and find some of the following information about it: connection and removal time, files copied to or from the device, opened and executed files and software from the attached drive. USB pen drives are heavily used by malicious actors for data stealing and malware propagation. Thus, related artifacts can be an essential part of many investigations.

Header picture - lock

There are three major USB device types in use nowadays. The one that is used the most for storage purposes is the Mass Storage Class (MSC). This is the class I am testing and documenting in this blog post. While lots of artifacts are the same for other classes as well, these were not tested by me. Here are the mentioned types and basic information about them:

  • Mass Storage Class (MSC):

    • Used by thumb drives, mp3 players, some smartphones
    • On Windows, it is recognized as Hard Disk Driver, or device with Removable Storage
    • Files can be copied to or from the drive
  • Picture Transfer Protocol (PTP):

    • Supported devices are: cameras, some smartphones
    • Can be used in case of image or video download from an external storage
    • User can download files from the drive but can’t upload anything to it (unidirectional)
  • Media Transfer Protocol (MTP):

    • Technically a successor of PTP
    • Bi-directional file moving (from/to the drive)
    • Can be used in case of any filetypes unlike PTP
    • Supported devices: cameras, smartphones

In this guide, I’m collecting the Windows events which can be used for MSC USB drive-related investigations. There are various other useful artifacts for investigations like this but I’m only going to expound some of them now, while the others are going to be explained in a later post.


  1. USB-related Windows events (this post)
  2. Registry files (upcoming post)
  3. (upcoming post)
  4. Other artifacts (LNK files, Recent files, etc) (upcoming post)

I am not only going to show the relevant artifacts but I am also writing some Powershell scripts to gather information. Correlating this info is also important because different sources contain different information so my tool is going to do that as well. The correlation part of the code is going to be written in Python. Powershell is a good choice to be used on a live system because it is not GUI-based. Thus, its impact on the system is smaller than another tool with graphical interface. It can collect events from local or remote systems and can be used to parse events from evtx files on the live system or offline. The script in this post only contains the collection part and the next post is going to have the full version with the correlation function.


There are a lot of commercial tools for USB investigation. While these can be used in specific cases, in other situations or at some companies you have to utilize other solutions. I have just started to deepen my Powershell knowledge lately, but I have already recognized some of its benefits over other softwares. Some examples when PS can be the good choice for collection over other tools:

  1. Low impact/non-GUI: You want to avoid GUI-based tools during collection or live forensics.
  2. Low resource demand: Collecting specific events instead of a full disk image or evtx files to decrease the storage or bandwidth usage. In some scenarios only a few specific events are necessary but it needs to be collected from a great deal of machines repeatedly.
  3. Flexible: You can use it for offline analysis on evtx files or in case of live forensics too.
  4. Remote: Collecting related events remotely from multiple systems.
  5. Pre-installed/non-GUI: You can remotely access a system, but you are not allowed to install any third-party tools onto it. / You can’t directly access an end-system but you can execute commands via some agents. / Your access to the system is not GUI-based (SSH or via some browser-based terminal tool), therefore you can only use command-line utility.

Here are two real-life scenarios:

Scenario 1:

There was a situation when my team encountered a malware which infected many workstations. The workstations were at the same location and since there weren’t any relevant network traffic between them, we assumed that the infection spread offline. The first idea was that an infected USB drive causes the issue but unfortunately we did not have any useful logs from the machines. The owners of the workstations confirmed they are using a lot of external drives but they didn’t know which one was the cause of the infection. In a situation like this, we do not have to behave in a forensic manner, we also do not want to pull a whole machine image. Remotely executing a Powershell script that collects the connected USB drives from multiple machines in a given timeframe is enough.

Scenario 2:

During this second investigation I have already found the malicious pen drive. I also knew the behavior of the malware on it. During connection, it did not put any malicious binary onto the machine but it generated a registry entry to obtain permanency. This entry only contained a malware download command which was executed after restarting the machine. After the command execution, this entry has been removed automatically. Because of this removal the registry entry wasn’t good enough for detection. The network connection generated by the download could have been a good idea as well but I wanted to cleanse the machines before they could connect to a suspicious URL. (Blocking the URL on the proxy wasn’t good enough, because circumventing the proxies was feasible in this network.) Since the pen drive was already identified, executing a Powershell script on every machine at the known location was a usable idea.


In this section, I’m going to list and explain the various events which are related to USB usage. Some of them are a clear indication of external storage usage. For example, the events which contain the name of the drive are assuredly related to that drive. There are some other events which are generated when an external drive is plugged in. Some of them are not a clear indication, still, these can refer to USB usage. One can use these events as a secondary confirmation, or these can be used to assume an external device usage when other logs were removed by the user or an attacker.

I’m not going to go into details of how events are working on Windows or how they are stored. But there are some common values and structures that are good to know. You can see the event logs in the Windows Event Viewer in different formats. The most useful for me is the XML format and I’m going to use this one in my Powershell codes as well because this one is detailed enough and well-structured. Thus, it is going to be easy to process in a Python code later on.

The events I’m using in this post has a simple structure. The XML entry starts with a root element called “Event”. Every piece of information is going to be stored as a child-node inside this root element. The first child-element is the “System” tag. This element appears in every type of events and it stores the same information in every one of them. This contains the same information for every event thus this part will be easy to parse and correlate. The second and last tag in the events I checked are either called “EventData” or “UserData”. The sub-nodes inside these and the contained information vary from events to events. Unique parsers have to be created for almost each type of events because of this variousness in the second child-node (EventData/UserData).

Here is an example of what a typical log looks like. One can see the “Event” root element, the “System” and “UserData” child-nodes and their child-nodes as well: (So as I said every tag in the System node like the Provider, EventID, Version, etc can be found in every tested event. On the other hand, the child-nodes in the UserData node like LifetimeId, TerminateStatus, etc are different for every type of event (every event id))

<Event xmlns="">
    <Provider Name="Microsoft-Windows-DriverFrameworks-UserMode" Guid="{2E35AAEB-857F-4BEB-A418-2E6C0E54D988}" /> 
    <TimeCreated SystemTime="2019-07-23T14:34:51.027729500Z" /> 
    <Correlation /> 
    <Execution ProcessID="784" ThreadID="868" /> 
    <Security UserID="S-1-5-18" /> 
    <UMDFDriverManagerHostShutdown xmlns="">

When collecting this data with Powershell we can use the Get-WinEvent cmdlet. There are two distinguished ways to do that. If we want to collect in a unified way we can execute the cmdlet without any other function. In this case, Powershell is going to return with the information from the “General” view of the Event Viewer. This includes every “System” node information and a “Message” property that contains the event in a flow-text form. This is lacking of information because it doesn’t contain the detailed “UserData/EventData” information and is hard to parse.

Still, in some specific cases, it is worth to use this form. During a manual investigation, it can contain enough information and it doesn’t have to be parsed at all. Also, it can be easier to store different events this way in a csv file or a database because of their unified structure and same properties. Check the following PS script and its output:

Get-WinEvent -FilterHashtable @{logname='system'; id=20001} | Select-Object -Property *

And a picture of its output. One can see the “Message” property that contains the description in a human-readable format:

Get-WinEvent output

The other way is to use the ToXml() function and save all of the information as an XML tag/node. In this case, the “EventData” or “UserData” node is also going to be saved in an easily parsable format.

$event = Get-WinEvent -FilterHashtable @{logname='system'; id=20001} -MaxEvents 1

I think on the output below it is easy to see that this version contains more information and that the UserData node is easier to parse than the Message property.

Get-WinEvent parsable XML output

Programmatically this is a better solution and I am using this one for my code. This post not going to contain the whole code though. The parsing and correlation function is going to come later. First I want to collect other information as well not just the events. Also one can see below how many different log sources and different events have to be collected and checked first.

The following event sources were investigated by me during this research:

  1. System
  2. DriverFramework-Usermode events
  3. UserPNP
  4. WPD-ClassInstaller
  5. Kernel-PnP
  6. WMI-Activity
  7. PushNotification-Platform
  8. Partition Diagnostic
  9. NTFS
  10. StorSVC Diagnostic
  11. Storage ClassPnP
  12. Device Setup Manager Admin
  13. Security
  14. Plug and Play detailed tracking
  15. Object Access Audit
  16. Microsoft-Windows-DriverFrameworks-UserMode/Operational

I’m going to collect the following information about every important event at the end of each section:

  • Useful data: What important pieces of information does the event store. It only details the unique information from the UserData/EventData part of the event. The ‘System’ child-node is stored in every event, so that data is stored in every event. (like event id, computer name, time)
  • Storage: Defines the name of the evtx file that contains the given event.
  • Enabled: Whether the logging of the event is enabled by default?
  • Trigger: The condition that triggers Windows to generate this event.

Please be aware that not every event is generated every time. Some of them only appear if there is an error, or if an already installed service needs to be updated. These are the events which were generated on my machine and I thought are worth to mention. These logs can vary based on the Windows type, version, build or settings.

1. System events

First I’m listing the related System events. These can be found in the System.evtx file. Important to note that the following system events were only generated during the first connection. It is due to driver installation which only happens once. After this, Windows will be able to handle the external device properly so the same events won’t be generated.

1.1 DriverFramework-Usermode events

These events are automatically generated; we do not have to enable anything. Here are the DriverFramework-Usermode events from the System.evtx file which were generated during the initial connection:

System DriverFramework-Usermode event

The following events were generated based on the picture:

  • Event ID: 10000 - driver package is being installed
  • Event ID: 10001 - service installation
  • Event ID: 10002 - service upgrade
  • Event ID: 10100 - the driver package installation has succeeded

Event ID 10000: This one contained some USB-related data, so this is a clear indication of external drive connection. The other ones don’t have too much useful information in them, so I’m not going to go into details.

Userdata from the first 10000 event:

    <UMDFDeviceInstallBegin xmlns="">  

Some of the cases the Vendor/Product/Revision/SerialNr are not in the event. Rather there is only a GUID in the DeviceId field. Example:


Useful data in event 10000:

  • DeviceID
  • GUID
  • Vendor
  • Product: example: {PROD_USB_DISK_PRO}
  • Revision
  • Serial Number


  • Storage: System.evtx
  • Enabled: yes
  • Trigger: first connection

1.2 UserPNP

The User Plug-n-Play Device Events found in the System Event Log indicate USB/PCI connections with the PC. An event is activated when a driver is installed or updated. These are enabled by default.

Relevant events:

  • Event ID: 20001 - Installation or Update
  • Event ID: 20002 - Installation error
  • Event ID: 20003 - Service Installation or Update

Here are the events which were generated during the initial connection of one of my USB drives:

System UserPNP event

UserData from the event 20001 (but 20003 also contains useful information, 20002 wasn’t tested):

  <InstallDeviceID xmlns="">
    <DriverDescription>WPD ...</DriverDescription> 

Useful data from 20001 and 20003:

  • Device Class ID: contains Vendor (VEN), Product name (Prod), Revision and Serial Number (field in the event: DeviceInstanceId)
  • VEN
  • PROD
  • Revision
  • Serial Number

Again, sometimes instead of the vendor, product name, revision and serial there is going to be a GUID. The same GUID can be found in the registry or in other logs. In this case to find the VEN/PROD/Revision,Serial values you have to search other artifacts with the same GUID in them.

1.3 WPD-ClassInstaller

Windows System also records the WPD (Windows Portable Devices) logs. WPD enables the operating system to communicate and coordinate with the attached devices which can be any one of the following: Music Players, Storage Media, Mobile Phones, Cameras and many other portable devices that can be connected to the computer. Enabled by default.

Related events:

  • Event ID: 24576 - Successful Installation Event ID
  • Event ID: 24577 - Compatibility Layer Successful Registration
  • Event ID: 24578 - Installation Error - this one wasn’t generated for me
  • Event ID: 24579 - Autoplay Skipping

System WPD event

These events do not contain any noteworthy information but it is a sign that something was attached. The generation time of the logs can be used as a pivot point.

Powershell code to collect relevant events from the System event file (github link):

$outputFile = "usbSystemLogsCollector.xml"

# System: DriverFramework-Usermode events: 10000,10001,10002,10100
# System: UserPNP events: 20001,20002,20003
# System: WPD-ClassInstaller: 24576,24577,24578,24579

$Filter = @{
    StartTime =  [datetime]::Today.AddDays(-30)
    EndTime = [datetime]::Today.AddDays(1)

$events = Get-WinEvent -FilterHashtable $Filter -ErrorAction SilentlyContinue
$finalXml = "<Events>"

ForEach ($event in $events){
    $finalXml += $event.ToXml()

$finalXml += "</Events>"
$finalXml | Out-File $outputFile

You can set the output file by modifying the $outputFile variable. The script checks the last 30 days only, if you want to look back further change the value -30 in the StartTime variable.

2. Kernel-PnP

These logs can be found in the Microsoft-Windows-Kernel-PnP%4Configuration.evtx file. The logging of these events is enabled by default. These logs are a good source of information so they are worth collecting. Collects other devices as well, like PCI devices, Display, SCSI. We only need to collect or investigate the USB ones.

This event type is heavily beneficial because:

  1. This is enabled by default while the Security events should be manually turned on and
  2. this logs every connection attempt while the System events only log the first connection.

This log is enabled by default and it logs every connection.

These are the events which were generated during the connection:

Kernel-PnP event

EventData from the event 400:

  <Data Name="DeviceInstanceId">USBSTOR\Disk&Ven_ADATA&Prod_USB_Flash_Drive&Rev_1100\27A17200901000F0&0</Data> 
  <Data Name="DriverName">disk.inf</Data> 
  <Data Name="ClassGuid">{4D36E967-E325-11CE-BFC1-08002BE10318}</Data> 
  <Data Name="DriverDate">06/21/2006</Data> 
  <Data Name="DriverVersion">10.0.18362.1</Data> 
  <Data Name="DriverProvider">Microsoft</Data> 
  <Data Name="DriverInbox">true</Data> 
  <Data Name="DriverSection">disk_install.NT</Data> 
  <Data Name="DriverRank">0xff0006</Data> 
  <Data Name="MatchingDeviceId">GenDisk</Data> 
  <Data Name="OutrankedDrivers">disk.inf:GenDisk:00FF2002</Data> 
  <Data Name="DeviceUpdated">false</Data> 
  <Data Name="Status">0x0</Data> 
  <Data Name="ParentDeviceInstanceId">USB\VID_125F&PID_CB10\27A17200901000F0</Data> 

EventData from the event 410:

  <Data Name="DeviceInstanceId">USB\VID_125F&PID_CB10\27A17200901000F0</Data> 
  <Data Name="DriverName">usbstor.inf</Data> 
  <Data Name="ClassGuid">{36FC9E60-C465-11CF-8056-444553540000}</Data> 
  <Data Name="ServiceName">USBSTOR</Data> 
  <Data Name="LowerFilters" /> 
  <Data Name="UpperFilters" /> 
  <Data Name="Problem">0x0</Data> 
  <Data Name="Status">0x0</Data> 

EventData from the event 430:

  <Data Name="DeviceInstanceId">SWD\WPDBUSENUM\{7ce3e952-a89e-11e9-9074-0021cccea670}#0000000000400000</Data> 

(The examples above are from unrelated USB activities. Do not try to correlate the properties in them.)

Useful data:

  • Device Class Id (DeviceInstanceId) in each events: either as a GUID or as VID/PID/Serial values


  • Storage: Microsoft-Windows-Kernel-PnP%4Configuration.evtx
  • Enabled: yes
  • Trigger: every connection

Powershell code to collect the relevant Kernel-PnP events (github link):

$outputFile = "usbKernelPnPLogsCollector.xml"

# Kernel-PnP Configuration events: 400,410,430
$Filter = @{
    StartTime =  [datetime]::Today.AddDays(-30)
    EndTime = [datetime]::Today.AddDays(1)

$events = Get-WinEvent -FilterHashtable $Filter -MaxEvents 100 -ErrorAction SilentlyContinue
$finalXml = "<Events>"

ForEach ($event in $events){
    $finalXml += $event.ToXml()

$finalXml += "</Events>"
$finalXml | Out-File $outputFile

3. WMI-Activity Operational

One event with ID 5857 was generated as well. This event was generated every time I tested the USB drive, but it does not contain any USB related information. While this can be a sign of external drive usage, it is inconclusive and doesn’t have any good information.

4. PushNotification-Platform

These events are generated when Windows shows a notification to the user. So this is once again an event type not specifically useful for us. Still, it is going to be generated during the connection and it contains the user ID to whom the system shows the notification. If you are lack of other sources this can be used as well to identify the user who used the drive. Be aware that lots of events are generated and there is be a little bit of latency, therefore, the timestamps are not going to be the same. Widen your timeframe when you make searches. Also generates logs in case of “Eject”.

Event IDs:

  • Event ID:2415
  • Event ID:3052
  • Event ID:3111
  • Event ID:3055
  • Event ID:3128
  • Event ID:3129

When I pulled out the drive I also got an event:

  • Event ID: 2415

These logs aren’t really useful for us, but it is good to know about them.

5. Partition Diagnostic events

Can be found in the Microsoft-Windows-Partition%4Diagnostic.evtx file. These events are enabled by default. Generates an event with id 1006 during insertion and removal. This even type is especially important. It contains some really useful and really unique information.

On some Windows versions this log wasn’t generated at all but I’m not sure why. However when it is generated it is a really good source of information.

Partial content of the EventData from an Event 1006:

  <Data Name="Manufacturer">ADATA</Data> 
  <Data Name="Model">USB Flash Drive</Data> 
  <Data Name="Revision">1100</Data> 
  <Data Name="Location">Integrated : Adapter 0 : Port 0</Data> 
  <Data Name="ParentId">USB\VID_125F&PID_CB10\27A17200901000F0</Data> 
  <Data Name="DiskId">{7CAB998D-00C7-60FE-329A-D3E38C066CCB}</Data> 
  <Data Name="AdapterId">{00000000-0000-0000-0000-000000000000}</Data> 
  <Data Name="RegistryId">{7CE3E952-A89E-11E9-9074-0021CCCEA670}</Data> 
  <Data Name="PoolId">{00000000-0000-0000-0000-000000000000}</Data> 
  <Data Name="PartitionCount">4</Data> 
  <Data Name="PartitionTableBytes">624</Data> 
  <Data Name="PartitionTable">00000000040000009C73CE1A2452EBAE0000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000B89C03000000010000000000000007000100002000009C73CE1A0000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F89C03000000000008000000000002000000000000000E000100007CCE019C73CE1A000000000000F89C0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009C73CE1A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009C73CE1A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</Data> 
  <Data Name="MbrBytes">512</Data> 
  <Data Name="Mbr">EB6390108ED0BC00B0B800008ED88EC0FBBE007CBF0006B90002F3A4EA21060000BEBE073804750B83C61081FEFE0775F3EB16B402B001BB007CB2808A74018B4C02CD13EA007C0000EBFE00000000000000000000000000000000800100000000000000FFFA9090F6C2807405F6C2707402B280EA797C000031C08ED88ED0BC0020FBA0647C3CFF740288C252BE057CB441BBAA55CD135A52723D81FB55AA753783E101743231C0894404408844FF894402C7041000668B1E5C7C66895C08668B1E607C66895C0CC744060070B442CD137205BB0070EB76B408CD13730D5A84D20F83DE00BE857DE98200660FB6C68864FF40668944040FB6D1C1E20288E888F4408944080FB6C2C0E80266890466A1607C6609C0754E66A15C7C6631D266F73488D131D266F774043B44087D37FEC188C530C0C1E80208C188D05A88C6BB00708EC331DBB80102CD13721E8CC3601EB900018EDB31F6BF00808EC6FCF3A51F61FF265A7CBE807DEB03BE8F7DE83400BE947DE82E00CD18EBFE47525542200047656F6D0048617264204469736B005265616400204572726F720D0A00BB0100B40ECD10AC3C0075F4C300000000000000000000000000009C73CE1A00000010011007FEC2FF00200000005CCE0100FEC2FF0EFEC2FF007CCE0100040000000000000000000000000000000000000000000000000000000000000000000055AA</Data> 
  <Data Name="Vbr0Bytes">512</Data> 
  <Data Name="Vbr0">EB52904E5446532020202000020800000000000000F8000020004000002000000000000080008000FF5BCE01000000000400000000000000BFE51C0000000000F60000000100000092BCA634767CD323000000000E1FBE717CAC22C0740B56B40EBB0700CD105EEBF032E4CD16CD19EBFE54686973206973206E6F74206120626F6F7461626C65206469736B2E20506C6561736520696E73657274206120626F6F7461626C6520666C6F70707920616E640D0A707265737320616E79206B657920746F2074727920616761696E202E2E2E200D0A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000055AA</Data> 
  <Data Name="Vbr1Bytes">512</Data> 
  <Data Name="Vbr1">EB3C906D6B66732E66617400020401000200020004F8010020004000000000000000000080012999AC1D21554546495F4E544653202046415431322020200E1FBE5B7CAC22C0740B56B40EBB0700CD105EEBF032E4CD16CD19EBFE54686973206973206E6F74206120626F6F7461626C65206469736B2E2020506C6561736520696E73657274206120626F6F7461626C6520666C6F70707920616E640D0A707265737320616E79206B657920746F2074727920616761696E202E2E2E200D0A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000055AA</Data> 

Some of the useful data:

  • Manufacturer
  • USB Capacity
  • Model : Same as Vendor ID in other events
  • Device Serial Number (stored in the ParentId field)
  • Parent ID : contains VID, PID and Serial Nr
  • VID / PID
  • DiskID: called DeviceGUID in some other events
  • Registry ID: You can use this one to identify the device in the registry.
  • PartitionTable : This is a really unique field. Contains the raw dump of the Partition Table.
  • MBR : This is a really unique field. Contains the raw dump of the MBR.
  • VBR : This is a really unique field. Contains the raw dump of the VBR.
  • LifetimeId: One of the events generated during removal will contain only this field and nothing else. Same Id can be found in other logs as well.

The event for insertion and removal is the same. It has the same ID and the same fields. (There is 1 unique event for removal with the same id. Its only content is a LifetimeId.) But you can differentiate them based on the values in the specific fields. For example, the “Capacity” field in the insertion events is going to have the size of the drive as value. On the other hand, the same field in the removal events is going to have the value of “0”. Therefore, this field can be used to find out which event was generated during the insertion and which was during the removal. (Timing information could be used as well obviously.)


  • Storage: Microsoft-Windows-Partition%4Diagnostic.evtx
  • Enabled: yes
  • Trigger: every connection / removal

Script to collect these Partition Diagnostic EventId 1006 events (github link):

$outputFile = "usbPartitionLogsCollector.xml"
$Filter = @{
    StartTime =  [datetime]::Today.AddDays(-30)
    EndTime = [datetime]::Today.AddDays(1)

$events = Get-WinEvent -FilterHashtable $Filter -ErrorAction SilentlyContinue
$finalXml = "<Events>"

ForEach ($event in $events){
    $finalXml += $event.ToXml()

$finalXml += "</Events>"
$finalXml | Out-File $outputFile


This one is only generated if the attached drive is an NTFS formatted drive. The logs are stored in the Microsoft-Windows-Ntfs%4Operational.evtx. Windows generates these type of events for any other drives which are NTFS not just for external/USB devices. Events are created during the first connection since the startup. (So if the user removes the drive and attaches it again no new logs are going to be made according to my investigation.)

Two events are generated:

  • Event ID 142: Shows information about the free space on the drive and the volume name as well.
  • Event ID 145: Shows the volume name, like drive D:\ (on some machine this event wasn’t generated)

EventData from event 142:

  <Data Name="VolumeGuid">{BB242FB7-AC21-11E9-9077-0021CCCEA670}</Data> 
  <Data Name="VolumeNameLength">2</Data> 
  <Data Name="VolumeName">D:</Data> 
  <Data Name="LowestFreeSpaceInBytes">3979325440</Data> 
  <Data Name="HighestFreeSpaceInBytes">3984949248</Data> 
  <Data Name="IsBootVolume">false</Data> 

Partial Event Data from event 145:

  <Data Name="VolumeCorrelationId">{BB242FB7-AC21-11E9-9077-0021CCCEA670}</Data> 
  <Data Name="VolumeNameLength">2</Data> 
  <Data Name="VolumeName">D:</Data> 
  <Data Name="IsBootVolume">false</Data> 
  <Data Name="MaxLatencyMs">30000</Data>

Technically the event 142 is enough for us and it is more useful. The information in the event 145 is not interesting from a forensic perspective (or at least the 142 is more beneficial).

Useful data:

  • VolumeGuid in 142 or VolumeCorrelationId in 145: registry contains more information about it
  • VolumeName: Letter of the volume, like D:
  • FreeSpaceInBytes


  • Storage: Microsoft-Windows-Ntfs%4Operational.evtx
  • Enabled: yes
  • Trigger: first connection for a drive after login

Script: Find the collector script on github under the name: usbNtfsCollector.ps1

7. StorSVC Diagnostic

Events from the Microsoft-Windows-Storsvc%4Diagnostic.evtx file. Every connection is logged under the ID 1001 and is enabled by default (some of my tested machines did not contain this file and event type). (Event ID 1002 was also generated in some cases but I don’t know what triggered it.)

Example EventData from event 1001:

  <Data Name="Version">2</Data> 
  <Data Name="DiskNumber">1</Data> 
  <Data Name="VendorId">ADATA</Data> 
  <Data Name="ProductId">USB Flash Drive</Data> 
  <Data Name="ProductRevision">1100</Data> 
  <Data Name="SerialNumber">AA00000000000489</Data> 
  <Data Name="ParentId">USB\VID_125F&PID_CB22\2851701540150099</Data> 
  <Data Name="FileSystem">FAT32</Data> 
  <Data Name="BusType">7</Data> 
  <Data Name="PartitionStyle">0</Data> 
  <Data Name="VolumeCount">1</Data> 
  <Data Name="ContainsRawVolumes">false</Data> 
  <Data Name="Size">7759462400</Data> 

Useful data:

  • Device Class ID: this also contains the VID, PID and the Serial Number (ParentId)
  • SerialNumber (not the same as the Unique Device Serial Number in the Device Class Id)
  • PID
  • VID
  • Size
  • VendorId: example: ADATA, but often it is emtpy
  • ProductId: example: USB DISK Pro
  • Product Revision


  • Storage: Microsoft-Windows-Storsvc%4Diagnostic.evtx
  • Enabled: yes
  • Trigger: connection

Script: Find the collector script on github under the name: usbStorSvcCollector.ps1

8. Storage ClassPnP

Events with ID 507 are going to be stored in this file: Microsoft-Windows-Storage-ClassPnP%4Operational.evtx. One or more event with the same ID is generated during every connection and also during safe removal (eject). Same events weren’t generated when I just pulled out the drive without the eject function. Based on my experiment the connection generates 2-3 Event ID 507 events, while the “Eject” generates 15-25 of them. The events I got are Error events, which means these are definitely not going to be generated every time.

Partial EventData information from Events ID: 507:

  <Data Name="DeviceGUID">{7CAB998D-00C7-60FE-329A-D3E38C066CCB}</Data> 
  <Data Name="DeviceNumber">1</Data> 
  <Data Name="Vendor">ADATA</Data> 
  <Data Name="Model">USB Flash Drive</Data> 
  <Data Name="FirmwareVersion">1100</Data> 
  <Data Name="SerialNumber">AA00000000000489</Data> 
  <Data Name="DownLevelIrpStatus">0xc0000185</Data> 
  <Data Name="SrbStatus">132</Data> 
  <Data Name="ScsiStatus">2</Data> 
  <Data Name="SenseKey">5</Data> 
  <Data Name="AdditionalSenseCode">32</Data> 
  <Data Name="AdditionalSenseCodeQualifier">0</Data> 
  <Data Name="CdbByteCount">6</Data> 
  <Data Name="CdbBytes">1E0000000100</Data> 
  <Data Name="NumberOfRetriesDone">0</Data> 

Useful data:

  • Vendor
  • Model: example: USB DISK Pro
  • FirmwareVersion: (Revision)
  • SerialNumber: example: 07B8040B68C001EA (not the same as the Unique Device Serial Number in the Device Class Id)
  • DeviceGUID: can be used to correlate between this event and event 1006


  • Storage: Microsoft-Windows-Storage-ClassPnP%4Operational.evtx
  • Enabled: yes
  • Trigger: connection / eject

Script: Find the collector script on gihub under the name: usbStorageClassPnpLogCollector.ps1

9. Device Setup Manager Admin events

Multiple logs are generated during connection and removal. Unfortunately, these are not generated every time and so far I couldn’t find out what triggers their generation. Sometimes new events are generated after logout-login or after a restart but in other cases, nothing happens. Because of this, I can’t handle it as a reliable information source. Therefore, I’m not going to use or detail these, but I thought they are worth mentioning.

Lack of these events doesn’t mean no connection happened, but the presence of them means that there was USB device activity. Related events:

  • Event ID: 100 - service start (no useful info in this one, but it precedes event 112)
  • Event ID: 112 - this one contains a “Prop_DeviceName” property, which is the name of the attached device
  • Event ID: 101 - service shutting down (no useful info in this one, but it is logged after event 112 every time)

Event ID 112 EventData content:

  <Data Name="Prop_DeviceName">ADATA USB Flash Drive</Data> 
  <Data Name="Prop_ContainerId">{756D86F5-387A-53A3-82AF-8B6267521DDA}</Data> 
  <Data Name="Prop_TaskCount">4</Data> 
  <Data Name="Prop_PropertyCount">34</Data> 
  <Data Name="Prop_WorkTime_MilliSeconds">922</Data> 

Useful data from event 112:

  • Model: (stored in the Prop_DeviceName field) example: USB Disk Pro
  • Prop_ContainerId: ContainerId (or DeviceContainer) can be found in the registry and it can be linked to the DeviceId


  • Storage location: Microsoft-Windows-DeviceSetupManager%4Admin.evtx
  • Enabled: yes
  • Trigger: ?

Script: Find the collector script on gihub under the name: usbDeviceSetupManagerLogCollector.ps1

10. Security events

No Security logs were generated by default. To utilize this event type one has to enable some additional logging capabilities.

10.1 Plug and Play detailed tracking

The collection/generation of Event ID 6416 is not enabled by default. Can be turned on under the Detailed Tracking category by enabling the Audit PNP Activity policy. Event 6416 is generated every time a device is plugged in. Unlike the default System events which are only generated during the first connection attempt. So over “System” events, it has the benefit of tracking every activity not just the first one. However, it also has a drawback: namely that it is not enabled by default.

Example EventData value from the event with id 6416:

  <Data Name="SubjectUserSid">S-1-5-18</Data> 
  <Data Name="SubjectUserName">DESKTOP-7T1733I$</Data> 
  <Data Name="SubjectDomainName">WORKGROUP</Data> 
  <Data Name="SubjectLogonId">0x3e7</Data> 
  <Data Name="DeviceId">USBSTOR\Disk&Ven_&Prod_USB_DISK_Pro&Rev_PMAP\07B8040B68C001EA&0</Data> 
  <Data Name="DeviceDescription">USB DISK Pro USB Device</Data> 
  <Data Name="ClassId">{4D36E967-E325-11CE-BFC1-08002BE10318}</Data> 
  <Data Name="ClassName">DiskDrive</Data> 
  <Data Name="VendorIds">USBSTOR\Disk________USB_DISK_Pro____PMAP USBSTOR\Disk________USB_DISK_Pro____ USBSTOR\Disk________ USBSTOR\________USB_DISK_Pro____P ________USB_DISK_Pro____P USBSTOR\GenDisk GenDisk</Data> 
  <Data Name="CompatibleIds">USBSTOR\Disk USBSTOR\RAW GenDisk</Data> 
  <Data Name="LocationInformation">-</Data> 

Contains a lot of information about the devices like (most of our events are not this talkative):

  1. Device Class Id: GUID or Vendor/Product/Revision/SerialNr (the latter one in the example above)
  2. Vendor IDs

One connection attempt generated 4 events with this id. Every event contains some common information and some unique which can’t be found in the others. For example, the last one contained the Volume Name: D:, but the other 3 don’t have this information. Every one of them should be collected and checked during an investigation.


  • Storage: Security
  • Enabled: no
  • Trigger: connection

10.2 Object Access Audit

The events listed below can be used to monitor the usage of the external drive. The following actions can be identified with these logs: file/folder creation, deletion, read, modification and metadata changes.

None of these are enabled by default. “Audit Removable Storage” and “Audit Handle Manipulation” policy needs to be turned on to provide full coverage. Without the latter one, you will only have visibility into the successful access attempts. (For some reason I also had to turn on the “Audit File System” option. Without this, I did not get any 4663 events, but with it, I got a lot of unnecessary, unneeded logs as well. I do not recommend this though, because this one policy itself can generate thousands of events per minute)

I found four different events during my investigation for this policy:

  • Event Id: 4656 - Request to a handle. Contains the object (folder, file), so can be used to look for some data but doesn’t mean the given data was accessed. This happens before a process could access to any object.
  • Event Id: 4663 - This is the actual action on the object. If this event exists, you can find out what a user did with some data.
  • Event Id: 4658 - After not using the file anymore the process is going to close the handle to the object.
  • Event Id: 4690 - Not useful for us in this scenario, but worth mentioning because technically this could be used by a malware to access an object it shouldn’t have access to.

Each event is different in this section so I’m going to describe them individually below.

[EventId: 4656]

A handle to an object was requested. When a process attempts to gain a handle to an audited object, this event is created. This doesn’t mean that anything was done with the object, only that a handle was requested. To find out what exactly happened with the given object look at the 4663 events. (If you want to find the 4663 event which is related to the given 4656 event then look for matching handle id-s in the logs. Handle ID is kept unique between reboots)

Event 4656 is not a clear indication of file or folder usage/modification. But it can still be useful to prove the existence of some data. Let’s say there is a data theft related investigation. You want to prove that a user stole some data via a USB drive. You are out of luck because the events 4663 are not logged, therefore you can’t prove that an actual copy happened to the external device. But Event 4656 contains the object (the file name with its full path pointing to the USB device) and the requested attributes. You don’t know what the user actually did with the file (without the event 4663) but now you can be sure that the file is on the external drive.

Useful data:

  • Object Name : the path to the file/folder (ex: \Device\HarddiskVolume4)
  • Process Name : the process which was used to access the file/folder
  • Handle ID : can be used to correlated data between different events
  • Access Mask : requested accesses


  • Enabled: no
  • Trigger: handle request
  • Storage: Security.evtx

[EventId: 4658]

This is the ending pair of the 4656 event. It means the given handle to an object was closed.

Useful data:

  • Handle ID: can be used to find its 4656 pair or the related 4663 event. This log itself doesn’t contain any useful information.


  • Enabled: no
  • Trigger: handle closure
  • Storage: Security.evtx

[EventId: 4663]

This event is going to tell you what exactly happened with the given object. A process can request a handle with multiple attributes but this doesn’t mean that any of the attributes were used at all. However, this event contains what happened with that object exactly.

For this log I show a picture instead of the XML code because from the code it is not trivial what is happening. On the picture, one can see that a file was created and modified. (WriteData and AppendData)

File creation modification based on 4663

Useful data:

  • Object Name : the path to the file/folder
  • Process Name : the process which was used to access the file/folder
  • Handle ID : can be used to correlate data between different events
  • Accesses: Not a mask but the executed actions.


  • Storage: Security
  • Enabled: no
  • Trigger: action on object

[EventId: 4690]

It doesn’t contain any useful information for us. Handle ID can be used to correlate data from the previous events, but it’s not really needed.

Description: When a program opens an object like a file, it gets a “handle” to that file which it references in subsequent operations on the object. Windows checks permissions at the time of the open (aka handle request) but not afterwards. Windows allows you to duplicate a handle and hand it off to another thread or process which then inherits whatever level of access the first program obtained to the object when the program opened.


  • Storage: Security
  • Enabled: no
  • Trigger: handle duplication

Script: Collector for every relevant Security event can be found at github: usbSecurityCollector.ps1

11. Microsoft-Windows-DriverFrameworks-UserMode/Operational

Description: These events are related to the drivers which are used by the external device. For example, events are generated when a device asks for a driver, when Windows starts/finishes the loading of the driver and so on. During USB removal Windows also generates “host process shutdown” and “UMDF Host shutdown” events. Therefore, we can easily monitor external drive connections and removals.

Different logs contain different information but there is some common information in all of them. The events generated during plug-in contains at least these two properties:

  • InstanceId: Information about the attached drive. Can be used to correlate information between connections because this value is unique for the drive.
  • LifetimeId: A value that is unique for a connection. Can be used to correlate data between “connection” and “removal” events because the “removal” ones do not have an InstanceID in them. If you detach and reattach a system, then you will get a new LifetimeId.

The events generated during the removal only have this one property in common:

  • LifetimeId

For this event source a lot of events are going to be generated. There is no fix number but generally a connection generates 30-40 events, while the removal generated exactly 4 events every time during my tests.

The following event ids were used during connection:

First 4 happens in this order (connection) (These four events weren’t generated during my first test):

  • Event Id: 1003: the Driver Manager service is starting a host process
  • Event Id: 2000: UMDF Host Process is starting up
  • Event Id: 2001: UMDF Host Process started successfully
  • Event Id: 1004: the host process started successfully

Others can be varied during a connection (connection):

  • Event Id: 2003: ask to load driver for device (first one every time)
  • Event Id: 2010: successfully loaded drivers for device
  • Event Id: 2004: loading driver
  • Event Id: 2006: successfully loaded driver
  • Event Id: 2100: received a PnP or Power operation
  • Event Id: 2105: forwarded a Pnp or Power operation
  • Event Id: 2106: received a Pnp or Power operation
  • Event Id: 2101: completed a Pnp or Power operation
  • Event Id: 2102: forwarded a finished Pnp or Power operation

The following eventids were used during removal (removal):

  • Event Id: 1006: ask to shut down
  • Event Id: 2900: UMDF Host has been asked to shutdown
  • Event Id: 2901: UMDF Host has shutdown
  • Event Id: 1008: successful shutdown (last one every time)

So you can monitor when exactly a device was connected by filtering on events with id 1003 / 2003 and 1008 and correlating their information based on the LifetimeId property. I’m going to do this at a later stage of my programme in Python. For now, here is a Powershell script that collects these events but the output has to be translated manually. The event at the bottom is the first one. One can see that a device was injected (event id 2003) then later on it was removed (event id 1008). You can find the injected device by looking at the 2003 event. I did not use the event with id 1003 because it did not exist during my first test.

The correlation between the injection and removal can be made based on the above-mentioned LifetimeId which is "{0CD7E7A3-E145-4027-8288-ADE14596C995}" in the first case. The picture shows multiple connections and removals with their unique LifetimeIds. The two events at the bottom are the ones with the previously mentioned LifetimeId. (I worked on an offline log)

Get-WinEvent -FilterHashTable @{Path="C:\Users\user\Logs\Microsoft-Windows-DriverFrameworks-UserMode%4Operational.evtx";  id=2003,1008} | Select-Object -Property TimeCreated, Id, Message

Connection tester script

Useful data. Most of the events contains one or both of these:

  • LifetimeId
  • Device Instance Id with RegistryID in it


  • Stored: Microsoft-Windows-DriverFrameworks-UserMode%4Operational.evtx
  • Enabled: no since Windows 8
  • Trigger: connection / removal


This post already became way longer than I originally intended it to be. During my research, I tested and documented a lot of different Windows events which are related to USB connection, removal or usage. Some of the events are a clear sign of external device usage with a lot of information while others only contain a low amount of information and aren’t proof of USB utilization. Some anti-forensics tools are able to remove events from evtx files, but it is hard to hide everything. Thus, collecting and knowing events with less amount of data can still be useful, because some of these are definitely not going to be removed by an anti-forensics solution.

Here is the list from the beginning of this post but now it only contains the event sources I will collect and use later in my script (supposedly). I also supplemented it with the related Event Ids:

  1. System
  2. DriverFramework-Usermode events (10000,10001,10002,10100)
  3. UserPNP (20001,20002,20003)
  4. WPD-ClassInstaller (24576,24577,24578,24579)
  5. Kernel-PnP (400,410,430)
  6. Partition Diagnostic (1006)
  7. NTFS (142,145)
  8. StorSVC Diagnostic (1001,1002)
  9. Storage ClassPnP (507)
  10. Device Setup Manager Admin (100,101,112)
  11. Security
  12. Plug and Play detailed tracking (6416)
  13. Object Access Audit 4656,4663,4658,4690)
  14. Microsoft-Windows-DriverFrameworks-UserMode/Operational (1003,2000,200,1004, 2003,2010,2004,2006,2100,2105,2106,2101,2102, 1006,2900,2901,1008)

As one can see I found much more related artifacts in the evtx files than I thought I would to so I have to cut this description short here. Because of this, I’m surely going to make 3 other related posts in the future:

  1. Post 2: The next one is still going to be related to Windows events. I’m planning to create a table/poster to put USB related events into it to make processing easier. I’m also going to create a Python script to correlate the information from the various collected events. This post is going to be a shorter one for sure. Different events store the same information in differently named fields so I also have to unify these properties.
  2. Post 3: The third post in this topic is going to contain the Windows registry-based artifacts and some code to collect and correlate them.
  3. Post 4: The presumably last post will be about the remaining USB related artifacts on Windows.

Find the collector code for these events on github:

If in the future I find out that some of the properties in the listed events are important but they weren’t mentioned in this post I’m going to correct this. But I’m not going to introduce any new events here after publication.

Test System

OS: MS Windows 10 Pro Version: 1903 Build: 18362.30

Powershell version: 5.1.18362.1