Search code examples
c#wmiwql

Retrieve LoggedOnUsers on Remote Machine


I'm building a C# application to monitor server and workstation workloads with WMI and WQL queries. I'm using WMI because it seems to be faster in comparison to powershell queries. My hardship starts when I try to retrieve logged on users on a remote machine. I figured I need to use the Win32_LoggedOnUser class. I have tried the following queries:

@"SELECT * FROM Win32_LoggedOnUser"
@"SELECT Antecedent FROM Win32_LoggedOnUser"

What I'm used to is to retrieve the desired value like this:

var cims = connection.getCimInstances(this, queryUser);

 if (cims != null)
 {
    foreach (CimInstance cim in cims)
    {
      Komponenten.User user = new Komponenten.User();
      user.Name = Convert.ToString(cim.CimInstanceProperties["Name"].Value);
                    users.Add(user);
    }
 }    

where queryUser is one of the strings from above.

In both cases, I get a Win32_Account object in return, which seems to suggest - and the debugger seems to confirm - that I should use CimInstanceProperties["Name"].Value on the returned Win32_Account class again. But that's not working at all. Any ideas on how to get access to the CimInstanceProperties of a Win32_Account stored in a CimInstanceProperity ? I can't find anything on the respective Windows reference page (https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-loggedonuser) nor during my extensive google-search.

Thanks!


Solution

  • I ended up using the ManagementObject-Class and Regex to find the usernames after converting the Antecedent - Object to a string:

    var users = new List<Komponenten.User>();
            var searcher = this.connection.makeQuery(this, "SELECT * FROM Win32_LoggedOnUser");
    
            if (searcher != null)
            {
                foreach (ManagementObject queryObj in searcher.Get())
                {
                    Komponenten.User user = new Komponenten.User();
                    var win32_account = queryObj["Antecedent"].ToString();
                    string stripped = Regex.Replace(win32_account, "[^a-zA-Z=]+", "", RegexOptions.Compiled);
                    int end = stripped.LastIndexOf("=");
                    user.Name = stripped.Substring(end+1);
                    users.Add(user);
                }
    
                this.users = users;
    

    An alternative which takes the LogonSession into account is:

    var users = new List<Komponenten.User>();
            var searcher = this.connection.makeQuery(this, "SELECT LogonId  FROM Win32_LogonSession Where LogonType=2");
            var Scope = this.connection.getScope(this, this.connection.getConnection());
    
            if (searcher != null)
            {
                foreach (ManagementObject queryObj in searcher.Get())
                {
                    ObjectQuery LQuery = new ObjectQuery("Associators of {Win32_LogonSession.LogonId=" + queryObj["LogonId"] + "} Where AssocClass=Win32_LoggedOnUser Role=Dependent");
                    ManagementObjectSearcher LSearcher = new ManagementObjectSearcher(Scope, LQuery);
                    foreach (ManagementObject LWmiObject in LSearcher.Get())
                    {
                        Komponenten.User user = new Komponenten.User();
                        user.Name =  Convert.ToString(LWmiObject["Name"]);
                        users.Add(user);
                    }
                }
                this.users = users;
            }
    

    where this.connection.getConnection is a ConnectionsOption object depending on your respective domain and account data