using Insight.Domain.Interfaces; using Insight.Domain.Network; using Insight.Domain.Network.Agent.Messages; using System.Management; using System.Runtime.Versioning; namespace Insight.Agent.Network.Handlers; [SupportedOSPlatform("windows")] public class UserHandler : IMessageHandler { public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage { switch (message) { case InventoryRequest: { var result = new Collection(); result.AddRange(GetUsers()); await sender.SendAsync(result, cancellationToken); break; } } } private static List GetUsers() { var users = QueryUsers(); var groups = GetGroups(); var usergrouping = QueryUserGroupMaps(); foreach (var u in users) { u.Groups = []; foreach (var ug in usergrouping.Where(ug => ug.UserDomain == u.Domain && ug.UserName == u.Name)) { var grps = groups.Where(g => g.Domain == ug.GroupDomain && g.Name == ug.GroupName); if (grps is not null) { u.Groups.AddRange(grps); } } } return users; } private static List GetGroups() { using var searcher = new ManagementObjectSearcher { Scope = new ManagementScope(@"root\cimv2"), Query = new ObjectQuery("select sid, domain, name, description, localaccount from win32_group") }; if (searcher.TryGet(out var collection) is false) { searcher.Query = new ObjectQuery("select * from win32_group"); if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); } var groups = new List(); using (collection) { foreach (ManagementObject @object in collection.Cast()) { var group = new Group(); var properties = @object.GetPropertyHashes(); group.Sid = @object.GetValue(properties, "sid")?.Trim(); group.Domain = @object.GetValue(properties, "domain")?.Trim(); group.Name = @object.GetValue(properties, "name")?.Trim(); group.Description = @object.GetValue(properties, "description")?.Trim(); group.LocalAccount = @object.GetValue(properties, "localaccount"); groups.Add(group); } } return [.. groups.OrderBy(x => x.Name)]; } private static List QueryUsers() { using var searcher = new ManagementObjectSearcher { Scope = new ManagementScope(@"root\cimv2"), Query = new ObjectQuery("select sid, name, fullname, description, domain, localaccount, disabled, lockout, status, passwordchangeable, passwordexpires, passwordrequired from win32_useraccount") }; if (searcher.TryGet(out var collection) is false) { searcher.Query = new ObjectQuery("select * from win32_useraccount"); if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); } var users = new List(); using (collection) { foreach (ManagementObject @object in collection.Cast()) { var user = new User(); var properties = @object.GetPropertyHashes(); user.Sid = @object.GetValue(properties, "sid")?.Trim(); user.Name = @object.GetValue(properties, "name")?.Trim(); user.FullName = @object.GetValue(properties, "fullname")?.Trim(); user.Description = @object.GetValue(properties, "description")?.Trim(); user.Domain = @object.GetValue(properties, "domain")?.Trim(); user.LocalAccount = @object.GetValue(properties, "localaccount"); user.Disabled = @object.GetValue(properties, "disabled"); user.Lockout = @object.GetValue(properties, "lockout"); user.Status = @object.GetValue(properties, "status")?.Trim(); user.PasswordChangeable = @object.GetValue(properties, "passwordchangeable"); user.PasswordExpires = @object.GetValue(properties, "passwordexpires"); user.PasswordRequired = @object.GetValue(properties, "passwordrequired"); users.Add(user); } } return users; } private static List QueryUserGroupMaps() { using var searcher = new ManagementObjectSearcher { Scope = new ManagementScope(@"root\cimv2"), Query = new ObjectQuery("select groupcomponent, partcomponent from win32_groupuser") }; if (searcher.TryGet(out var collection) is false) { searcher.Query = new ObjectQuery("select * from win32_groupuser"); if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); } var usergroups = new List(); using (collection) { foreach (ManagementObject @object in collection.Cast()) { var usergroup = new UserGroupMap(); var properties = @object.GetPropertyHashes(); var raw = @object.GetValue(properties, "groupcomponent"); var split = raw?.Split(".Domain=")[1]?.Split(",Name="); if (split is not null && split.Length > 1) { usergroup.GroupDomain = split[0].TrimStart('"').TrimEnd('"'); usergroup.GroupName = split[1].TrimStart('"').TrimEnd('"'); } raw = @object.GetValue(properties, "partcomponent"); split = raw?.Split(".Domain=")[1]?.Split(",Name="); if (split is not null && split.Length > 1) { usergroup.UserDomain = split[0].TrimStart('"').TrimEnd('"'); usergroup.UserName = split[1].TrimStart('"').TrimEnd('"'); } usergroups.Add(usergroup); } } return usergroups; } private class UserGroupMap { public string? GroupDomain { get; set; } public string? GroupName { get; set; } public string? UserDomain { get; set; } public string? UserName { get; set; } } }