Feature #49: Active Directory Managed Groups
Document Template Attachments, Device Batches, Device Profiles and User Flags can be associated with an Active Directory group. This AD group is then automatically synchronized with relevant User/Machine accounts. Contains various other UI tweaks and configuration enhancements.
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Logging;
|
||||
using Disco.Services.Tasks;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADNetworkLogonDatesUpdateTask : ScheduledTask
|
||||
{
|
||||
public override string TaskName { get { return "Active Directory - Update Last Network Logon Dates Task"; } }
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
// ADNetworkLogonDatesUpdateTask @ 11:30pm
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().
|
||||
WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(23, 30));
|
||||
|
||||
this.ScheduleTask(triggerBuilder);
|
||||
}
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
int changeCount;
|
||||
|
||||
this.Status.UpdateStatus(1, "Starting", "Connecting to the Database and initializing the environment");
|
||||
using (DiscoDataContext database = new DiscoDataContext())
|
||||
{
|
||||
UpdateLastNetworkLogonDates(database, this.Status);
|
||||
this.Status.UpdateStatus(95, "Updating Database", "Writing last network logon dates to the Database");
|
||||
changeCount = database.SaveChanges();
|
||||
this.Status.Finished(string.Format("{0} Device last network logon dates updated", changeCount), "/Config/SystemConfig");
|
||||
}
|
||||
|
||||
SystemLog.LogInformation(new string[]
|
||||
{
|
||||
"Updated LastNetworkLogon Device Property for Device/s",
|
||||
changeCount.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public static ScheduledTaskStatus ScheduleImmediately()
|
||||
{
|
||||
var existingTask = ScheduledTasks.GetTaskStatuses(typeof(ADNetworkLogonDatesUpdateTask)).Where(s => s.IsRunning).FirstOrDefault();
|
||||
if (existingTask != null)
|
||||
return existingTask;
|
||||
|
||||
var instance = new ADNetworkLogonDatesUpdateTask();
|
||||
return instance.ScheduleTask();
|
||||
}
|
||||
|
||||
public static bool UpdateLastNetworkLogonDate(Device Device)
|
||||
{
|
||||
const string ldapFilterTemplate = "(&(objectCategory=Computer)(sAMAccountName={0}))";
|
||||
string[] ldapProperties = new string[] { "lastLogon", "lastLogonTimestamp" };
|
||||
|
||||
System.DateTime? lastLogon = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(Device.DeviceDomainId) && Device.DeviceDomainId.Contains('\\'))
|
||||
{
|
||||
var context = ActiveDirectory.Context;
|
||||
string deviceSamAccountName;
|
||||
ADDomain deviceDomain;
|
||||
|
||||
ActiveDirectory.ParseDomainAccountId(Device.DeviceDomainId + "$", out deviceSamAccountName, out deviceDomain);
|
||||
|
||||
var ldapFilter = string.Format(ldapFilterTemplate, ADHelpers.EscapeLdapQuery(deviceSamAccountName));
|
||||
IEnumerable<ADDomainController> domainControllers;
|
||||
|
||||
if (context.SearchAllForestServers)
|
||||
domainControllers = deviceDomain.GetAllReachableDomainControllers();
|
||||
else
|
||||
domainControllers = deviceDomain.GetReachableSiteDomainControllers();
|
||||
|
||||
lastLogon = domainControllers.Select(dc =>
|
||||
{
|
||||
var result = dc.SearchEntireDomain(ldapFilter, ldapProperties, ActiveDirectory.SingleSearchResult).FirstOrDefault();
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
long lastLogonValue = default(long);
|
||||
long lastLogonTimestampValue = default(long);
|
||||
|
||||
lastLogonValue = result.Value<long>("lastLogon");
|
||||
lastLogonTimestampValue = result.Value<long>("lastLogonTimestamp");
|
||||
|
||||
long highedValue = Math.Max(lastLogonValue, lastLogonTimestampValue);
|
||||
|
||||
if (highedValue > 0)
|
||||
return (DateTime?)new DateTime((DateTime.FromFileTime(highedValue).Ticks / 10000000L) * 10000000L);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}).Where(dt => dt.HasValue).Max();
|
||||
}
|
||||
|
||||
if (lastLogon.HasValue &&
|
||||
(
|
||||
!Device.LastNetworkLogonDate.HasValue
|
||||
|| Device.LastNetworkLogonDate.Value < lastLogon
|
||||
))
|
||||
{
|
||||
Device.LastNetworkLogonDate = lastLogon;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void UpdateLastNetworkLogonDates(DiscoDataContext Database, IScheduledTaskStatus status)
|
||||
{
|
||||
var context = ActiveDirectory.Context;
|
||||
const string ldapFilter = "(objectCategory=Computer)";
|
||||
string[] ldapProperties = new string[] { "sAMAccountName", "lastLogon" };
|
||||
|
||||
status.UpdateStatus(2, "Initializing", "Determining Domains and Available Domain Controllers");
|
||||
|
||||
// Determine Domain Scopes to Query
|
||||
var domainQueries = context.Domains
|
||||
.Select(d => Tuple.Create(d, d.SearchContainers ?? new List<string>() { d.DistinguishedName }))
|
||||
.Where(d => d.Item2.Count > 0);
|
||||
|
||||
// Determine Domain Controllers to Query
|
||||
IEnumerable<Tuple<ADDomain, ADDomainController, List<string>>> serverQueries;
|
||||
if (context.SearchAllForestServers)
|
||||
serverQueries = domainQueries.SelectMany(q => q.Item1.GetAllReachableDomainControllers(), (q, dc) => Tuple.Create(q.Item1, dc, q.Item2));
|
||||
else
|
||||
serverQueries = domainQueries.SelectMany(q => q.Item1.GetReachableSiteDomainControllers(), (q, dc) => Tuple.Create(q.Item1, dc, q.Item2));
|
||||
|
||||
var scopedQueries = serverQueries.SelectMany(q => q.Item3, (q, scope) => Tuple.Create(q.Item1, q.Item2, scope)).ToList();
|
||||
|
||||
var queries = Enumerable.Range(0, scopedQueries.Count).Select(i =>
|
||||
{
|
||||
var q = scopedQueries[i];
|
||||
return Tuple.Create(i, q.Item1, q.Item2, q.Item3);
|
||||
});
|
||||
|
||||
var queryResults = queries.SelectMany(q =>
|
||||
{
|
||||
var queryIndex = q.Item1;
|
||||
var domain = q.Item2;
|
||||
var domainController = q.Item3;
|
||||
var searchRoot = q.Item4;
|
||||
|
||||
// Update Status
|
||||
double progress = 5 + (queryIndex * (90 / scopedQueries.Count));
|
||||
status.UpdateStatus(progress, string.Format("Querying Domain [{0}] using controller [{1}]", domain.NetBiosName, domainController.Name), string.Format("Searching: {0}", searchRoot));
|
||||
|
||||
// Perform Query
|
||||
var directoryResults = domainController.SearchInternal(searchRoot, ldapFilter, ldapProperties, null);
|
||||
|
||||
return directoryResults.Select(result =>
|
||||
{
|
||||
var samAccountName = result.Value<string>("sAMAccountName");
|
||||
|
||||
long lastLogonValue = default(long);
|
||||
long lastLogonTimestampValue = default(long);
|
||||
|
||||
lastLogonValue = result.Value<long>("lastLogon");
|
||||
lastLogonTimestampValue = result.Value<long>("lastLogonTimestamp");
|
||||
|
||||
long highedValue = Math.Max(lastLogonValue, lastLogonTimestampValue);
|
||||
|
||||
if (highedValue > 0)
|
||||
{
|
||||
var computerName = string.Format(@"{0}\{1}", domain.NetBiosName, samAccountName.TrimEnd('$'));
|
||||
var lastLogon = new DateTime((DateTime.FromFileTime(highedValue).Ticks / 10000000L) * 10000000L);
|
||||
return Tuple.Create(computerName, lastLogon);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}).Where(i => i != null).ToList();
|
||||
|
||||
}).GroupBy(r => r.Item1, StringComparer.OrdinalIgnoreCase).ToDictionary(g => g.Key.ToUpper(), g => g.Max(i => i.Item2));
|
||||
|
||||
status.UpdateStatus(90, "Processing Results", "Processing last network logon dates and looking for updates");
|
||||
|
||||
foreach (Device device in Database.Devices.Where(device => device.DeviceDomainId != null))
|
||||
{
|
||||
DateTime lastLogonDate;
|
||||
if (queryResults.TryGetValue(device.DeviceDomainId.ToUpper(), out lastLogonDate))
|
||||
{
|
||||
if (!device.LastNetworkLogonDate.HasValue)
|
||||
device.LastNetworkLogonDate = lastLogonDate;
|
||||
else
|
||||
{
|
||||
// Change accuracy to the second
|
||||
lastLogonDate = new DateTime((lastLogonDate.Ticks / 10000000L) * 10000000L);
|
||||
|
||||
if (device.LastNetworkLogonDate.Value < lastLogonDate)
|
||||
device.LastNetworkLogonDate = lastLogonDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user