Giter Club home page Giter Club logo

ormi's Introduction

ORMi (Object Relational Management Instrumentation)

ORMi (pronounced "ormee") is a quite simple Light-ORM to work with WMI (Windows Management Instrumentation). It handles WMI CRUD operations in a very easy way. ORMi does automatic mapping to model clases so you can easily work with WMI classes without having to worry about writing complex queries and handling WMI connections.

Getting Started

Nuget Nuget GitHub release (latest by date)

ORMi is available via NuGet. Also, you can always download the latest release on https://github.com/nicoriff/ORMi/releases/.

How to Use

ORMi is just too easy to work with. Let's for example suppose we want to access root\CIMV2 namespace to get the some information about our computer proccesors. First of all, we need to use the library:

using ORMi;

Then, we'll define the following class:

    [WMIClass("Win32_Processor")]
    public class Processor : WMIInstance
    {
        public string Name { get; set; }

        [WMIProperty("NumberOfCores")]
        public int Cores { get; set; }

        public string Description { get; set; }
    }

ORMi has some custom attributes to map the model clases to WMI classes. WMI classes usually have tricky or non conventional names that you will for sure not want to use on your class. For solving that problem ORMi just maps the class property name to the WMI property name. If you do not want to use the WMI property name then you can just specify the WMIProperty attribute and match it to the name of the WMI property. The same run for class names. In that case you can make use of WMIClass attribute. Note that the class inherits from WMIInstance class. This is an optional practice from version 2.0. Even if you can not use it, it is recommended as it will be strictly neccesary if you work with WMI methods. If you don't use methods, just don't add the inheritance.

The first thing you got to do is create the WMIHelper that is the class that you'll use to interact with WMI. You can either create the instance for local use or to connect to a remote client. In that case you have to specify credentials or make sure that the user have the corresponding privileges. From version 3.0 there is actually two ways you can create an instance of WMIHelper:

1) Manually Create

You just have to create a WMIHelper instance and you are all set to go.

    WMIHelper helper = new WMIHelper("root\\CimV2");

Or specifiying client machine and credentials:

    WMIHelper helper = new WMIHelper("root\\CimV2", "W2012SRV-WRK", "Administrator", "Password01");

2) Dependecy Injection

From version 3.0 you can make use of Microsoft DI implementation to inject WMIHelper instance to all the classes that need to use it:

On Program.cs declare the IWMIHelper implementation:

    .ConfigureServices((hostContext, services) =>
    {
        services.AddSingleton<IWMIHelper>(new WMIHelper("root\\cimv2"));
        services.AddHostedService<Worker>();
    });

And then you can make use of dependency injection wherever you need it:

    private readonly IWMIHelper _helper;

    public WMIService(IWMIHelper helper)
    {
        _helper = helper;
    }

Usage

Then you simply query for the data:

    List<Processor> processors = helper.Query<Processor>().ToList();

This can also be done in async fashion:

    List<Processor> processors = await helper.QueryAsync<Processor>().ToList();

If you don't want to define your model classes the you can also get the result in a List<dynamic>

    var devices = helper.Query("SELECT * FROM Win32_PnPEntity");

You can also search for single instances:

     Printer printer = helper.QueryFirstOrDefault<Printer>();

Create, Update and Delete:

For adding, updating and deleting instances we are going to use a custom namespace and classes. In this example the namespace is root\EmployeesSystem. And we have the following class defined:

    [WMIClass("Lnl_Person")]
    public class Person
    {
        public string Lastname { get; set; }
        public string FirstName { get; set; }

        [WMIProperty( Name = "SSNO", SearchKey = true)]
        public string DocumentNumber { get; set; }

        [WMIProperty("PRIMARYSEGMENTID")]
        public int Segment { get; set; }

        [WMIIgnore]
        public string City { get; set; }
    }

Examples:

Add Instance:

	Person person = new Person
	{
	    FirstName = "John",
	    Lastname = "Doe",
	    DocumentNumber = "9995",
	    Segment = -1
	};

	helper.AddInstance(person);

Update Instance:

For the Update operation, the class must have the WmiProperty attribute declared with the SearchKey property properly set to true. This will use the property with the SearchKey to get the instance that is going to be updated. For example:

	Person person= helper.Query<Person>("SELECT * FROM Lnl_Cardholder WHERE LASTNAME = 'Doe'").SingleOrDefault();

	person.Lastname = "Doe Modified";

	helper.UpdateInstance(person);

