# Hardware.Info reads the same hardware list on three operating systems

> Hardware.Info is a .NET Standard 2.0 library that reports battery, BIOS, processor, drive, keyboard, memory, monitor, motherboard, mouse, network adapter, printer, sound card and graphics card information, using WMI on Windows and /dev, /proc and /sys on Linux. It suits a .NET application that needs to describe the machine it runs on, and the Windows path has a documented startup cost.

**Jinjinov/Hardware.Info** — Battery, BIOS, CPU - processor, storage drive, keyboard, RAM - memory, monitor, motherboard, mouse, NIC - network adapter, printer, sound card - audio card, graphics card - video card. Hardware.Info is a .NET Standard 2.0 library and uses WMI on Windows, /dev, /proc, /sys on Linux and sysctl, system_profiler on macOS.

- Repository: https://github.com/Jinjinov/Hardware.Info
- Stars: 704 · Forks: 107
- Language: C#
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/jinjinov-hardware-info

## One API over three very different system interfaces

Hardware.Info is a .NET Standard 2.0 library that reports battery, BIOS, CPU processor, storage drive, keyboard, RAM memory, monitor, motherboard, mouse, NIC network adapter, printer, sound card audio card and graphics card video card information. The interesting part is how it does that on three operating systems that expose hardware in incompatible ways. On Windows it uses WMI, the Windows Management Instrumentation. On Linux it reads /dev, /proc and /sys directly. On macOS it uses sysctl and system_profiler. The audience is a .NET developer who needs a structured answer to what hardware is this, and who does not want to write a Windows branch, a Linux branch and a macOS branch. The library returns lists of typed objects with consistent properties across platforms, which is the practical value, since the same object graph is what you would otherwise have to normalise yourself. The repository is split into Hardware.Info.Core, the shared object model, Hardware.Info, Hardware.Info.Aot, and matching test and benchmark projects for each, plus a NuGet test project and a solution file.

The package is added by reference in the project file:

```xml
<PackageReference Include="Hardware.Info" Version="110.0.0.1" />
```

The AOT package is a separate reference with the same version number.

## The AOT variant exists because System.Management does not survive trimming

Hardware.Info.Aot uses WmiLight instead of System.Management and supports AOT. That single line explains a whole branch of the repository. The standard System.Management assembly in .NET is a Windows-only COM interop wrapper that pulls in reflection and is not friendly to ahead-of-time compilation or to trimming, so a project publishing with PublishTrimmed enabled, or building native ahead of time, cannot use it. WmiLight is a managed reimplementation of the WMI query protocol that avoids the COM dependency, which makes the AOT package the one to choose for those publishing models. The cost is that the two packages are separate NuGet packages with separate versions, so a codebase that supports both trimmed and normal builds carries two references. The README also documents a related known issue, that WmiNetUtilsHelper will throw an exception on Windows if the publish settings use PublishTrimmed true, and it links the dotnet issue that tracks the underlying cause.

## The refresh model is explicit, per category

The usage pattern is a HardwareInfo instance and a set of Refresh methods, one per hardware category, with RefreshAll() available when you want everything. The example in the README shows the whole set commented out, one per line, for the operating system, memory status, battery list, BIOS list, computer system list, CPU list, drive list, keyboard list, memory list, monitor list, motherboard list, mouse list, network adapter list, printer list, sound device list and video controller list, and then a single call to hardwareInfo.RefreshAll() to populate everything. The per category methods are the interesting design choice, because a full refresh on Windows touches every WMI class, and the library gives you a way to ask for only what you need. The properties are then plain lists, so hardwareInfo.BatteryList, hardwareInfo.BiosList, hardwareInfo.CpuList, hardwareInfo.DriveList, hardwareInfo.KeyboardList, hardwareInfo.MemoryList, hardwareInfo.MonitorList, hardwareInfo.MotherboardList, hardwareInfo.MouseList, hardwareInfo.NetworkAdapterList, hardwareInfo.PrinterList, hardwareInfo.SoundDeviceList and hardwareInfo.VideoControllerList, alongside hardwareInfo.OperatingSystem and hardwareInfo.MemoryStatus for the scalar values.

## Drives nest partitions which nest volumes

The example loops are worth reading because they show the shape of the object graph rather than just the names. A CPU has a CpuCoreList, so you iterate the processor and then its cores. A drive has a PartitionList and each partition has a VolumeList, so the nesting goes drive, then partition, then volume, which is what makes it possible to report a physical disk, its partition layout and the mounted volumes separately. Static helpers cover the network address case, with overloads of GetLocalIPv4Addresses that take an interface type, an operational status, or nothing at all, so you can ask for Ethernet addresses that are up, wireless addresses on the 802.11 interface, everything that is up, or every address the machine has. The BIOS and computer system lists are separate, which matters on machines with more than one BIOS entry, and the memory status is exposed as a single object rather than a list because it describes the current state of RAM rather than a set of devices.

