同时向多台计算机发送WMI查询(C#) [英] Fire WMI query to multiple computer at the same time (C#)

查看:72
本文介绍了同时向多台计算机发送WMI查询(C#)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,



我复制了一些代码片段并构建了一个小软件:



1.查询域中所有现有计算机

2.如果已定义的用户在此计算机上登录,则查询列表中的每台计算机

3.使用所有计算机填写Listbox1此用户登录的位置



但是如您所知,查询远程WMI非常小......而且AD中有数百个计算机对象,这可能会占用几个小时,直到完成。



所以我需要知道最好的方法,如何同时启动wmi查询到10或20台计算机。



textBox1.Text =应搜索的用户名

Listbox1 =找到用户登录的计算机

Listbox2 = All ActiveDirectory中的计算机

Button2 =从活动目录中读取所有计算机并写入listbox2

Button1 =开始搜索listbox2中列出的计算机



我尝试过:



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:

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

推荐答案

假设你不关心物品的顺序在 listBox1 中,某些 async / await magic可能会有所帮助:

Assuming you don't care about the order of items in listBox1, some async / await magic might help:
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方法(System.Threading.Tasks)| Microsoft Docs [ ^ ]



注意:使用 WhenAny 将是 O(N 2 。 Stephen Toub在2012年发布了一个更有效的选择:

完成处理任务|使用.NET并行编程 [ ^ ]


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[^]


这篇关于同时向多台计算机发送WMI查询(C#)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