In the above example, ORMi is going to look for the person with SSNO = 9995 and update that instance with the properties set on person instance.

Remove Instance:

As in the update operation, the removal works with the SearchKey property set or manually specifying a query. In both cases, the result will be removed:

	Person p = helper.Query<Person>("SELECT * FROM Lnl_Cardholder WHERE LASTNAME = 'Doe'").SingleOrDefault();
	helper.RemoveInstance(p);

NOTE: From version 1.5 ORMi supports multiple SearchKey attributes set. This is due to WMI classes that have composite keys. If there is no SearchKey set, then a exception will be thrown.

All above operations can also be done asynchronously. For example:

Add Instance asynchronously:

	 Person person = new Person
	 {
	     FirstName = "John",
	     Lastname = "Doe",
	     DocumentNumber = "9995",
	     Segment = -1
	 };

	 await helper.AddInstanceAsync(person);

Creating an WMI Event Watcher:

Creating a watcher is one of the simplest tasks in ORMi. Just declare the watcher specifying scope, query and the desired output type and that's it!. Start receiving events!. In this example we are going to watch for new processes created on the system:

First, we define the class:

    [WMIClass("Win32_ProcessStartTrace")]
    public class Process
    {
        public string ProcessName { get; set; }
        public int ProcessID { get; set; }
    }

Then subscribe for events...

	WMIWatcher watcher = new WMIWatcher("root\\CimV2", "SELECT * FROM Win32_ProcessStartTrace", typeof(Process));
	watcher.WMIEventArrived += Watcher_WMIEventArrived;

Or if you have WMIClass attribute set:

	WMIWatcher watcher = new WMIWatcher("root\\CimV2", typeof(Process));
	watcher.WMIEventArrived += Watcher_WMIEventArrived;

And then, just handle the events...

    private static void Watcher_WMIEventArrived(object sender, WMIEventArgs e)
    {
        Process process = (Process)e.Object;

        Console.WriteLine("New Process: {0} (Pid: {1})", process.ProcessName, process.ProcessID.ToString());
    }

Or you can just not define any Type to return and ORMi will return a dynamic object containing all the WMI properties for the WMI instance:

	WMIWatcher watcher = new WMIWatcher("root\\CimV2", "SELECT * FROM Win32_ProcessStartTrace");
	watcher.WMIEventArrived += Watcher_WMIEventArrived;

Since version 3.1.0 you can also inject WMIWatcher into your classes using Microsoft DI implementation. Just like you can do with WMIHelper:

    .ConfigureServices((hostContext, services) =>
    {
        services.AddHostedService<Worker>();
        services.AddSingleton<IWMIWatcher, WMIWatcher>();
    });

NOTE: If you inject WMIWatcher with the empty constructor you will have to call the Initialize method so you can correctly initialize WMIWatcher with the desired parameters. Otherwise it will not work

    public class Worker : BackgroundService
    {
        private readonly IWMIWatcher _watcher;

        public Worker(IWMIHelper helper, IWMIWatcher watcher)
        {
            _watcher = watcher;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _watcher.Initialize("root\\CimV2", "SELECT * FROM Win32_ProcessStartTrace");
            _watcher.WMIEventArrived += _watcher_WMIEventArrived;
        }

        private void _watcher_WMIEventArrived(object sender, WMIEventArgs e)
        {
            dynamic process = e.Object;

            Console.WriteLine("New Process: {0} (Pid: {1})", process.ProcessName, process.ProcessID.ToString());
        }
    }

Methods

Since version 1.3.0 ORMi supports method working in a quite simple way. WMI defines two types of methods: Instance methods and Static methods.

Static methods are the ones in which you don't need any instance of a class to run the method. You just call the method and that's about it. What you will have to do on with ORMi to call the methods you want, is to define them on your model class. This will make a more readable and understandable code, and you will not have to mess with the complexity of having to do all the method calling coding by yourself.

IMPORTANT: From version 2.0 all classes that have methods declared must inherit from WMIInstance. This is due to the need to use the scope of the instance. If there is no inheritance, the methods will be executed using the current user, and will probably throw an exception if it runs against a remote computer.

Static Methods:

