Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WMI is being too slow

Tags:

c#

wmi

Is there a way to limit the number of entries WMI retrieves with a WQL statement? I say this because running a query to retrieve all Win32_NTLogEvent instances is taking forever! All I really need are the most recent events (for about a week, or 2000 entries)

Here's a snippet of the code I'm using to get the log data. Other queries such as Win32_Processor are nice and quick.

            if (Configuration.OnlyErrorLogs)
            {
                // If Information logs should be suppressed, only get events where event type is not 3
                WMIDataTemp1 = DataRetriever.GetWMIData("Win32_NTLogEvent", "EventType<>3");
            }
            else
            {
                WMIDataTemp1 = DataRetriever.GetWMIData("Win32_NTLogEvent");
            }
            foreach (ManagementObject Object in WMIDataTemp1)
            {
                this.Log.Add(new Log(Object));
            }

And the functions to get WMI data are as follows:

    public static ManagementObject[] GetWMIData(string wmiClass) { return GetWMIData(wmiClass, "", "CIMV2"); }
    public static ManagementObject[] GetWMIData(string wmiClass, string whereClause) { return GetWMIData(wmiClass, whereClause, "CIMV2"); }
    public static ManagementObject[] GetWMIData(string wmiClass, string whereClause, string nameSpace)
    {
        try
        {
            // If a where clause has been set, prepare the clause to add to the query string
            if (whereClause != "")
            {
                whereClause = " WHERE " + whereClause;
            }
            // Create a search query
            string query = "SELECT * FROM " + wmiClass + whereClause;
            ManagementObjectSearcher wmiSearcher = new ManagementObjectSearcher("root\\" + nameSpace, query);
            ManagementObjectCollection matches = wmiSearcher.Get();

            // Create an array to hold the matches
            ManagementObject[] matchArray = new ManagementObject[matches.Count];

            // If matches found, copy to output
            if(matches.Count > 0)
            {
                // Copy the search matches into this array
                matches.CopyTo(matchArray, 0);
            }

            // Return array
            return matchArray;
        }
        catch (Exception e)
        {
            ErrorDialogue errorReporter = new ErrorDialogue(e);
            return null;
        }
    }

Where each Log gets stored:

public class Log
{
    public string Category = "N/A";
    public string DateTime = "N/A";
    public UInt16 ID = 0;
    public string Level = "N/A";
    public string Message = "N/A";
    public string Source = "N/A";

    public Log() { }
    public Log(ManagementObject wmiLogEvent)
    {
        this.GetInfo(wmiLogEvent);
    }

    public void GetInfo(ManagementObject wmiLogEvent)
    {
        try
        {
            this.Category = DataRetriever.GetValue(wmiLogEvent, "CategoryString");
            this.DateTime = DataRetriever.GetValue(wmiLogEvent, "TimeGenerated");
            this.ID = DataRetriever.GetValueUInt16(wmiLogEvent, "EventIdentifier");
            this.Level = DataRetriever.ConvertEventType(DataRetriever.GetValueUInt16(wmiLogEvent, "CategoryString"));
            this.Message = DataRetriever.GetValue(wmiLogEvent, "Message");
            this.Source = DataRetriever.GetValue(wmiLogEvent, "SourceName");
        }
        catch (Exception e)
        {
            ErrorDialogue errorReporter = new ErrorDialogue(e);
        }
    }
}
like image 259
Chris Watts Avatar asked Dec 29 '25 01:12

Chris Watts


2 Answers

One option is to use a WHERE clause to specify the range of the entries you want...

For example you could use TimeGenerated in the WHERE clause to specify a time-based range...

Another option is to set BlockSize accordingly when creating ManagementObjectSearcher.

You could use that to specify that you want 2000 entries per call for example - together with an ORDER BY TimeGenerated DESC this should give a nice result.

like image 127
Yahia Avatar answered Dec 31 '25 18:12

Yahia


Speed is not a strong suit for WMI. It tends to be quite memory intensive. However, the question has been addressed and there are a few things you can do. Check out Why are my queries taking such a long time to complete? from Microsoft TechNet.

like image 28
Nilpo Avatar answered Dec 31 '25 18:12

Nilpo