Subscribe to the Inserted and Removed events to be notified when a USB drive is plugged in or unplugged, or when a USB device is connected or disconnected. Usb.Events is a .NET Standard 2.0 library and uses WMI on Windows, libudev on Linux and IOKit on macOS.
-
Include NuGet package from https://www.nuget.org/packages/Usb.Events
<ItemGroup> <PackageReference Include="Usb.Events" Version="11.1.1.0" /> </ItemGroup> -
Subscribe to events:
using Usb.Events; class Program { static void Main(string[] _) { using IUsbEventWatcher usbEventWatcher = new UsbEventWatcher(); usbEventWatcher.UsbDeviceRemoved += (_, device) => Console.WriteLine("Removed:" + Environment.NewLine + device + Environment.NewLine); usbEventWatcher.UsbDeviceAdded += (_, device) => Console.WriteLine("Added:" + Environment.NewLine + device + Environment.NewLine); usbEventWatcher.UsbDriveEjected += (_, path) => Console.WriteLine("Ejected:" + Environment.NewLine + path + Environment.NewLine); usbEventWatcher.UsbDriveMounted += (_, path) => { Console.WriteLine("Mounted:" + Environment.NewLine + path + Environment.NewLine); foreach (string entry in Directory.GetFileSystemEntries(path)) Console.WriteLine(entry); Console.WriteLine(); }; Console.ReadLine(); } }
UsbEventWatcher(
bool startImmediately = true,
bool addAlreadyPresentDevicesToList = false,
bool usePnPEntity = false,
bool includeTTY = false)
- Set
startImmediatelytofalseif you don't want to start immediately, then callStart(). - Set
addAlreadyPresentDevicesToListtotrueto include already present devices inUsbDeviceList. - Set
usePnPEntitytotrueto queryWin32_PnPEntityinstead ofWin32_USBControllerDevicein Windows. - Set
includeTTYtotrueto monitor theTTYsubsystem in Linux (besides theUSBsubsystem).
Win32_PnPEntity- PRO: works for all devices
- CON: is CPU intensive
- CON: uses only 2 methods to find
MountedDirectoryPathfor storage devices (this should still work for most devices)
Win32_USBControllerDevice- PRO: uses 3 methods to find
MountedDirectoryPathfor storage devices - PRO: in not CPU intensive
- CON: for some devices it can stop reporting
UsbDeviceAddedevent after the device is added and removed a few times
- PRO: uses 3 methods to find
Using Win32_USBControllerDevice is usually the better option.
Usb.Events.Example demonstrates how to use Windows SetupAPI.dll functions SetupDiGetClassDevs, SetupDiEnumDeviceInfo and SetupDiGetDeviceProperty together with DEVPKEY_Device_DeviceDesc, DEVPKEY_Device_BusReportedDeviceDesc and DEVPKEY_Device_FriendlyName to get "Device description", "Bus reported device description" and "Friendly name" of the Usb.Events.UsbDevice reported by the Usb.Events.IUsbEventWatcher.UsbDeviceAdded event.
Usb.Events.csproj uses gcc to build UsbEventWatcher.Mac.dylib from UsbEventWatcher.Mac.c when run on macOS and to build UsbEventWatcher.Linux.so from UsbEventWatcher.Linux.c when run on Linux.
On Debian/Ubuntu based Linux distros you need to install:
gcc with:
sudo apt-get install build-essential
32-bit and 64-bit udev with:
sudo apt-get install libudev-dev:i386 libudev-dev:amd64
support for compiling 32-bit on 64-bit Linux:
sudo apt-get install gcc-multilib
Usb.Events.dll expects to find UsbEventWatcher.Linux.so and UsbEventWatcher.Mac.dylib in the working directory when it runs, so make sure to build the project on Linux and Mac before building the NuGet package on Windows.
32-bit Intel macOS:
gcc -shared -m32 ./Mac/UsbEventWatcher.Mac.c -o ./x86/Release/UsbEventWatcher.Mac.dylib -framework CoreFoundation -framework DiskArbitration -framework IOKit
32-bit Intel Linux:
gcc -shared -m32 ./Linux/UsbEventWatcher.Linux.c -o ./x86/Release/UsbEventWatcher.Linux.so -ludev -fPIC
64-bit Intel macOS:
gcc -shared -m64 ./Mac/UsbEventWatcher.Mac.c -o ./x64/Release/UsbEventWatcher.Mac.dylib -framework CoreFoundation -framework DiskArbitration -framework IOKit
64-bit Intel Linux:
gcc -shared -m64 ./Linux/UsbEventWatcher.Linux.c -o ./x64/Release/UsbEventWatcher.Linux.so -ludev -fPIC
32-bit ARM macOS:
gcc -shared -march=armv7-a+fp ./Mac/UsbEventWatcher.Mac.c -o ./arm/Release/UsbEventWatcher.Mac.dylib -framework CoreFoundation -framework DiskArbitration -framework IOKit
32-bit ARM Linux:
gcc -shared -march=armv7-a+fp ./Linux/UsbEventWatcher.Linux.c -o ./arm/Release/UsbEventWatcher.Linux.so -ludev -fPIC
64-bit ARM macOS:
gcc -shared -march=armv8-a ./Mac/UsbEventWatcher.Mac.c -o ./arm64/Release/UsbEventWatcher.Mac.dylib -framework CoreFoundation -framework DiskArbitration -framework IOKit
64-bit ARM Linux:
gcc -shared -march=armv8-a ./Linux/UsbEventWatcher.Linux.c -o ./arm64/Release/UsbEventWatcher.Linux.so -ludev -fPIC
To build 32-bit and 64-bit ARM versions of UsbEventWatcher.Linux.so on Windows, you need to install Docker.
Due to changes in macOS Gatekeeper that were introduced sometime between May 28, 2025 and July 15, 2025, simply building and running the code on macOS no longer works by default.
macOS may block the included .dylib files, reporting that it "couldn’t verify the software for malicious content".
To use the code successfully, the .dylib must be signed with a Developer ID Application certificate.
- Automatically mount USB drive on
UsbDeviceAddedevent in Linux - Automatically mount USB drive on
UsbDeviceAddedevent in macOS
- 11.1.1.0 (2025-01-29):
- Fixed
GetChildin Linux - thanks to @M0ns1gn0r
- Fixed
- 11.1.0.1 (2024-01-05):
- Added XML documentation
- 11.1.0.0 (2023-11-30):
- Added
UsbEvents.snkto sign the assembly with a strong name key
- Added
- 11.0.1.1 (2023-11-17):
- Added 64-bit ARM support in macOS - thanks to @slater1
- 11.0.1.0 (2023-07-29):
- Fixed
InvalidOperationExceptionin Linux and macOS - by @Frankh67
- Fixed
- 11.0.0.1 (2023-07-21):
- Added 32-bit and 64-bit ARM support in Linux
- 11.0.0.0 (2023-07-16):
- Added 32-bit support in Linux
- 10.1.1.1 (2023-06-04):
- Fixed
Dispose()to exit native monitor loop in macOS
- Fixed
- 10.1.1.0 (2023-06-01):
- Fixed
Dispose()to exit native monitor loop in Linux - Added
bool usePnPEntityto useWin32_PnPEntityin Windows
- Fixed
- 10.1.0.1 (2023-04-21):
- Added
bool addAlreadyPresentDevicesToListin Windows
- Added
- 10.1.0.0 (2023-04-15):
- Updated
System.Managementpackage reference from4.7.0to7.0.0
- Updated
- 10.0.1.1 (2021-11-09):
- Added
bool startImmediately = truetoUsbEventWatcherconstructor - Added
void Start(bool includeTTY = false)toIUsbEventWatcher
- Added
- 10.0.1.0 (2021-11-01):
- Added
bool includeTTY = falsetoUsbEventWatcherconstructor - Fixed a
EnumerateDevicesbug in Linux - thanks to @d79ima
- Added
- 10.0.0.1 (2021-10-31):
- Fixed a false "device added" events bug in Linux - thanks to @d79ima
- 10.0.0.0 (2021-07-02):
- Fixed a
NullReferenceExceptionin Linux and macOS - by @thomOrbelius
- Fixed a
- 1.1.1.1 (2021-02-13):
- Fixed a bug in Windows where
MountedDirectoryPathwasn't set for a disk drive - thanks to @cksoft0807
- Fixed a bug in Windows where
- 1.1.1.0 (2021-02-01):
- Fixed a memory leak in Linux function
GetLinuxMountPoint- by @maskimthedog - Fixed a bug in Linux where after instantiating
UsbEventWatcher, the list of devices was empty - by @maskimthedog - Added monitoring of
TTYsubsystem in Linux - by @maskimthedog - Fixed a bug in Linux where monitoring would stop upon error - by @maskimthedog
- Fixed a memory leak in Linux function
- 1.1.0.1 (2020-09-19):
- Fixed a bug
- 1.1.0.0 (2020-08-01):
- Added:
MountedDirectoryPathIsMountedIsEjected
- Breaking changes:
DevicePathrenamed toDeviceSystemPathUsbDriveInsertedrenamed toUsbDriveMountedUsbDriveRemovedrenamed toUsbDriveEjectedUsbDeviceInsertedrenamed toUsbDeviceAdded
- Added:
- 1.0.1.1 (2020-07-10):
- Fixed a bug
- 1.0.1.0 (2020-07-04):
- Events for all USB devices
- 1.0.0.1 (2020-07-07):
- Fixed a bug
- 1.0.0.0 (2020-04-28):
- Events for USB drives and USB storage devices
| version | linux-arm | linux-arm64 | linux-x64 | linux-x86 | osx-arm64 | osx-x64 |
|---|---|---|---|---|---|---|
| 11.1.1.0 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| 11.1.0.1 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| 11.1.0.0 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| 11.0.1.1 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| 11.0.1.0 | ✔ | ✔ | ✔ | ✔ | ✔ | |
| 11.0.0.1 | ✔ | ✔ | ✔ | ✔ | ✔ | |
| 11.0.0.0 | ✔ | ✔ | ✔ | ✔ | ✔ | |
| 10.1.1.1 | ✔ | ✔ | ||||
| 10.1.1.0 | ✔ | ✔ | ||||
| 10.1.0.1 | ✔ | ✔ | ||||
| 10.1.0.0 | ✔ | ✔ | ||||
| 10.0.1.1 | ✔ | ✔ | ||||
| 10.0.1.0 | ✔ | ✔ | ||||
| 10.0.0.1 | ✔ | ✔ | ||||
| 10.0.0.0 | ✔ | ✔ | ||||
| 1.1.1.1 | ✔ | ✔ | ||||
| 1.1.1.0 | ✔ | ✔ | ||||
| 1.1.0.1 | ✔ | ✔ | ||||
| 1.1.0.0 | ✔ | ✔ | ||||
| 1.0.1.1 | ✔ | ✔ | ||||
| 1.0.1.0 | ✔ | ✔ | ||||
| 1.0.0.1 | ✔ | ✔ | ||||
| 1.0.0.0 | ✔ | ✔ |