One example of static method is Create() on Win32_Process class. We are going to use it fo this example. Suppose we have the following model:

    [WMIClass(Name = "Win32_Process", Namespace = "root\\CimV2")]
    public class Process
    {
        public int Handle { get; set; }
        public string Name { get; set; }
        public int ProcessID { get; set; }
        public DateTime CreationDate { get; set; }

        public dynamic GetOwnerSid()
        {
            return WMIMethod.ExecuteMethod(this);
        }

        public ProcessOwner GetOwner()
        {
            return WMIMethod.ExecuteMethod<ProcessOwner>(this);
        }

        public int AttachDebugger()
        {
            return WMIMethod.ExecuteMethod<int>(this);
        }

        public ProcessResult Create(string commandLine, string currentDirectory, string processStartupInformation)
        {
            ProcessResult res = WMIMethod.ExecuteStaticMethod<ProcessResult>(new { CommandLine = commandLine, CurrentDirectory = currentDirectory, ProcessStartupInformation = processStartupInformation});
            return res;
        }
    }

    public class ProcessOwner
    {
        public string Domain { get; set; }
        public int ReturnValue { get; set; }
        public string User { get; set; }
    }


    public class ProcessResult
    {
        public int ProcessId { get; set; }
        public int ReturnValue { get; set; }
    }

You can see that Process class has a couple of methods. Some of them are instance methods like GetOwner and others like Create() are static. As said earlier, static means that there is no need for an instance to be created to call the method. Notice that the implementation of Create() method is the following:

    ProcessResult res = WMIMethod.ExecuteStaticMethod<ProcessResult>(new { CommandLine = commandLine, CurrentDirectory = currentDirectory, ProcessStartupInformation = processStartupInformation});

As you can see, you call the ExecuteStaticMethod method and specify which type of response you are awaiting by setting the <T> parameter.

So finally, you call the method simply like this:

	WMIHelper helper = new WMIHelper("root\\CimV2");

	Process p = new Process();
	p.Create("C:/Windows/notepad.exe", null, null);

Instance Methods:

Instance methods are a little bit more complicated than static ones. Instance methods (as you imagine) requiere that you call the method on an actual instance of a class. So you will first have to retrieve the instance on where you want to run the method. In this example we are going to work with Win32_Printer class and we are going to rename one printer.

Firstly, we are going to define our class:

	[WMIClass(Name = "Win32_Printer", Namespace = "root\\CimV2")]
	public class Printer : WMIInstance
	{
	    public string DeviceID { get; set; }
	    public string Name { get; set; }
	    public string Caption { get; set; }

	    public void RenamePrinter(string newName)
	    {
	        WMIMethod.ExecuteMethod(this, new { NewPrinterName = newName });
	    }
	}

Note that we have a DeviceID property. This property must always be set on this case because in this case, DeviceID is a CIM_Key and Unique and it is the only unique identifier between instances. If you do not set this property then you will get an exception. Also you can note that the parameters are sent using an anonymous object with properties that match the instance method ones. If this properties cannot be mapped the you'll receive an exception.

Then finally we'll use it this way:

	List<Printer> printers = helper.Query<Printer>().ToList();

	foreach (Printer p in printers)
	{
	    p.RenamePrinter("Newly renamed printer");
	}

The above code will rename all printers to "Newly renamed printer" (be careful! :D)

ORMi can also return and object containing the method execution result. For example let´s take Win32_Process class:

We´ll define it as the following:

    [WMIClass("Win32_Process")]
    public class Process : WMIInstance
    {
        public int Handle { get; set; }
        public string Name { get; set; }
        public int ProcessID { get; set; }

        public dynamic GetOwnerSid()
        {
            return WMIMethod.ExecuteMethod(this);
        }

        public ProcessOwner GetOwner()
        {
            return WMIMethod.ExecuteMethod<ProcessOwner>(this);
        }

        public int AttachDebugger()
        {
            return WMIMethod.ExecuteMethod<int>(this);
        }
    }

Note that GetOwner() implementation specifies a ProcesOwner type. If you check WMI docs on Win32_Processor class for GetOwner method, you´ll see the following definition:

uint32 GetOwner(
  [out] string User,
  [out] string Domain
);

So you will have to define the following structure to retrieve the result in a beautiful way:

    public class ProcessOwner
    {
        public string Domain { get; set; }
        public int ReturnValue { get; set; }
        public string User { get; set; }
    }

So, finally, you would do the following:

    List<Process> processes = helper.Query<Process>().ToList();

    foreach (Process p in processes)
    {
        ProcessOwner po = p.GetOwner();
    }

ormi's People

Contributors

