1

There is a domain network with are connected computers.

Need a code that will display a list of Active Directory users connected to it now (using them / connected remotely).

Something similar to the "Users" tab in Task Manager, only for a domain network.


I tried to do this with WMI. Classes Win32_LogonSession, Win32_LoggedOnUser, Win32_Account

The principle is this:

From active Win32_LogonSession weeded out LogonType = 2, 10 и 11.
By LogonId from Win32_LoggedOnUser get name and domain, search it in Win32_Account (to weed out system sessions) (Below there will be a code, maybe someone will come in handy)

But I ran into a problem : the event Session_onEnd is triggered far from 100% of cases, and LogOff seems not to be recorded at all, or is recorded incorrectly.

As a result, I get a lot of "hanging" sessions that users connect to, or create new ones when they log in. Analysis of the Windows event log in this regard does not give anything useful either. (LogOff is still incorrect)


So, if I can connect to a computer and get all the information out of it, how to extract - is it in use now and who is using it?

using System;
using System.Collections.Generic;
using System.Data;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Management;
using System.Net;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace UserManager
{
    public partial class LogOnSession : Form
    {
        List<LogOnSessionR> SessionsList = new List<LogOnSessionR>();
        List<LoggedOnUser> LoggedList = new List<LoggedOnUser>();
        List<PC> CompList = new List<PC>();
        public LogOnSession()
        {
            InitializeComponent();
        }

        private void LogOnSession_Load(object sender, EventArgs e)
        {
            if (Form1.SelfRef != null)
            {
                CBDomain.Items.Add("All Forest");
                foreach (object a in Form1.SelfRef.CBDomain.Items)
                {
                    CBDomain.Items.Add(a);
                }
                CBDomain.SelectedIndex = Form1.SelfRef.CBDomain.SelectedIndex;
            }

            GetComputersInDomain(CBDomain.SelectedIndex);
            CBComputers.SelectedIndex = 0;
        }
        private void CBDomain_SelectedIndexChanged(object sender, EventArgs e)
        {
            LogOnListView.Items.Clear();
            GetComputersInDomain(CBDomain.SelectedIndex);
        }
        public void GetComputersInDomain(int I)
        {
            CompList.Clear();
            CBComputers.Items.Clear();
            if (I == 0)
            {
                DirectoryEntry de = new DirectoryEntry();
                DirectorySearcher myADSearcher = new DirectorySearcher(de);
                myADSearcher.Filter = "(&(objectClass=computer))";

                foreach (SearchResult sr in myADSearcher.FindAll())
                {
                    PC pc = new PC();
                    pc.Name = removeCN(sr.GetDirectoryEntry().Name);
                    pc.IP = getPCIP(pc.Name);
                    CompList.Add(pc);
                }
            }
            else
            {
                DirectoryEntry de = new DirectoryEntry("LDAP://" + Form1.ListDomain[I-1].Name);
                DirectorySearcher myADSearcher = new DirectorySearcher(de);
                myADSearcher.Filter = "(&(objectClass=computer))";

                foreach (SearchResult sr in myADSearcher.FindAll())
                {
                    PC pc = new PC();
                    pc.Name = removeCN(sr.GetDirectoryEntry().Name);
                    pc.IP = getPCIP(pc.Name);
                    CompList.Add(pc);
                }
            }
            
            CBComputers.Items.Add("All");
            foreach (PC pc in CompList)
            {
                CBComputers.Items.Add(pc.Name);
            }
        }



        public string removeCN(string str)
        {
            if (str.Contains("CN="))
            {
                return str.Replace("CN=", "");
            }
            else
            {
                return str;
            }
        }
        public string getPCIP(string hostName)
        {
            IPHostEntry hostEntry;

            hostEntry = Dns.GetHostEntry(hostName);

            if (hostEntry.AddressList.Length > 0)
            {
                return hostEntry.AddressList[0].ToString();
                //you might get more than one ip for a hostname since 
                //DNS supports more than one record
            }
            return null;
        }


        private void RefreshL_Click(object sender, EventArgs e)
        {
            ViewResult(getInfo());
        }
        public void ViewResult(List<LogonUser> results)
        {

            LogOnListView.Items.Clear();
            if (results.Count == 0) { return; }
            int i = 0;
            foreach (LogonUser result in results)
            {

                LogOnListView.Items.Add(i.ToString());
                LogOnListView.Items[i].SubItems.Add(result.SamAccountName);
                LogOnListView.Items[i].SubItems.Add(result.FullName);
                LogOnListView.Items[i].SubItems.Add(result.Computer);
                LogOnListView.Items[i].SubItems.Add(result.Domain);
                LogOnListView.Items[i].SubItems.Add(result.StartTime.ToLocalTime().ToString());
                LogOnListView.Items[i].SubItems.Add(cAD.LastLastLogon(getDN(result.SamAccountName)).ToLocalTime().ToString());
                LogOnListView.Items[i].SubItems.Add(cAD.LastLastLogoff(getDN(result.SamAccountName)).ToLocalTime().ToString());
                i++;
            }

        }

        private string getDN(string samAccountName)
        {
            DirectoryEntry myADEntry = new DirectoryEntry();
            DirectorySearcher myADSearcher = new DirectorySearcher(myADEntry);
            myADSearcher.Filter = "(&(objectClass=user)(sAMAccountName=" + samAccountName + ")(!(objectClass=computer)))";
            return myADSearcher.FindOne().GetDirectoryEntry().Properties["distinguishedName"].Value.ToString();
        }

        private List<LogonUser> getInfo()
        {
            List<LogonUser> LogonUserList = new List<LogonUser>();
            ConnectionOptions options;
            options = new ConnectionOptions();

            //options.Username = "administrator";
            //options.Password = "Parol-Admin";
            options.EnablePrivileges = true;
            options.Impersonation = ImpersonationLevel.Impersonate;

            if (CBComputers.SelectedIndex == 0)
            {
                foreach (PC pc in CompList)
                {
                    if (pc.Name == Environment.MachineName)
                    {
                        LogonUserList.AddRange(getLogonUserList(pc, options, LocalWMIRequestLogOnSession(), LocalWMIRequestLoggedOnUser()));
                    }
                    else
                    {
                        LogonUserList.AddRange(getLogonUserList(pc, options, WMIRequestLogOnSession(pc.IP, options), WMIRequestLoggedOnUser(pc.IP, options)));
                    }
                }
            }
            else
            {
                PC pc = CompList[CBComputers.SelectedIndex - 1];
                if (pc.Name == Environment.MachineName)
                {
                    LogonUserList.AddRange(getLogonUserList(pc, options, LocalWMIRequestLogOnSession(), LocalWMIRequestLoggedOnUser()));
                }
                else
                {
                    LogonUserList.AddRange(getLogonUserList(pc, options, WMIRequestLogOnSession(pc.IP, options), WMIRequestLoggedOnUser(pc.IP, options)));
                }
            }
            return LogonUserList;
        }



        private LogonUser FindInDomainController(PC pc, ConnectionOptions options, LoggedOnUser lou, LogOnSessionR losr)
        {
            try
            {
                List<PC> Controllers = new List<PC>();
                if (CBDomain.SelectedIndex == 0)
                {
                    foreach (GlobalCatalog contr in Form1.DsDomain.Forest.GlobalCatalogs)
                    {
                        PC Con = new PC();
                        Con.Name = contr.Name;
                        Con.IP = contr.IPAddress;
                        Controllers.Add(Con);
                    }
                }
                else
                {
                    foreach (DomainController contr in Form1.ListDomain[CBDomain.SelectedIndex - 1].DomainControllers)
                    {
                        PC Con = new PC();
                        Con.Name = contr.Name;
                        Con.IP = contr.IPAddress;
                        Controllers.Add(Con);
                    }

                }
                LogonUser getlg;

                foreach (PC Controller in Controllers)
                {
                    ManagementScope scope;
                    if (Controller.Name == Environment.MachineName)
                    {
                        scope = new ManagementScope("\\root\\cimv2");
                    }
                    else
                    {
                        scope = new ManagementScope("\\\\" + Controller.IP + "\\root\\cimv2", options);
                        scope.Connect(); // 
                    }

                    String queryString = "SELECT * FROM Win32_UserAccount WHERE Domain=\"" + getDomain(lou.Antecedent) + "\" AND Name=\"" + getsAmAccountName(lou.Antecedent) + "\"";

                    ObjectQuery query;
                    query = new ObjectQuery(queryString);

                    ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
                    var Temp = searcher.Get()
                        .Cast<ManagementObject>()
                        .Select(mo => new
                        {
                            Name = Convert.ToString(mo["Name"]),
                            FullName = Convert.ToString(mo["FullName"]),
                            AccountType = Convert.ToUInt32(mo["AccountType"]),
                            Caption = Convert.ToString(mo["Caption"]),
                            Description = Convert.ToString(mo["Description"]),
                            Disabled = Convert.ToBoolean(mo["Disabled"]),
                            Domain = Convert.ToString(mo["Domain"]),
                            InstallDate = Convert.ToDateTime(mo["InstallDate"]),
                            LocalAccount = Convert.ToBoolean(mo["LocalAccount"]),
                            Lockout = Convert.ToBoolean(mo["Lockout"]),
                            PasswordChangeable = Convert.ToBoolean(mo["PasswordChangeable"]),
                            PasswordExpires = Convert.ToBoolean(mo["PasswordExpires"]),
                            PasswordRequired = Convert.ToBoolean(mo["PasswordRequired"]),
                            SID = Convert.ToString(mo["SID"]),
                            SIDType = Convert.ToByte(mo["SIDType"]),
                            Status = Convert.ToString(mo["Status"])
                        }
                        ).ToList();
                    if (Temp.Count == 0) { continue; }
                   // if (Temp.Count > 1) { throw new Exception("Найденно " + Temp.Count + " одинаковых пользователя"); }

                    getlg = new LogonUser()
                    {
                        AuthenticationPackage = losr.AuthenticationPackage,
                        Name = Temp[0].Name,
                        Domain = Temp[0].Domain,
                        Caption = Temp[0].Caption,
                        Description = Temp[0].Description,
                        InstallDate = Temp[0].InstallDate,
                        LogonId = losr.LogonId,
                        LogonType = losr.LogonType,
                        StartTime = losr.StartTime,
                        Status = Temp[0].Status,
                        Computer = pc.Name,
                        SamAccountName = getsAmAccountName(lou.Antecedent),
                        FullName = Temp[0].FullName,
                        AccountType = Temp[0].AccountType,
                        Enabled = !Temp[0].Disabled,
                        LocalAccount = Temp[0].LocalAccount,
                        Lockout = Temp[0].Lockout,
                        PasswordChangeable = Temp[0].PasswordChangeable,
                        PasswordExpires = Temp[0].PasswordExpires,
                        PasswordRequired = Temp[0].PasswordRequired,
                        SID = Temp[0].SID,
                        SIDType = Temp[0].SIDType
                    };

                    return getlg;
                }

                return null;

            }
            catch
            {

            }
            return null;
        }

        public List<LogOnSessionR> LocalWMIRequestLogOnSession()
        {
            List<LogOnSessionR> ReqList = new List<LogOnSessionR>();

            ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2",
                   "SELECT * FROM Win32_LogonSession WHERE LogonType = '2' OR LogonType = '10' OR LogonType = '11'");
            var Temp = searcher.Get()
                .Cast<ManagementObject>()
                .Select(mo => new
                {
                    AuthenticationPackage = Convert.ToString(mo["AuthenticationPackage"]),
                    Name = Convert.ToString(mo["Name"]),
                    Caption = Convert.ToString(mo["Caption"]),
                    Description = Convert.ToString(mo["Description"]),
                    InstallDate = (mo["InstallDate"] == null ? Convert.ToDateTime(mo["InstallDate"]) : ManagementDateTimeConverter.ToDateTime(mo["InstallDate"].ToString())),
                    LogonId = Convert.ToString(mo["LogonId"]),
                    LogonType = Convert.ToUInt32(mo["LogonType"]),
                    StartTime = (mo["StartTime"] == null ? Convert.ToDateTime(mo["StartTime"]) : ManagementDateTimeConverter.ToDateTime(mo["StartTime"].ToString())),
                    Status = Convert.ToString(mo["Status"])
                }
                ).ToList();

            foreach (var obj in Temp)
            {
                LogOnSessionR req = new LogOnSessionR();
                req.AuthenticationPackage = obj.AuthenticationPackage;
                req.Name = obj.Name;
                req.Caption = obj.Caption;
                req.Description = obj.Description;
                req.InstallDate = obj.InstallDate;
                req.LogonId = obj.LogonId;
                req.LogonType = obj.LogonType;
                req.StartTime = obj.StartTime;
                req.Status = obj.Status;
                ReqList.Add(req);
            }


            return ReqList;
        }
        public List<LoggedOnUser> LocalWMIRequestLoggedOnUser()
        {
            List<LoggedOnUser> ReqList = new List<LoggedOnUser>();

            ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2",
                   "SELECT * FROM Win32_LoggedOnUser");
            var Temp = searcher.Get()
                .Cast<ManagementObject>()
                .Select(mo => new
                {
                    Antecedent = Convert.ToString(mo["Antecedent"]),
                    Dependent = Convert.ToString(mo["Dependent"])
                }
                ).ToList();

            foreach (var obj in Temp)
            {
                LoggedOnUser req = new LoggedOnUser();
                req.Antecedent = obj.Antecedent;
                req.Dependent = obj.Dependent;
                ReqList.Add(req);
            }


            return ReqList;
        }




        private string getLogonId(string dependent)
        {
            var start = "LogonId=\"";
            var end = "\"";
            var regEx = new Regex(String.Format("{0}(.*){1}", Regex.Escape(start), Regex.Escape(end)));
            var match = regEx.Match(dependent);
            return match.Groups[1].Value;
            // "\\\\.\\root\\cimv2:Win32_LogonSession.LogonId=\"997\""
        }
        private string getDomain(string antecedent)
        {
            var start = "Domain=\"";
            var end = "\",";
            var regEx = new Regex(String.Format("{0}(.*){1}", Regex.Escape(start), Regex.Escape(end)));
            var match = regEx.Match(antecedent);
            return match.Groups[1].Value;
            // "\\\\.\\root\\cimv2:Win32_Account.Domain=\"LAB\" AND Name=\"Administrator\""
        }
        private string getsAmAccountName(string antecedent)
        {
            var start = "Name=\"";
            var end = "\"";
            var regEx = new Regex(String.Format("{0}(.*){1}", Regex.Escape(start), Regex.Escape(end)));
            var match = regEx.Match(antecedent);
            return match.Groups[1].Value;
            // 
        }




        private List<LogonUser> getLogonUserList(PC pc, ConnectionOptions options, List<LogOnSessionR> sessionsList, List<LoggedOnUser> loggedList)
        {
            List<LogonUser> getList = new List<LogonUser>();

            foreach (LoggedOnUser lou in loggedList)
            {
                foreach(LogOnSessionR losr in sessionsList)
                {
                    if (losr.LogonId == getLogonId(lou.Dependent))
                    {
                        LogonUser temp = FindInDomainController(pc, options, lou, losr);
                        if (temp != null)
                        {
                            getList.Add(temp);
                        }
                    }
                }
            }
            return getList;
        }
        public List<LogOnSessionR> WMIRequestLogOnSession(string ip, ConnectionOptions options)
        {
            List<LogOnSessionR> ReqList = new List<LogOnSessionR>();

            try
            {
                ManagementScope scope;
                scope = new ManagementScope("\\\\" + ip + "\\root\\cimv2", options);
                scope.Connect();

                String queryString = "SELECT * FROM Win32_LogonSession WHERE LogonType = '2' OR LogonType = '10' OR LogonType = '11'";

                ObjectQuery query;
                query = new ObjectQuery(queryString);

                ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
                var Temp = searcher.Get()
                    .Cast<ManagementObject>()
                    .Select(mo => new
                    {
                        AuthenticationPackage = Convert.ToString(mo["AuthenticationPackage"]),
                        Name = Convert.ToString(mo["Name"]),
                        Caption = Convert.ToString(mo["Caption"]),
                        Description = Convert.ToString(mo["Description"]),
                        InstallDate = (mo["InstallDate"] == null ? Convert.ToDateTime(mo["InstallDate"]) : ManagementDateTimeConverter.ToDateTime(mo["InstallDate"].ToString())),
                        LogonId = Convert.ToString(mo["LogonId"]),
                        LogonType = Convert.ToUInt32(mo["LogonType"]),
                        StartTime = (mo["StartTime"] == null ? Convert.ToDateTime(mo["StartTime"]) : ManagementDateTimeConverter.ToDateTime(mo["StartTime"].ToString())),
                        Status = Convert.ToString(mo["Status"])
                    }
                    ).ToList();

                foreach (var obj in Temp)
                {
                    LogOnSessionR req = new LogOnSessionR();
                    req.AuthenticationPackage = obj.AuthenticationPackage;
                    req.Name = obj.Name;
                    req.Caption = obj.Caption;
                    req.Description = obj.Description;
                    req.InstallDate = obj.InstallDate;
                    req.LogonId = obj.LogonId;
                    req.LogonType = obj.LogonType;
                    req.StartTime = obj.StartTime;
                    req.Status = obj.Status;
                    ReqList.Add(req);
                }
                return ReqList;
            }
            catch
            {

            }


            return new List<LogOnSessionR>();
        }
        public List<LoggedOnUser> WMIRequestLoggedOnUser(string ip, ConnectionOptions options)
        {
            List<LoggedOnUser> ReqList = new List<LoggedOnUser>();

            try
            {
                ManagementScope scope;
                scope = new ManagementScope("\\\\" + ip + "\\root\\cimv2", options);
                scope.Connect();

                String queryString = "SELECT * FROM Win32_LoggedOnUser";

                ObjectQuery query;
                query = new ObjectQuery(queryString);

                ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
                var Temp = searcher.Get()
                    .Cast<ManagementObject>()
                    .Select(mo => new
                    {
                        Antecedent = Convert.ToString(mo["Antecedent"]),
                        Dependent = Convert.ToString(mo["Dependent"])
                    }
                    ).ToList();

                foreach (var obj in Temp)
                {
                    LoggedOnUser req = new LoggedOnUser();
                    req.Antecedent = obj.Antecedent;
                    req.Dependent = obj.Dependent;
                    ReqList.Add(req);
                }
                return ReqList;
            }
            catch
            {
                
            }


            return new List<LoggedOnUser>();
        }



        private void label2_Click(object sender, EventArgs e)
        {

        }
    }
    public class PC
    {
        public string Name { get; set; }
        public string IP { get; set; }

    }
    public class LoggedOnUser
    {
        public string Antecedent { get; set; }
        public string Dependent  { get; set; }

    }
    public class LogOnSessionR
    {
        public string AuthenticationPackage { get; set; }
        public string Name { get; set; }
        public string Caption { get; set; }
        public string Description { get; set; }
        public System.DateTime InstallDate { get; set; }
        public string LogonId { get; set; }
        public UInt32 LogonType { get; set; }
        public System.DateTime StartTime { get; set; }
        public string Status { get; set; }

    }
    public class LogonUser
    {
        public string AuthenticationPackage { get; set; }
        public string Name { get; set; }
        public string Domain { get; set; }
        public string Caption { get; set; }
        public string Description { get; set; }
        public System.DateTime InstallDate { get; set; }
        public string LogonId { get; set; }
        public UInt32 LogonType { get; set; }
        public System.DateTime StartTime { get; set; }
        public string Status { get; set; }
        public string Computer { get; set; }
        public string SamAccountName { get; set; }
        public string FullName { get; set; }
        public uint AccountType { get; set; }
        public bool? Enabled { get; set; }
        public bool LocalAccount { get; set; }
        public bool Lockout { get; set; }
        public bool PasswordChangeable { get; set; }
        public bool PasswordExpires { get; set; }
        public bool PasswordRequired { get; set; }
        public string SID { get; set; }
        public byte SIDType { get; set; }
    }
}
Tikey
  • 13
  • 3

