Search code examples
c#linqsortingwmiwmi-query

Sorting WMI ManagementObjectCollection and GetProcessesByName


I need to get information about and manipulate instances of a third-party program with the executable filename strModule for which hundreds of instances are spawned. Each instance is spawned with different command line parameters. To get information on and manipulate these instances, I am using a combination of WMI and Process.GetProcessesByName().

I sometimes need to act on the instances in process creation time order, and sometimes in alphabetical order by their command lines. That first part is easy, because WMI already by default returns the processes in order by creation time, and because I can easily sort the processes returned by GetProcessesByName() by creation time. I can just do something along the lines of:

ManagementObjectSearcher objWMISearcher = new ManagementObjectSearcher(
    "SELECT ProcessID, CommandLine FROM Win32_Process WHERE Name = \"" + strModule + ".exe\"");
ManagementObjectCollection aobjWMIs = objWMISearcher.Get();

Process[] aprc = Process.GetProcessesByName(strModule).OrderBy(x => x.StartTime).ToArray();

// I would like to sort aobjWMIs and aprc alphabetically by command line here,
// before entering the foreach loop

int nInstance = -1;
foreach (ManagementObject objWMI in aobjWMIs)
{
    nInstance++;
    // Code that does stuff on objWMI and aprc[nInstance]
}

I have code that is working fine and doing everything it is supposed to for when acting on the instances in order by creation time.

The problem is, I sometimes need to instead act on the instances in alphabetical order by command line instead of in creation time order.

My first thought was to add "ORDER BY" to the WMI SELECT query, but that didn't work, and I was so disappointed to then see in the documentation that WQL is only a very limited subset of SQL that apparently does not support "ORDER BY".

So what I need is some way to sort aobjWMIs by CommandLine, where it says "I would like to sort alphabetically by command line here, before the foreach loop" in the code I posted above.

My intuition is that there is some simple way using LINQ to first sort the ManagementObjectCollection aobjWMIs. Then, we could use LINQ to match the .Id field of each element of aprc to the ProcessID field of each element of aobjWMIs to sort aprc so that both ManagementObjectCollection aobjWMIs and Process[] aprc would have the instances of strModule in the same order.

However, I am not skilled with LINQ and do not know how to do this. Can anyone help? Thanks.


Solution

  • You first need to convert your WMI results from objects to concrete C# types. For example

    var tmpArray = (from mo in aobjWMIs.OfType<ManagementObject>() select new 
            { 
                ProcessID   = Convert.ToInt32 (mo.Properties["ProcessID"  ].Value), 
                CommandLine = Convert.ToString(mo.Properties["CommandLine"].Value)
            }
            ).ToArray();
    

    So you can now join the two arrays and sort the results by commandLine, eg

    var results = (from mo in tmpArray
                  join p in aprc on mo.ProcessID equals p.Id
                  orderby mo.CommandLine  
                  select new { mo.ProcessID, mo.CommandLine , p }
                  ).ToArray();