C# 如何在远程机器上获取登录用户的状态

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14212155/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:04:20  来源:igfitidea点击:

how to get logged on users with their status on remote machine

c#wmi

提问by user1130336

I'm looking for a way to get the users that are logged in on a remote machine. I would love to know if they are logged on localy or remotely, but most of all I MUST know their status. I saw some answers on the net that are written in VB, but I need it in c#. the solution given in markdmak answer hereis looking like a good start, but it's in VB and it looks for remote sessions only. I have this piece of code, which can be a start, but I would like to couple the LogonId to a username and to see its status:

我正在寻找一种方法来获取在远程计算机上登录的用户。我很想知道他们是本地登录还是远程登录,但最重要的是我必须知道他们的状态。我在网上看到一些用 VB 编写的答案,但我需要用 c# 编写。此处的 markdmak 答案中给出的解决方案看起来是一个好的开始,但它在 VB 中并且仅查找远程会话。我有这段代码,可以作为一个开始,但我想将 LogonId 与用户名结合起来并查看其状态:

string fqdn = ""; // set!!!    
ConnectionOptions options = new ConnectionOptions();
options.EnablePrivileges = true;
// To connect to the remote computer using a different account, specify these values:
// these are needed in dev environment
options.Username = ConfigurationManager.AppSettings["KerberosImpersonationUser"];
options.Password = ConfigurationManager.AppSettings["KerberosImpersonationPassword"];
options.Authority = "ntlmdomain:" + ConfigurationManager.AppSettings["KerberosImpersonationDomain"];

ManagementScope scope = new ManagementScope("\\" + fqdn + "\root\CIMV2", options);
try
{
    scope.Connect();
}
catch (Exception ex)
{
    if (ex.Message.StartsWith("The RPC server is unavailable"))
    {
        // The Remote Procedure Call server is unavailable
        // cannot check for logged on users
        return false;
    }
    else
    {
        throw ex;
    }
}

SelectQuery query = new SelectQuery("Select * from Win32_LogonSession");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection results = searcher.Get();
bool returnVal = false;
foreach (ManagementObject os in results)
{
    try
    {
        if (os.GetPropertyValue("LogonId").ToString() != null && os.GetPropertyValue("LogonId").ToString() != "")
        {
            returnVal = true;
        }
    }
    catch (NullReferenceException)
    {
        continue;
    }
}
return returnVal;
}

What I really need and can't find, is a way of getting ALL users on a remote machine AND their status, meaning: Active, Disconnected, Logged-off, etc.

我真正需要但找不到的是一种让远程机器上的所有用户及其状态的方法,意思是:活动、断开连接、注销等。

采纳答案by RRUZ

You can use the Win32_LogonSessionWMI class filtering for the LogonTypeproperty with the value 2 (Interactive)

您可以对值为 2(交互式)Win32_LogonSessionLogonType属性使用WMI 类过滤

Try this sample

试试这个样本

using System;
using System.Collections.Generic;
using System.Management;
using System.Text;

namespace GetWMI_Info
{
class Program
{

    static void Main(string[] args)
    {
        try
        {
            string ComputerName = "remote-machine";
            ManagementScope Scope;

            if (!ComputerName.Equals("localhost", StringComparison.OrdinalIgnoreCase))
            {
                ConnectionOptions Conn = new ConnectionOptions();
                Conn.Username = "username";
                Conn.Password = "password";
                Conn.Authority = "ntlmdomain:DOMAIN";
                Scope = new ManagementScope(String.Format("\\{0}\root\CIMV2", ComputerName), Conn);
            }
            else
                Scope = new ManagementScope(String.Format("\\{0}\root\CIMV2", ComputerName), null);

            Scope.Connect();
            ObjectQuery Query = new ObjectQuery("SELECT LogonId  FROM Win32_LogonSession Where LogonType=2");
            ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);

            foreach (ManagementObject WmiObject in Searcher.Get())
            {
                Console.WriteLine("{0,-35} {1,-40}", "LogonId", WmiObject["LogonId"]);// String
                ObjectQuery LQuery = new ObjectQuery("Associators of {Win32_LogonSession.LogonId=" + WmiObject["LogonId"] + "} Where AssocClass=Win32_LoggedOnUser Role=Dependent");
                ManagementObjectSearcher LSearcher = new ManagementObjectSearcher(Scope, LQuery);
                foreach (ManagementObject LWmiObject in LSearcher.Get())
                {
                    Console.WriteLine("{0,-35} {1,-40}", "Name", LWmiObject["Name"]);                    
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(String.Format("Exception {0} Trace {1}", e.Message, e.StackTrace));
        }
        Console.WriteLine("Press Enter to exit");
        Console.Read();
    }
}
}

回答by Guish

@RRUZ got me started but the Associatorsquery did not work on remote machine with a lot of Win32_LoggedOnUserobjects (don't know why). No results were returned.

@RRUZ 让我开始了,但Associators查询在有很多Win32_LoggedOnUser对象的远程机器上不起作用(不知道为什么)。没有返回任何结果。

I also needed remote Desktop sessions so I used LogonType "10" sessions and my ConnectionOptionswere differents

我还需要远程桌面会话,所以我使用了 LogonType "10" 会话,我ConnectionOptions的不同之处

I replaced the Associators query with WmiObject.GetRelationships("Win32_LoggedOnUser")and the speed increases by a lot and results were there.

我替换了 Associators 查询,WmiObject.GetRelationships("Win32_LoggedOnUser")速度提高了很多,结果就在那里。

    private void btnUnleash_Click(object sender, EventArgs e)
    {
        string serverName = "serverName";
        foreach (var user in GetLoggedUser(serverName))
        {
            dataGridView1.Rows.Add(serverName, user);
        }            
    }   

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

            foreach (ManagementObject WmiObject in Searcher.Get())
            {
                foreach (ManagementObject LWmiObject in WmiObject.GetRelationships("Win32_LoggedOnUser"))
                {
                    users.Add(regName.Match(LWmiObject["Antecedent"].ToString()).Value);
                }
            }
        }
        catch (Exception ex)
        {
            users.Add(ex.Message);
        }

        return users;
    }

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

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

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