anetre avatar chucker avatar ewisted avatar kevwkev avatar nicoriff avatar ssewell avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ormi's Issues

WMI cannot return the result, please help, thank you

I use WMI to get information on a remote computer, If use Administrator, both of the following queries can return data。

SELECT * FROM Win32_DiskDrive,
SELECT * FROM Win32_NTLogEvent

If use a non-Administrator account, the data can be returned first.The second one returns zero data, I guess it is the problem of the remote computer setting, but I don't know how to do it specifically. Please help me, thank you

System.InvalidCastException: Object must implement IConvertible

I ran across this exception when trying to query for a WMI object with other WMI objects as properties. The specific instance is Win32_UserProfile.

As you can see in the docs, it has properties of Win32_FolderRedirectionHealth. My first thought was to treat it like you would serializing an object from JSON, where you have the properties as follows-

[WMIClass(Name = "Win32_UserProfile", Namespace = "root\\CimV2")]
    public class UserProfile
    {
        public string SID { get; set; }
        public string LocalPath { get; set; }
        public bool Loaded { get; set; }
        [WMIProperty("refCount")]
        public uint RefCount { get; set; }
        public bool Special { get; set; }
        public bool RoamingConfigured { get; set; }
        public string RoamingPath { get; set; }
        public bool RoamingPreference { get; set; }
        public uint Status { get; set; }
        public DateTime LastUseTime { get; set; }
        public DateTime LastDownloadTime { get; set; }
        public DateTime LastUploadTime { get; set; }
        public byte HealthStatus { get; set; }
        public DateTime LastAttemptedProfileDownloadTime { get; set; }
        public DateTime LastAttemptedProfileUploadTime { get; set; }
        public DateTime LastBackgroundRegistryUploadTime { get; set; }
        public FolderRedirectionHealth AppDataRoaming { get; set; }
        public FolderRedirectionHealth Desktop { get; set; }
        public FolderRedirectionHealth StartMenu { get; set; }
        public FolderRedirectionHealth Documents { get; set; }
        public FolderRedirectionHealth Pictures { get; set; }
        public FolderRedirectionHealth Music { get; set; }
        public FolderRedirectionHealth Videos { get; set; }
        public FolderRedirectionHealth Favorites { get; set; }
        public FolderRedirectionHealth Contacts { get; set; }
        public FolderRedirectionHealth Downloads { get; set; }
        public FolderRedirectionHealth Links { get; set; }
        public FolderRedirectionHealth Searches { get; set; }
        public FolderRedirectionHealth SavedGames { get; set; }
    }

And for the properties model, it would look like this-

[WMIClass(Name = "Win32_FolderRedirectionHealth", Namespace = "root\\CimV2")]
    public class FolderRedirectionHealth
    {
        public string OfflineFileNameFolderGUID { get; set; }
        public bool Redirected { get; set; }
        public bool OfflineAccessEnabled { get; set; }
        public DateTime LastSuccessfulSyncTime { get; set; }
        public DateTime LastSyncTime { get; set; }
        public byte LastSyncStatus { get; set; }
        public byte HealthStatus { get; set; }
    }

Using this data model and passing UserProfile as a type parameter to QueryAsync results in the following exception-

System.InvalidCastException: Object must implement IConvertible.
   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at System.Convert.ChangeType(Object value, Type conversionType)
   at ORMi.Helpers.TypeHelper._SetPropertyValue(ManagementBaseObject mo, PropertyInfo p, Object o)
   at ORMi.Helpers.TypeHelper.LoadObject(ManagementObject mo, Type t)
   at ORMi.WMIHelper.QueryFirstOrDefault[T](String query)
   at ORMi.WMIHelper.<>c__DisplayClass28_0`1.<QueryFirstOrDefaultAsync>b__0()
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ORMi.WMIHelper.<QueryFirstOrDefaultAsync>d__28`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at servicedesk_tools.Services.Implementations.RemoteSessionService.<IsUserLoggedIn>d__1.MoveNext() in C:\Users\EricWi\Source\Repos\servicedesk-tools\servicedesk-tools\Services\Implementations\RemoteSessionService.cs:line 103
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at servicedesk_tools.UnitTests.RemoteSessionServiceIntegrationTests.<IsUserLoggedInSingleServerTest>d__3.MoveNext()

I've already forked the repo and fixed this with a little recursion, but I was wondering if this is a known issue or a design choice that this functionality was left out? Or is there a better way built in to handle this that I don't know about?

