Revision: 31823
Initial Code
Initial URL
Initial Description
Initial Title
Initial Tags
Initial Language
at September 14, 2010 10:05 by cabrel
Initial Code
/// <summary> /// Returns a list of users on a target machine or machines which could /// include an additional domain to search in. /// </summary> /// <param name="connection"></param> /// <param name="domain"></param> /// <param name="hosts"></param> /// <returns></returns> public List<string> GetLocalUsers(ConnectionOptions connection, string domain, ConcurrentBag<string> hosts) { // For storing any exceptions var ex = new ConcurrentBag<string>(); // Stores our hosts and any groups found on the local machine var hostCollection = new ConcurrentDictionary<string, string>(); // holds any of our results var results = new ConcurrentBag<string>(); // Since there are multiple user groups on each machine // we want to know them all, so we go and find them // // This will search each machine for the groups it contains // and then store it in our host collection. foreach (var h in hosts) { var groups = RunGetGroups(connection, h); hostCollection.TryAdd(h, groups); } // Since we don't know ahead of time how many hosts // we could have, we want to try to speed this up as // much as possible. // // Parallel.ForEach allows us to iterate over the collection // and push each iteration into a parallel state, meaning we // can search a number of machines at once instead of one // by one. Parallel.ForEach(hostCollection, col => { var groups = col.Value.Split(','); var tsafeGroups = new ConcurrentBag<string>(groups); // The same as above but now since we have multiple groups // per machine we want to make sure we don't get stuck on a // machine that might have a large number of local groups on it. Parallel.ForEach(tsafeGroups, group => { // This is the formatted string we'll use when we connect to the remote // machine. // // we are telling the future connector that on the given hostname // we are searching in root\cimv2 var scopeFormat = String.Format("\\\\{0}\\root\\cimv2", col.Key); // This is constructing our clause to only choose user accounts // that are part of the local computer domain StringBuilder sb = new StringBuilder("GroupComponent="); sb.Append('"'); sb.Append("Win32_Group.Domain="); sb.Append("'"); sb.Append(col.Key); sb.Append("'"); sb.Append(",Name="); sb.Append("'"); sb.Append(group); sb.Append("'"); sb.Append('"'); // If user passed in a domain, be sure to include it as well if (!String.IsNullOrEmpty(domain)) { sb.Append(" or "); sb.Append("GroupComponent="); sb.Append('"'); sb.Append("Win32_Group.Domain="); sb.Append("'"); sb.Append(domain.ToUpper()); sb.Append("'"); sb.Append(",Name="); sb.Append("'"); sb.Append(group); sb.Append("'"); sb.Append('"'); } // I haven't looked to much into it but WMI seems to throw a lot of exceptions // some are important and some seem to be a by product of cross platform or // remote querying. // // We catch them all anyway and store them but we don't do anything with them here // try { var scope = new ManagementScope(scopeFormat, connection); // Here is where we apply our condition we built above to the query var sQuery = new SelectQuery("Win32_GroupUser", sb.ToString()); var searcher = new ManagementObjectSearcher(scope, sQuery); if (searcher != null) { // Returns our list of objects which match our above SelectQuery ManagementObjectCollection mObjects = searcher.Get(); if (mObjects.Count > 0) { foreach (ManagementObject obj in mObjects) { var path = new ManagementPath(obj["PartComponent"].ToString()); if (path.ClassName == "Win32_UserAccount") { // The relativepath string looks like this: // Win32_UserAccount.Domain="DOMAIN",Name="Username" // // The domain could be either the local computer name or // if the user passed in a domain to search for then that // domain as well // // We now have to split it up and pull out the pieces we need // string[] names = path.RelativePath.Split(','); // the domain var memberOf = names[0].Substring(names[0].IndexOf("=") + 1).Replace('"', ' ').Trim(); // the username var name = names[1].Substring(names[1].IndexOf("=") + 1).Replace('"', ' ').Trim(); // This formats a nice csv string in order of: // hostname, group name, domain name, username var output = String.Format("{0},{1},{2},{3}", col.Key, group, memberOf, name); results.Add(output); } } } } } catch (Exception e1) { ex.Add(String.Format("{0}: {1}", col.Key, e1.ToString())); } }); }); return results.ToList<string>(); }
Initial URL
Initial Description
Initial Title
Querying WMI for local users
Initial Tags
windows, user
Initial Language
C#