Posted By

cabrel on 09/14/10


Tagged

remote windows user access WMI querying


Versions (?)

Who likes this?

1 person have marked this snippet as a favorite

Tyster


Querying WMI for local users


 / Published in: C#
 

  1. /// <summary>
  2. /// Returns a list of users on a target machine or machines which could
  3. /// include an additional domain to search in.
  4. /// </summary>
  5. /// <param name="connection"></param>
  6. /// <param name="domain"></param>
  7. /// <param name="hosts"></param>
  8. /// <returns></returns>
  9. public List<string> GetLocalUsers(ConnectionOptions connection, string domain, ConcurrentBag<string> hosts)
  10. {
  11. // For storing any exceptions
  12. var ex = new ConcurrentBag<string>();
  13.  
  14. // Stores our hosts and any groups found on the local machine
  15. var hostCollection = new ConcurrentDictionary<string, string>();
  16.  
  17. // holds any of our results
  18. var results = new ConcurrentBag<string>();
  19.  
  20. // Since there are multiple user groups on each machine
  21. // we want to know them all, so we go and find them
  22. //
  23. // This will search each machine for the groups it contains
  24. // and then store it in our host collection.
  25. foreach (var h in hosts)
  26. {
  27. var groups = RunGetGroups(connection, h);
  28. hostCollection.TryAdd(h, groups);
  29. }
  30.  
  31. // Since we don't know ahead of time how many hosts
  32. // we could have, we want to try to speed this up as
  33. // much as possible.
  34. //
  35. // Parallel.ForEach allows us to iterate over the collection
  36. // and push each iteration into a parallel state, meaning we
  37. // can search a number of machines at once instead of one
  38. // by one.
  39. Parallel.ForEach(hostCollection, col =>
  40. {
  41. var groups = col.Value.Split(',');
  42. var tsafeGroups = new ConcurrentBag<string>(groups);
  43.  
  44. // The same as above but now since we have multiple groups
  45. // per machine we want to make sure we don't get stuck on a
  46. // machine that might have a large number of local groups on it.
  47. Parallel.ForEach(tsafeGroups, group =>
  48. {
  49.  
  50. // This is the formatted string we'll use when we connect to the remote
  51. // machine.
  52. //
  53. // we are telling the future connector that on the given hostname
  54. // we are searching in root\cimv2
  55. var scopeFormat = String.Format("\\\\{0}\\root\\cimv2", col.Key);
  56.  
  57. // This is constructing our clause to only choose user accounts
  58. // that are part of the local computer domain
  59. StringBuilder sb = new StringBuilder("GroupComponent=");
  60. sb.Append('"');
  61. sb.Append("Win32_Group.Domain=");
  62. sb.Append("'");
  63. sb.Append(col.Key);
  64. sb.Append("'");
  65. sb.Append(",Name=");
  66. sb.Append("'");
  67. sb.Append(group);
  68. sb.Append("'");
  69. sb.Append('"');
  70.  
  71. // If user passed in a domain, be sure to include it as well
  72. if (!String.IsNullOrEmpty(domain))
  73. {
  74. sb.Append(" or ");
  75. sb.Append("GroupComponent=");
  76. sb.Append('"');
  77. sb.Append("Win32_Group.Domain=");
  78. sb.Append("'");
  79. sb.Append(domain.ToUpper());
  80. sb.Append("'");
  81. sb.Append(",Name=");
  82. sb.Append("'");
  83. sb.Append(group);
  84. sb.Append("'");
  85. sb.Append('"');
  86. }
  87.  
  88. // I haven't looked to much into it but WMI seems to throw a lot of exceptions
  89. // some are important and some seem to be a by product of cross platform or
  90. // remote querying.
  91. //
  92. // We catch them all anyway and store them but we don't do anything with them here
  93. //
  94. try
  95. {
  96. var scope = new ManagementScope(scopeFormat, connection);
  97.  
  98. // Here is where we apply our condition we built above to the query
  99. var sQuery = new SelectQuery("Win32_GroupUser", sb.ToString());
  100. var searcher = new ManagementObjectSearcher(scope, sQuery);
  101.  
  102. if (searcher != null)
  103. {
  104.  
  105. // Returns our list of objects which match our above SelectQuery
  106. ManagementObjectCollection mObjects = searcher.Get();
  107.  
  108. if (mObjects.Count > 0)
  109. {
  110. foreach (ManagementObject obj in mObjects)
  111. {
  112. var path = new ManagementPath(obj["PartComponent"].ToString());
  113.  
  114. if (path.ClassName == "Win32_UserAccount")
  115. {
  116.  
  117. // The relativepath string looks like this:
  118. // Win32_UserAccount.Domain="DOMAIN",Name="Username"
  119. //
  120. // The domain could be either the local computer name or
  121. // if the user passed in a domain to search for then that
  122. // domain as well
  123. //
  124. // We now have to split it up and pull out the pieces we need
  125. //
  126.  
  127. string[] names = path.RelativePath.Split(',');
  128.  
  129. // the domain
  130. var memberOf = names[0].Substring(names[0].IndexOf("=") + 1).Replace('"', ' ').Trim();
  131.  
  132. // the username
  133. var name = names[1].Substring(names[1].IndexOf("=") + 1).Replace('"', ' ').Trim();
  134.  
  135. // This formats a nice csv string in order of:
  136. // hostname, group name, domain name, username
  137. var output = String.Format("{0},{1},{2},{3}", col.Key, group, memberOf, name);
  138. results.Add(output);
  139. }
  140. }
  141. }
  142. }
  143. }
  144. catch (Exception e1)
  145. {
  146. ex.Add(String.Format("{0}: {1}", col.Key, e1.ToString()));
  147. }
  148. });
  149. });
  150.  
  151. return results.ToList<string>();
  152. }

Report this snippet  

Comments

RSS Icon Subscribe to comments
Posted By: cabrel on November 17, 2010

http://blog.zerklabs.com/2010/09/problem-solving-part-2/

You need to login to post a comment.