如何在.NET 4.7中创建Decoupled MI Provider?Windows NT服务场景
Hey there! Let's break this down step by step—you're dealing with a tricky mix of legacy tech and under-documented newer MI tooling, so I'll start by clearing up the terminology confusion, then walk you through creating a decoupled MI provider in .NET 4.7 for your NT services.
First: Let's Unpack Those Terms
I totally get the confusion with all the acronyms—here's a quick, plain-English breakdown:
- WMI (v1): The old, COM-based Windows Management Instrumentation system you're finding all the outdated examples for. Microsoft has officially deprecated this, so you're right to avoid it.
- MI (Management Infrastructure): WMI's modern replacement (often called WMIv2). It's lighter, more efficient, and built on the industry-standard CIM (Common Information Model).
- CIM / CIMv2: CIM is a universal standard for defining management data; CIMv2 is the most widely used version (you might recognize it from the
root/cimv2namespace in old WMI). MI is Microsoft's implementation of CIM for Windows. - MMI (Managed Management Infrastructure): The .NET wrapper for MI, letting you write MI providers in C#/VB.NET instead of native C++.
- Decoupled MI Provider: A type of MI provider that runs as a separate process from your NT services. This keeps your service's stability independent of the monitoring provider—if the provider crashes, your service keeps running, and vice versa.
Creating a Decoupled MI Provider in .NET 4.7
Since there's scarce documentation for this, here's a working example tailored to your use case (exposing NT service status for monitoring):
1. Set Up Your Project
- Create a new Class Library (.NET Framework 4.7) project (or a Console App if you want to run the provider as a standalone process).
- Install the
Microsoft.Management.InfrastructureNuGet package—this gives you access to the MMI APIs.
2. Define Your CIM Data Class
First, create a .NET class that maps to the CIM object you want to expose (this is what monitoring tools will query):
using Microsoft.Management.Infrastructure; [CimClass("MyServiceStatus", Namespace = "root/MyServiceMonitor")] public class MyServiceStatus { [CimKey] // Marks this as a unique identifier for the instance public string ServiceName { get; set; } // 0 = Stopped, 1 = Running, 2 = Paused, 3 = Other, 4 = Error public uint Status { get; set; } public DateTime LastStartTime { get; set; } public ulong UptimeSeconds { get; set; } }
3. Build the Provider Host
Create a host (we'll use a console app for simplicity) that listens for MI queries and returns your service status data:
using Microsoft.Management.Infrastructure; using Microsoft.Management.Infrastructure.Options; using System; using System.ServiceProcess; using System.Threading; namespace MyServiceMIProvider { class ProviderHost { static void Main(string[] args) { // Configure the provider and target namespace var providerOptions = new CimProviderOptions("MyServiceMonitorProvider"); var targetNamespace = "root/MyServiceMonitor"; // Initialize the CIM server to handle incoming queries using (var cimServer = new CimServer(providerOptions)) { // Register our class and request handler cimServer.RegisterInstanceProvider(targetNamespace, typeof(MyServiceStatus), HandleInstanceRequests); Console.WriteLine("Decoupled MI Provider running... Press Ctrl+C to stop."); var shutdownEvent = new ManualResetEvent(false); Console.CancelKeyPress += (sender, e) => shutdownEvent.Set(); shutdownEvent.WaitOne(); } } // Handles incoming queries for service status data static CimInstance HandleInstanceRequests(CimRequest request) { // Replace these with your actual NT service names var targetServices = new[] { "Service1", "Service2", "Service3" }; foreach (var serviceName in targetServices) { using (var serviceController = new ServiceController(serviceName)) { try { // Map ServiceController status to our custom code var statusCode = serviceController.Status switch { ServiceControllerStatus.Running => 1, ServiceControllerStatus.Stopped => 0, ServiceControllerStatus.Paused => 2, _ => 3 }; // Calculate uptime if the service is running var uptime = serviceController.Status == ServiceControllerStatus.Running ? (ulong)(DateTime.Now - serviceController.StartTime).TotalSeconds : 0; // Return the populated CIM instance return new CimInstance(typeof(MyServiceStatus)) { CimInstanceProperties = { { "ServiceName", CimValue.Create(serviceName) }, { "Status", CimValue.Create(statusCode) }, { "LastStartTime", CimValue.Create(serviceController.StartTime) }, { "UptimeSeconds", CimValue.Create(uptime) } } }; } catch (Exception) { // Return an error state if the service can't be accessed return new CimInstance(typeof(MyServiceStatus)) { CimInstanceProperties = { { "ServiceName", CimValue.Create(serviceName) }, { "Status", CimValue.Create(4) }, { "LastStartTime", CimValue.Create(DateTime.MinValue) }, { "UptimeSeconds", CimValue.Create(0UL) } } }; } } } return null; } } }
4. Register the Provider
To let Windows know about your MI provider, use the miregprov.exe tool (included with the Windows SDK):
- Open an elevated command prompt.
- Run this command (replace the path with your compiled provider executable):
miregprov.exe -n root/MyServiceMonitor -p MyServiceMonitorProvider -c "C:\Path\To\Your\MyServiceMIProvider.exe"
5. Test the Provider
You can verify it works using tools like:
Get-CimInstancein PowerShell:Get-CimInstance -Namespace root/MyServiceMonitor -ClassName MyServiceStatus- WBEMTest (legacy WMI tool—MI is backward-compatible, so this will work too).
Key Notes
- Permissions: Run the provider host with an account that has access to query NT service status (Local System works well for this).
- Decoupling: Since this provider runs as a separate process, it won't impact your NT services if it encounters issues. You can even deploy it to a separate server if needed.
- Monitoring Compatibility: Most modern monitoring tools support MI directly, but if yours only uses WMI v1, it will still be able to query your MI provider thanks to backward compatibility.
内容的提问来源于stack exchange,提问作者user5423533

