Files
Disco/Disco.Services/Interop/ActiveDirectory/ADNetworkLogonDatesUpdateTask.cs
T
Gary Sharp a819d2722a 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.
2014-06-16 22:21:31 +10:00

207 lines
9.1 KiB
C#

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;
}
}
}
}
}
}