Elaay Ответов: 1

Запуск WMI-запроса на несколько компьютеров одновременно (C#)


Привет,

Я скопировал несколько сниплетов кода и построил небольшое программное обеспечение, чтобы:

1. запросите все существующие компьютеры в домене
2. запросите каждый компьютер в списке, если определенный пользователь вошел в систему на этом компьютере
3. Заполните Listbox1 всеми компьютерами, на которых этот пользователь вошел в систему

Но, как вы знаете, запрос удаленного WMI действительно невелик... А с сотнями компьютерных объектов в объявлении это может занять до нескольких часов до окончания.

Поэтому мне нужно знать лучший способ, как запустить запрос wmi на 10 или 20 компьютеров одновременно.

textBox1.Text = имя пользователя, которое следует искать
Listbox1 = компьютеры, найденные там, где пользователь вошел в систему
Listbox2 = все компьютеры в ActiveDirectory
Button2 = чтение всех компьютеров из active directory и запись в listbox2
Button1 = начать поиск компьютеров, перечисленных в списке listbox2

Что я уже пробовал:

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;
        }
    }
}

1 Ответов

Рейтинг:
2

Richard Deeming

Предполагая, что вы не заботитесь о порядке элементов в listBox1, некоторые async / await магия может помочь:

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;
    }
}

Задача.Метод WhenAny (System.Нарезание резьбы.Задачи) | Microsoft Docs[^]

NB: С помощью WhenAny будет O(N2) Стивен Тоуб опубликовал более эффективный вариант еще в 2012 году:
Обработка задач по мере их завершения | параллельное программирование с помощью .NET[^]