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; } /// /// Compare all Disco devices' assigned users against the AD computer managedBy field. /// Only considers active (not decommissioned) devices with a domain ID. /// public DeviceComparisonSummary CompareAllDevices() { var summary = new DeviceComparisonSummary(); // Load active devices that have a domain computer account var devices = database.Devices .Include("AssignedUser") .Where(d => d.DeviceDomainId != null && d.DecommissionedDate == null) .ToList(); summary.TotalDevices = devices.Count; foreach (var device in devices) { var result = CompareDevice(device); summary.Results.Add(result); } summary.DevicesWithAssignment = summary.Results.Count(r => r.HasAssignment); summary.DevicesNotInAD = summary.Results.Count(r => !r.FoundInAD); summary.DevicesMatched = summary.Results.Count(r => r.IsMatch); summary.DevicesMismatched = summary.Results.Count(r => !r.IsMatch && r.FoundInAD); summary.DevicesNoAssignment = summary.Results.Count(r => !r.HasAssignment); summary.DevicesNoManagedBy = summary.Results.Count(r => r.FoundInAD && !r.HasManagedBy); summary.DevicesADDisabled = summary.Results.Count(r => r.ADAccountDisabled); return summary; } /// /// Compare a single device's Disco assignment against AD managedBy. /// public DeviceComparisonResult CompareDevice(Device device) { var result = new DeviceComparisonResult { SerialNumber = device.SerialNumber, DeviceDomainId = device.DeviceDomainId, ComputerName = device.ComputerName, DiscoAssignedUserId = device.AssignedUserId, DiscoAssignedUserDisplayName = device.AssignedUser?.DisplayName, HasAssignment = !string.IsNullOrEmpty(device.AssignedUserId) }; try { // Look up the computer in AD, requesting the managedBy attribute 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; // Get the managedBy DN from AD var managedByDN = adAccount.GetPropertyValue("managedBy"); result.ADManagedByDN = managedByDN; result.HasManagedBy = !string.IsNullOrEmpty(managedByDN); // Resolve managedBy DN to a DOMAIN\username if (result.HasManagedBy) { try { var managedByUser = ActiveDirectory.RetrieveADUserAccount(managedByDN); if (managedByUser != null) { result.ADManagedByUserId = managedByUser.Id; result.ADManagedByDisplayName = managedByUser.DisplayName; } else { result.ADManagedByUserId = managedByDN; // fallback to DN } } catch { // If we can't resolve the DN, store it raw result.ADManagedByUserId = managedByDN; } } // Now compare result.IsMatch = DetermineMatch(result); if (!result.IsMatch) { result.MismatchReason = DetermineMismatchReason(result); } } catch (Exception ex) { result.FoundInAD = false; result.MismatchReason = $"AD lookup error: {ex.Message}"; } return result; } /// /// Determine if the Disco assignment matches the AD managedBy. /// private bool DetermineMatch(DeviceComparisonResult result) { // Both empty = match (neither has an assignment) if (!result.HasAssignment && !result.HasManagedBy) return true; // One has assignment, other doesn't = mismatch if (result.HasAssignment != result.HasManagedBy) return false; // Both have values - compare the user IDs (case-insensitive) return string.Equals( result.DiscoAssignedUserId, result.ADManagedByUserId, StringComparison.OrdinalIgnoreCase); } /// /// Generate a human-readable reason for the mismatch. /// private string DetermineMismatchReason(DeviceComparisonResult result) { 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 "Not assigned in Disco but AD managedBy is set"; if (result.HasAssignment && result.HasManagedBy) return $"Different users: Disco={result.DiscoAssignedUserId}, AD managedBy={result.ADManagedByUserId}"; return "Unknown mismatch"; } } }