Implement IDisposable pattern in WMIWatcher class

The class WMIWatcher contains a field ManagementEventWatcher that is disposable.

It's possible change WMIWatcher to dispose the ManagementEventWatcher field and stop watcher for new events when the object WMIWatcher is finalized?

System.Management compatibility

Getting some "ORMi 3.1.1 requires System.Management (= 4.6.0) but version System.Management 5.0.0 was resolved"

Possible to lift the supported version for System.Management?

Best regards

Win32_Process create method

Can you help me with creating process with ORMi?
Something like this?

[WMIClass("Win32_Process")] public class Win32_Process : WMIInstance { public dynamic Create(string commandLine, string currentDirectory, dynamic data, dynamic result) { return WMIMethod.ExecuteMethod(this,commandLine,currentDirectory,data,result); } }

Cannot access namespace "TerminalServices" remotely (Access Denied)

Hi,

This is what I try to do:

WMIHelper helper = new WMIHelper("root\CimV2\TerminalServices", "10.0.0.1", "contoso\user", "Hello");
List remoteApps = helper.Query().ToList();

System.Management.ManagementException
HResult=0x80131501
Message=Access denied
Source=System.Management
StackTrace:
at System.Management.ManagementException.ThrowWithExtendedInfo(ManagementStatus errorCode)
at System.Management.ManagementObjectSearcher.Get()
at ORMi.WMIHelper.QueryT

This is the cause of the issue:

To connect to the Root\CIMV2\TerminalServices namespace, the authentication level must include packet privacy. For C/C++ calls, this is an authentication level of RPC_C_AUTHN_LEVEL_PKT_PRIVACY.
https://docs.microsoft.com/en-us/windows/win32/termserv/win32-terminalservicesetting?redirectedfrom=MSDN

Can you support packet privacy scenario?

Thanks!

Call static method without an instance

I may be reading the documentation incorrectly but in the example, for executing a static method you are using a namespace that has instances. I'm trying to call a static method on a WMI class that has only a single static method and nothing else. If I try to use helper.query, I don't get anything back since there are no instances so I don't have a way to make the method call. I know I'm missing something obvious but it escapes me at the moment.

Plans to migrate to Microsoft.Management.Infrastructure namespace?

I love this project. It really makes WMI much easier to use in C#. However, I was wondering if there are any plans to migrate the project to start using the Microsoft.Management.Infrastructure namespace instead of System.Management. Here is what Microsoft has to say about the choice between the two:

System.Management was the original namespace that covered managed code for WMI. However, the underlying technology for System.Management is generally slower than, and does not scale as well as, Microsoft.Management.Infrastructure. As such, it is not recommended that you use System.Management for new projects.

https://docs.microsoft.com/en-us/previous-versions/hh872326(v=vs.85)

Adding caching and performance improvements to the mapping and reflection

An immediate performance improvement would be to cache the PropertyInfo and setter as a delegate and the attributes for the target POCO, like how HyperDescriptor or FastMember or Fasterflect and the ORM Entity Framework does it.

I'm writing a library that is using some heavy hitting WMI queries and it's the mapping part that's adding a time delay. In my particular business case it goes from .002 to .05 for a particular operation. It's not bad from a human user perspective but it would be nice to keep it in the thousandths of a second range for the operation, because in my particular use case and code architecture I can't use an event watcher and have to run my operation in a tight blocking loop.

Although I don't know how to improve iterating over ManagementObjectCollection. That also adds a heavy delay but that's just WMI. Someone suggests using ManagementClass on MSDN. Also maybe analyzing the target POCO and removing irrelevant properties from the query automatically may be of some use, but the consumer can already handle that.

Method Name is incorrect

When attempting to use WMIMethod.ExecuteMethod with parameters. The wrong method name is selected and the calling method name is used instead.

 [WMIClass("Win32_NetworkAdapterConfiguration")]
    public class NetworkAdapterConfiguration
    {
        public string Caption { get; set; }
        public string Description { get; set; }

        public UInt32 InterfaceIndex { get; set; }

        public bool SetStatic(string ip, string netmask)
        {
            int retVal = WMIMethod.ExecuteMethod(this, new {IPAddress = new string[] {ip}, SubnetMask = new string[] {netmask}});

            if(retVal != 0)
                Console.WriteLine($"Failed to set network settings with error code {retVal}");

            return retVal == 0;
        }
    }
