using Disco.Data.Repository; using Disco.Models.Repository; using Disco.Plugins.ADCompare.Models; using Disco.Services.Interop.ActiveDirectory; using System; using System.Collections.Generic; using System.Linq; namespace Disco.Plugins.ADCompare.Features { public class DeviceCompareService { private readonly DiscoDataContext database; public DeviceCompareService(DiscoDataContext database) { this.database = database; } public DeviceComparisonSummary CompareAllDevices() { var summary = new DeviceComparisonSummary(); var devices = database.Devices .Include("AssignedUser") .Where(d => d.DeviceDomainId != null && d.DecommissionedDate == null) .ToList(); // Only process devices with a valid DOMAIN\ComputerName format var validDevices = devices.Where(d => d.DeviceDomainId.Contains("\\")).ToList(); summary.TotalDevices = validDevices.Count; summary.SkippedDevices = devices.Count - validDevices.Count; foreach (var device in validDevices) { var result = CompareDevice(device); // Skip devices not found in AD - only keep ones we can actually compare if (!result.FoundInAD) { summary.DevicesNotInAD++; continue; } summary.Results.Add(result); } summary.DevicesWithAssignment = summary.Results.Count(r => r.HasAssignment); summary.DevicesMatched = summary.Results.Count(r => r.IsMatch); summary.DevicesMismatched = summary.Results.Count(r => !r.IsMatch); summary.DevicesNoAssignment = summary.Results.Count(r => !r.HasAssignment); summary.DevicesNoManagedBy = summary.Results.Count(r => !r.HasManagedBy); summary.DevicesADDisabled = summary.Results.Count(r => r.ADAccountDisabled); return summary; } public DeviceComparisonResult CompareDevice(Device device) { var result = new DeviceComparisonResult(); result.SerialNumber = device.SerialNumber; result.DeviceDomainId = device.DeviceDomainId; result.ComputerName = device.ComputerName; result.DiscoAssignedUserId = device.AssignedUserId; result.DiscoAssignedUserDisplayName = device.AssignedUser != null ? device.AssignedUser.DisplayName : null; result.HasAssignment = !string.IsNullOrEmpty(device.AssignedUserId); try { var adAccount = ActiveDirectory.RetrieveADMachineAccount(device.DeviceDomainId, new[] { "managedBy" }); if (adAccount == null) { result.FoundInAD = false; result.MismatchReason = "Computer not found in AD"; return result; } result.FoundInAD = true; result.ADAccountDisabled = adAccount.IsDisabled; var managedByDN = adAccount.GetPropertyValue("managedBy"); result.ADManagedByDN = managedByDN; result.HasManagedBy = !string.IsNullOrEmpty(managedByDN); if (result.HasManagedBy) { result.ADManagedByDisplayName = ExtractCNFromDN(managedByDN); } string assignedUserDN = null; if (result.HasAssignment) { try { var assignedUserAD = ActiveDirectory.RetrieveADUserAccount(device.AssignedUserId); if (assignedUserAD != null) { assignedUserDN = assignedUserAD.DistinguishedName; result.ADManagedByUserId = device.AssignedUserId; } } catch { } } if (!result.HasAssignment && !result.HasManagedBy) { result.IsMatch = true; } else if (result.HasAssignment && result.HasManagedBy && assignedUserDN != null) { result.IsMatch = string.Equals(assignedUserDN, managedByDN, StringComparison.OrdinalIgnoreCase); if (result.IsMatch) { result.ADManagedByUserId = device.AssignedUserId; } } else { result.IsMatch = false; } if (!result.IsMatch) { result.MismatchReason = DetermineMismatchReason(result, assignedUserDN); } } catch (Exception ex) { result.FoundInAD = false; result.MismatchReason = "AD lookup error: " + ex.Message; } return result; } private string DetermineMismatchReason(DeviceComparisonResult result, string assignedUserDN) { if (!result.FoundInAD) return "Computer not found in AD"; if (result.HasAssignment && !result.HasManagedBy) return "Assigned in Disco but AD managedBy is empty"; if (!result.HasAssignment && result.HasManagedBy) return string.Format("Not assigned in Disco but AD managedBy is set to {0}", ExtractCNFromDN(result.ADManagedByDN)); if (result.HasAssignment && result.HasManagedBy) { var managedByName = ExtractCNFromDN(result.ADManagedByDN); return string.Format("Different users: Disco={0} ({1}), AD managedBy={2}", result.DiscoAssignedUserId, result.DiscoAssignedUserDisplayName ?? "?", managedByName); } return "Unknown mismatch"; } private string ExtractCNFromDN(string dn) { if (string.IsNullOrEmpty(dn)) return null; if (dn.StartsWith("CN=", StringComparison.OrdinalIgnoreCase)) { var commaIndex = dn.IndexOf(','); if (commaIndex > 3) return dn.Substring(3, commaIndex - 3); return dn.Substring(3); } return dn; } } }