## The 21 second WMI delay is the thing to plan around

The known issues section leads with the one that bites hardest in production. Hardware.Info uses WMI on Windows, and for certain queries WMI takes 21 seconds to initialize the first time you use it, after which all subsequent queries execute immediately. If WMI is not used for 15 minutes it has to be initialized again the next time. The cause is RPC, which WMI uses internally, where the documentation says the RPC over TCP time-out interval is defined by an SCMApiConnectionParam registry value under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control with a default of 21,000, which is 21 seconds. The fix given is to avoid the delay by excluding the queries that cause it, which is what the Settings options are for. For a desktop application that is merely slow on first run, and for a service that has a startup timeout it is a serious problem. There is a second issue in the same family, that NetworkAdapter.Speed in Win32_NetworkAdapter can sometimes be 0 or long.MaxValue, with the correct value in CurrentBandwidth in Win32_PerfFormattedData_Tcpip_NetworkAdapter, but reading that class also triggers the 21 second first read, so calling RefreshNetworkAdapterList with includeBytesPersec set to true will read it and cost you the same delay.

## Versions, packaging and what is not in the README

The release history shows a versioning scheme with four segments, which is unusual and worth noting because it means the major version is not the only thing that moves. The recent releases are 110.0.0.1 on 2026-05-21, 110.0.0.0 on 2026-05-19 and 101.1.1.1 on 2026-01-26, so the 100 series carries the .1 patch component and the 110 series carries a .0 component. The package references in the README use version 110.0.0.1 for both Hardware.Info and Hardware.Info.Aot, so the two ship in step. The repository is not archived and the last push was on 2026-05-21, and the licence is MIT. The tree carries CODE_OF_CONDUCT.md, CONTRIBUTING.md, a PULL_REQUEST_TEMPLATE.md, a HardwareInfo.snk signing key and a .gitignore, alongside the benchmark and test projects. What the documentation does not cover is the accuracy of the values themselves, the mapping of each property across the three platforms, and which categories return empty lists on a given system, so for a project that depends on specific fields it is worth reading the source for those types rather than trusting that a property means the same thing everywhere.

## Conclusion

Adopt Hardware.Info when a .NET application needs a structured inventory of the machine it is running on, and you want one API across Windows, Linux and macOS rather than three platform specific code paths. Do not adopt it for a service that must start in under a second on Windows, because the first WMI query costs 21 seconds unless you exclude the offending queries, and do not use it in place of a monitoring agent. Verify first that the hardware categories you need are present on your platforms, that you can set the options that skip the slow WMI queries, and that the AOT variant is the one you want if you publish trimmed.

## FAQ

### What can Hardware.Info report about a machine?

Battery, BIOS, CPU processor, storage drive, keyboard, RAM memory, monitor, motherboard, mouse, NIC network adapter, printer, sound card and graphics card information, plus the operating system and the memory status. It is a .NET Standard 2.0 library using WMI on Windows, /dev, /proc and /sys on Linux, and sysctl and system_profiler on macOS.

### Why does the first Hardware.Info call on Windows take 21 seconds?

WMI needs to initialize for certain queries the first time you use it, and subsequent queries execute immediately, but if WMI is not used for 15 minutes it initializes again. The delay comes from RPC internally used by WMI, whose default TCP time-out interval is 21 seconds, and you can avoid it by excluding the queries that cause it through the Settings options.

### When should I use Hardware.Info.Aot instead of Hardware.Info?

Hardware.Info.Aot uses WmiLight instead of System.Management and supports ahead-of-time compilation, so it is the one to choose if you publish trimmed or build native ahead of time. Note that WmiNetUtilsHelper throws an exception on Windows if PublishTrimmed is set to true in the standard package.

### How do I get the network addresses with Hardware.Info?

Call the static helper GetLocalIPv4Addresses with the filters you need: an interface type such as NetworkInterfaceType.Ethernet or Wireless80211, an OperationalStatus, or no arguments for every address. For the adapter list itself, use RefreshNetworkAdapterList, noting that passing includeBytesPersec as true reads CurrentBandwidth and triggers the same 21 second first read on Windows.

## Sources

- [Issues](https://github.com/Jinjinov/Hardware.Info/issues)
- [Jinjinov/Hardware.Info on GitHub](https://github.com/Jinjinov/Hardware.Info)
- [License: MIT](https://github.com/Jinjinov/Hardware.Info/blob/master/LICENSE)
- [README](https://github.com/Jinjinov/Hardware.Info/blob/master/README.md)
- [Releases](https://github.com/Jinjinov/Hardware.Info/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jinjinov-hardware-info