1 Answers1

0

If you can connect to any computer in your domain network and get any info from it - this is security issue, that must be solved.

First of all, you must understand a security problem of your solution. Any computer than you can connect to may be attacked by hacker. There are similar precedents in my experience.

So, if you need to get any info from computer or server in your domain network - you must install some agent on every computer and server, where you want to get internal data of it state. This agent will be monitor computer/server by your rule sets and send information to some database or collecting system.

Microsoft has System Center Operations Manager with this architecture and purpose. You can develop own agents, or use powershell scrips + windows scheduler to collect any data from computer.

Do not implement your solution in domain network - it's bad. A better solution is to check which computers are included in the domain and which have agents from the monitoring database. And install agents on those computers on which they do not yet exist.

Any user account or group, that has a lot of rignts on domain objects (for example, all computers) - is security issue, that must be solved.

If you want to get any logged on users - you can check process explorer.exe - which user starts it.

So, if you use powershell script as agent to collect data, you can run

query user

It will display, for expample:

user |seance    |ID |Staus  |Idle time | logon time     |
-----|----------|---|-------|----------|----------------|
user1|rdp-tcp   |2  |Active | .        |12/07/2020 10:20|

then you can store this data in you database, or another storage.

If you want to develop some agent, you can use Windows API, System.Runtime.InteropServices, like this, because your agent will can access this API.

Also, you can get users, which logged on computer by this

    foreach (System.Management.ManagementObject Process in Processes.Get())
{
    if (Process["ExecutablePath"] != null && 
        System.IO.Path.GetFileName(Process["ExecutablePath"].ToString()).ToLower() == "explorer.exe" )
    {
        string[] OwnerInfo = new string[2];
        Process.InvokeMethod("GetOwner", (object[])OwnerInfo);

        Console.WriteLine(string.Format("Windows Logged-in Interactive UserName={0}", OwnerInfo[0]));

        break;
    }
}

Every user start process explorer.exe, and own it.

Also, you not need to store any sp

Maxim
  • 854
  • 1
  • 8
  • 16