void SetupInterfaces(){
 var interfaces = helper.Query<NetworkAdapterConfiguration>()

foreach(var interface in interfaces){
    interface.SetStatic("123.123.123.123","255.255.255.0");
}
}

SetupInterface ends up being selected as the MethodName instead of SetStatic.

Issue with getting the property DelayedAutoStart on Win32_Service and Windows Server 2012R2

Hi!

Doing this crashes with an exception "Invalid Query" on Windows Server 2012R2 but works fine on Windows Server 2016:
servicesTask = _wmiHelper.QueryAsync();

Service look like this:

[WMIClass("Win32_Service")]
public class Service : WMIInstance
{
    public string Name { get; set; }
    public string DisplayName { get; set; }
    public string StartMode { get; set; }
    public string State { get; set; }
    public string Description { get; set; }
    public bool DelayedAutoStart { get; set; }
    public string StartName { get; set; }
    public string PathName { get; set; }
}

If I instead query like this servicesTask = _wmiHelper.QueryAsync("SELECT * FROM Win32_Service"); it works but the dynamic objects returned doesn't contain the property "DelayedAutoStart" running on Windows Server 2012R2 but running it in 2016 includes the property though. In Windows Server 2012R2 the services can be set to Automatic and with delayed start though.

BR

Knekten

[BUG] Querying classes with property of type ManagementBaseObject[]

There is an unhandled case of mapping using the IWMIHelper : when the result contain an array of ManagementBaseObject.
I faced an error when I was querying "WmiMonitorListedSupportedSourceModes" (https://docs.microsoft.com/en-us/windows/win32/wmicoreprov/wmimonitorlistedsupportedsourcemodes). The class contain an array of "VideoModeDescriptor" but the mapping cannot be done in the "_SetPropertyValue" function because there isn't a case for "ManagementBaseObject[]".

Can't use async query with Helper

Hi and thank you for your work.
i try to use Ormi with async query like that:

[WMIClass("Win32_Processor")]
  public class Processor : WMIInstance
  {
      public string Name { get; set; }
      [WMIProperty("NumberOfCores")]
      public int Cores { get; set; }
      public string Description { get; set; }
  }

WMIHelper helper = new WMIHelper("root\\CimV2", host, account, password);
List<Processor> processors = await helper.QueryAsync<Processor>().ToList();
...

but i got Compiler Error CS1061 with msg like: Task<IEnumerable<Form1.Processor>> no definition for ToList()...
is anybody have a idea to fix that ?

Can't run code on linux

If i publish app on linux server i get System.Management currently is only supported for Windows desktop applications.

Conversion fails for Nullable ValueType

It seems Convert.ChangeType at L76 of TypeHelper chokes on a nullable value type when the value is null. Since a null value will result in default value of property anyway, we can do an early return out of _SetPropertyValue and not run into an InvalidCastException.

Property tested: IPConnectionMetric as unit? on NetworkAdapterConfiguration

StackTrace:

   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at ORMi.Helpers.TypeHelper.LoadObject(ManagementObject mo, Type t)
   at ORMi.WMIHelper.Query[T]()
   at UserQuery.Main()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

Proposed fix @L76: Simplify to p.SetValue(o, a, null);

Is there a specific scenario that you're using Convert.ChangeType for? IMHO, if there's a mismatch of types between what WMI was expecting and what end-user wanted, end-user should be doing an explicit cast rather than the library.

It might be worth looking into a Converter attribute for more custom behaviour like going from a string IPAddress to IPAddress. I've done something similar in my powershell-converter repo for the same reason: Serialize & Deserialize

Thank you very much for your work. This makes working with WMI much more pleasant.

Remote machine

Can ORMi access WMI remotely?

WmiLight code, as an example:

var cred = new NetworkCredential("USERNAME", "PASSWORD", "DOMAIN");

using (WmiConnection con = new WmiConnection(@"\\MACHINENAME\root\cimv2", cred, opt))
{
    foreach (WmiObject partition in con.CreateQuery("SELECT * FROM Win32_DiskPartition"))
    {
        Console.WriteLine(partition["Name"]);
    }
}

.NET framework 4

Not working under .NET Fr. 4?? What? o_O?
Why you supports only 4.6.1?
If no any variants to resolve this problem, I just will write mine custom wmi-classes. If you can't use WMI on XP/old Win Server and Framework 4, for what this ORM?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.