Click here to Skip to main content
15,886,578 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Hello,

I've copied some code sniplets and build a small software to:

1. Query all existiing Computers in Domain
2. Query each Computer in the list if a defined user is logged in on this computer
3. Fill Listbox1 with all computers where this user is logged in

But as you know, querying remote WMI is really small... And with hundreds of computer objects in the AD this can take up to hours until finishing.

So I need to know the best way, how to fire up the wmi query to 10 or 20 computers at the same time.

textBox1.Text = Username which should be searched
Listbox1 = Computers found where the User is logged in
Listbox2 = All Computers in the ActiveDirectory
Button2 = Read all Computers from active directory and write to listbox2
Button1 = Beginn searching the computers listed in listbox2

What I have tried:

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Management;
using System.Text.RegularExpressions;
using System.DirectoryServices;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public static string serverName;
        public static string searchUser;
        public static int computerlist = 0;
        public static int mycounter = 0;

        private void button1_Click(object sender, EventArgs e)
        {
            searchUser = textBox1.Text;
            do
            {
                serverName = listBox2.Items[mycounter].ToString();
                foreach (var user in GetLoggedUser(serverName))
                {
                    listBox1.Items.Add(serverName + " - " + user);
                }
                label2.Text = "Quering: " + serverName;
                mycounter++;
            }
            while (mycounter < computerlist);
        }

        private List<string> GetLoggedUser(string serverName)
        {
            int mycounter = 0;
            string founduser;
            List<string> users = new List<string>();
            try
            {
                var scope = GetManagementScope(serverName);
                scope.Connect();
                var Query = new SelectQuery("SELECT LogonId FROM Win32_LogonSession Where LogonType=2");
                var Searcher = new ManagementObjectSearcher(scope, Query);
                var regName = new Regex(@"(?<=Name="").*(?="")");

                foreach (ManagementObject WmiObject in Searcher.Get())
                {
                    if (mycounter == 0)
                    {
                        foreach (ManagementObject LWmiObject in WmiObject.GetRelationships("Win32_LoggedOnUser"))
                        {
                            founduser = regName.Match(LWmiObject["Antecedent"].ToString()).Value;
                            if (founduser.ToLower() == searchUser.ToLower())
                            {
                                users.Add(founduser);
                                mycounter = 1;
                                break;
                            }
                            else
                            {
                                // Nothing
                            }
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                users.Add(ex.Message);
            }
            return users;
        }

        private static ManagementScope GetManagementScope(string serverName)
        {
            ManagementScope Scope;

            if (serverName.Equals("localhost", StringComparison.OrdinalIgnoreCase))
                Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", "."), GetConnectionOptions());
            else
            {
                Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", serverName), GetConnectionOptions());
            }
            return Scope;
        }

        private static ConnectionOptions GetConnectionOptions()
        {
            var connection = new ConnectionOptions
            {
                EnablePrivileges = true,
                Authentication = AuthenticationLevel.PacketPrivacy,
                Impersonation = ImpersonationLevel.Impersonate,
            };
            return connection;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            List<string> computerNames = new List<string>();

            using (DirectoryEntry entry = new DirectoryEntry("LDAP://My LDAP Domain"))
            {
                using (DirectorySearcher mySearcher = new DirectorySearcher(entry))
                {
                    mySearcher.Filter = ("(objectClass=computer)");
                    mySearcher.SizeLimit = 0;
                    mySearcher.PageSize = 250;
                    mySearcher.PropertiesToLoad.Add("name");
                    foreach (SearchResult resEnt in mySearcher.FindAll())
                    {
                        if (resEnt.Properties["name"].Count > 0)
                        {
                            string computerName = (string)resEnt.Properties["name"][0];
                            listBox2.Items.Add(computerName);
                        }
                    }
                }
            }
            label3.Text = "Found " + listBox2.Items.Count.ToString() + " Computer Objects";
            button1.Enabled = true;
            computerlist = listBox2.Items.Count;
        }
    }
}
Posted
Updated 13-Sep-18 7:12am
v2

1 solution

Assuming you don't care about the order of items in listBox1, some async / await magic might help:
C#
private async void button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false;
    try
    {
        searchUser = textBox1.Text;
        
        // Get the list of servers to search:
        List<string> serversToSearch = listBox1.Items.Select(i => i.ToString()).ToList();
        
        // Start a Task to query each server on a thread-pool thread:
        List<Task<List<string>>> tasks = serversToSearch.Select(serverName => Task.Run(() => GetLoggedUser(serverName))).ToList();
        
        while (tasks.Count != 0)
        {
            // Wait for the first task to complete, and remove it from the list:
            Task<List<string>> completedTask = await Task.WhenAny(tasks);
            tasks.Remove(completedTask);
            
            // Process the results from that task:
            List<string> users = await completedTask;
            foreach (string user in users)
            {
                listBox1.Items.Add(serverName + " - " + user);
            }
        }
    }
    finally
    {
        button1.Enabled = true;
    }
}

Task.WhenAny Method (System.Threading.Tasks) | Microsoft Docs[^]

NB: Using WhenAny will be O(N2). Stephen Toub posted a more efficient option back in 2012:
Processing tasks as they complete | Parallel Programming with .NET[^]
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900