Update #42: AD Migration

Refactor to target specific Domain Controllers, with failover.
This commit is contained in:
Gary Sharp
2014-04-21 21:43:13 +10:00
parent 43fc622121
commit 09c2a24222
98 changed files with 3808 additions and 3271 deletions
+5 -5
View File
@@ -15,10 +15,10 @@ namespace Disco.BI.AttachmentBI
if (Source != null)
{
// GDI+ (jpg, png, gif, bmp)
if (SourceMimeType.Equals("image/jpeg", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("jpg") ||
SourceMimeType.Equals("image/png", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("png") ||
SourceMimeType.Equals("image/gif", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("gif") ||
SourceMimeType.Equals("image/bmp", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("bmp"))
if (SourceMimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("jpg") ||
SourceMimeType.Equals("image/png", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("png") ||
SourceMimeType.Equals("image/gif", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("gif") ||
SourceMimeType.Equals("image/bmp", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("bmp"))
{
try
{
@@ -42,7 +42,7 @@ namespace Disco.BI.AttachmentBI
}
// PDF
if (SourceMimeType.Equals("application/pdf", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("pdf"))
if (SourceMimeType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("pdf"))
{
PdfReader pdfReader = new PdfReader(Source);
try
+39 -40
View File
@@ -1,7 +1,6 @@
using Disco.BI.Extensions;
using Disco.Data.Repository;
using Disco.Models.ClientServices;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
@@ -295,12 +294,12 @@ namespace Disco.BI.DeviceBI
//if (RepoDeviceProfileContext.DistributionType == DeviceProfileConfiguration.DeviceProfileDistributionTypes.OneToOne && RepoDevice.AssignedUser != null)
if (RepoDevice.DeviceProfile.DistributionType == DeviceProfile.DistributionTypes.OneToOne && RepoDevice.AssignedUser != null)
{
ActiveDirectoryUserAccount AssignedUserInfo = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(RepoDevice.AssignedUser.UserId);
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain, AssignedUserInfo.SecurityIdentifier);
ADUserAccount AssignedUserInfo = ActiveDirectory.RetrieveADUserAccount(RepoDevice.AssignedUser.UserId);
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain.NetBiosName, AssignedUserInfo.SecurityIdentifier.ToString());
response.DeviceAssignedUserUsername = AssignedUserInfo.SamAccountName;
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain;
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain.NetBiosName;
response.DeviceAssignedUserName = AssignedUserInfo.DisplayName;
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier;
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier.ToString();
}
response.DeviceComputerName = RepoDevice.DeviceDomainId;
EnrolmentLog.LogSessionProgress(sessionId, 100, "Completed Successfully");
@@ -324,23 +323,24 @@ namespace Disco.BI.DeviceBI
}
public static EnrolResponse Enrol(DiscoDataContext Database, string Username, Models.ClientServices.Enrol Request)
{
ActiveDirectoryMachineAccount adMachineAccount = null;
ADMachineAccount adMachineAccount = null;
EnrolResponse response = new EnrolResponse();
AuthorizationToken authenticatedToken = null;
bool isAuthenticated = false;
ActiveDirectoryDomain domain = null;
Lazy<DomainController> domainController = new Lazy<DomainController>(() => {
ADDomain domain = null;
Lazy<ADDomainController> domainController = new Lazy<ADDomainController>(() =>
{
if (domain == null)
throw new InvalidOperationException("The [domain] variable must be initialized first");
return domain.RetrieveWritableDomainController();
return domain.GetAvailableDomainController(RequireWritable: true);
});
string sessionId = System.Guid.NewGuid().ToString("B");
response.SessionId = sessionId;
EnrolmentLog.LogSessionStarting(sessionId, Request.DeviceSerialNumber, EnrolmentTypes.Normal);
EnrolmentLog.LogSessionDeviceInfo(sessionId, Request);
@@ -362,7 +362,7 @@ namespace Disco.BI.DeviceBI
{
if (!authenticatedToken.Has(Claims.ComputerAccount))
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.DeviceSerialNumber, authenticatedToken.User.UserId));
if (!authenticatedToken.User.UserId.Equals(string.Format("{0}$", Request.DeviceComputerName), System.StringComparison.InvariantCultureIgnoreCase))
if (!authenticatedToken.User.UserId.Equals(string.Format("{0}$", Request.DeviceComputerName), System.StringComparison.OrdinalIgnoreCase))
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.DeviceSerialNumber, authenticatedToken.User.UserId));
}
}
@@ -393,16 +393,16 @@ namespace Disco.BI.DeviceBI
System.Guid? uuidGuid = null;
System.Guid? macAddressGuid = null;
if (!string.IsNullOrEmpty(Request.DeviceUUID))
uuidGuid = ActiveDirectoryExtensions.NetbootGUIDFromUUID(Request.DeviceUUID);
uuidGuid = ADMachineAccount.NetbootGUIDFromUUID(Request.DeviceUUID);
if (!string.IsNullOrEmpty(Request.DeviceLanMacAddress))
macAddressGuid = ActiveDirectoryExtensions.NetbootGUIDFromMACAddress(Request.DeviceLanMacAddress);
macAddressGuid = ADMachineAccount.NetbootGUIDFromMACAddress(Request.DeviceLanMacAddress);
if (domain == null)
domain = ActiveDirectory.GetDomainByDnsName(Request.DeviceDNSDomainName);
domain = ActiveDirectory.Context.GetDomainByName(Request.DeviceDNSDomainName);
var requestDeviceId = string.Format(@"{0}\{1}", domain.NetBiosName, Request.DeviceComputerName);
adMachineAccount = ActiveDirectory.RetrieveMachineAccount(domainController.Value, requestDeviceId, uuidGuid, macAddressGuid);
adMachineAccount = domainController.Value.RetrieveADMachineAccount(requestDeviceId, uuidGuid, macAddressGuid);
}
if (RepoDevice == null)
{
@@ -468,20 +468,20 @@ namespace Disco.BI.DeviceBI
if (RepoDevice.DeviceProfile.ProvisionADAccount)
{
EnrolmentLog.LogSessionProgress(sessionId, 50, "Provisioning an Active Directory Computer Account");
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
throw new InvalidOperationException("No Organisational Unit has been set in the device profile");
if (domain == null)
domain = ActiveDirectory.GetDomainByDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
domain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
if (string.IsNullOrEmpty(RepoDevice.DeviceDomainId) || RepoDevice.DeviceProfile.EnforceComputerNameConvention)
RepoDevice.DeviceDomainId = RepoDevice.ComputerNameRender(Database, domain);
string offlineProvisionDiagnosicInfo;
EnrolmentLog.LogSessionTaskProvisioningADAccount(sessionId, RepoDevice.SerialNumber, RepoDevice.DeviceDomainId);
adMachineAccount = ActiveDirectory.RetrieveMachineAccount(domainController.Value, RepoDevice.DeviceDomainId);
response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(domain, domainController.Value, RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
adMachineAccount = domainController.Value.RetrieveADMachineAccount(RepoDevice.DeviceDomainId);
response.OfflineDomainJoin = domainController.Value.OfflineDomainJoinProvision(RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, offlineProvisionDiagnosicInfo);
@@ -490,7 +490,7 @@ namespace Disco.BI.DeviceBI
if (adMachineAccount != null)
{
response.DeviceComputerName = adMachineAccount.Name;
response.DeviceDomainName = adMachineAccount.Domain;
response.DeviceDomainName = adMachineAccount.Domain.NetBiosName;
}
else
{
@@ -509,7 +509,7 @@ namespace Disco.BI.DeviceBI
{
RepoDevice.DeviceDomainId = adMachineAccount.Name;
response.DeviceComputerName = adMachineAccount.Name;
response.DeviceDomainName = adMachineAccount.Domain;
response.DeviceDomainName = adMachineAccount.Domain.NetBiosName;
// Enforce Computer Name Convention
if (!adMachineAccount.IsCriticalSystemObject && RepoDevice.DeviceProfile.EnforceComputerNameConvention)
@@ -517,12 +517,12 @@ namespace Disco.BI.DeviceBI
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
throw new InvalidOperationException("No Organisational Unit has been set in the device profile");
if (domain == null)
domain = ActiveDirectory.GetDomainByDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
domain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
var calculatedComputerName = RepoDevice.ComputerNameRender(Database, domain);
var computerNameSplit = Disco.Services.UserExtensions.SplitUserId(calculatedComputerName);
if (!Request.DeviceComputerName.Equals(computerNameSplit.Item2, StringComparison.InvariantCultureIgnoreCase))
if (!Request.DeviceComputerName.Equals(computerNameSplit.Item2, StringComparison.OrdinalIgnoreCase))
{
EnrolmentLog.LogSessionProgress(sessionId, 50, string.Format("Renaming Device: {0} -> {1}", Request.DeviceComputerName, calculatedComputerName));
EnrolmentLog.LogSessionTaskRenamingDevice(sessionId, Request.DeviceComputerName, calculatedComputerName);
@@ -533,9 +533,9 @@ namespace Disco.BI.DeviceBI
// Create New Account
string offlineProvisionDiagnosicInfo;
response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(domain, domainController.Value, RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
response.OfflineDomainJoin = domainController.Value.OfflineDomainJoinProvision(RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, offlineProvisionDiagnosicInfo);
response.RequireReboot = true;
@@ -545,14 +545,14 @@ namespace Disco.BI.DeviceBI
// Enforce Organisational Unit
if (!adMachineAccount.IsCriticalSystemObject && response.OfflineDomainJoin == null && RepoDevice.DeviceProfile.EnforceOrganisationalUnit)
{
var parentDistinguishedName = adMachineAccount.ParentDistinguishedName();
var parentDistinguishedName = adMachineAccount.ParentDistinguishedName;
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
throw new InvalidOperationException(string.Format("The Organisational Unit for the Device Profile '{0}' [{1}] is not set.", RepoDevice.DeviceProfile.Name, RepoDevice.DeviceProfile.Id));
if (!parentDistinguishedName.Equals(RepoDevice.DeviceProfile.OrganisationalUnit, StringComparison.InvariantCultureIgnoreCase)) // Custom OU
if (!parentDistinguishedName.Equals(RepoDevice.DeviceProfile.OrganisationalUnit, StringComparison.OrdinalIgnoreCase)) // Custom OU
{
var proposedDomain = ActiveDirectory.GetDomainByDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
var currentDomain = ActiveDirectory.GetDomainByDistinguishedName(parentDistinguishedName);
var proposedDomain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
var currentDomain = ActiveDirectory.Context.GetDomainFromDistinguishedName(parentDistinguishedName);
if (currentDomain != proposedDomain)
throw new NotSupportedException("Unable to move the devices organisational unit when the source and destination domains are different.");
if (domain == null)
@@ -563,7 +563,6 @@ namespace Disco.BI.DeviceBI
EnrolmentLog.LogSessionProgress(sessionId, 65, string.Format("Moving Device Organisational Unit: {0} -> {1}", parentDistinguishedName, RepoDevice.DeviceProfile.OrganisationalUnit));
EnrolmentLog.LogSessionTaskMovingDeviceOrganisationUnit(sessionId, parentDistinguishedName, RepoDevice.DeviceProfile.OrganisationalUnit);
adMachineAccount.MoveOrganisationalUnit(domainController.Value, RepoDevice.DeviceProfile.OrganisationalUnit);
adMachineAccount = ActiveDirectory.RetrieveMachineAccount(domainController.Value, adMachineAccount.NetBiosId);
response.RequireReboot = true;
}
}
@@ -585,14 +584,14 @@ namespace Disco.BI.DeviceBI
else
{
EnrolmentLog.LogSessionProgress(sessionId, 80, "Retrieving Active Directory Assigned User Account");
ActiveDirectoryUserAccount AssignedUserInfo = Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(RepoDevice.AssignedUser.UserId);
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain, AssignedUserInfo.SecurityIdentifier);
ADUserAccount AssignedUserInfo = ActiveDirectory.RetrieveADUserAccount(RepoDevice.AssignedUser.UserId);
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain.NetBiosName, AssignedUserInfo.SecurityIdentifier.ToString());
response.AllowBootstrapperUninstall = true;
response.DeviceAssignedUserIsLocalAdmin = RepoDevice.DeviceProfile.AssignedUserLocalAdmin;
response.DeviceAssignedUserUsername = AssignedUserInfo.SamAccountName;
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain;
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain.NetBiosName;
response.DeviceAssignedUserName = AssignedUserInfo.DisplayName;
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier;
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier.ToString();
}
}
else
@@ -655,4 +654,4 @@ namespace Disco.BI.DeviceBI
return response;
}
}
}
}
@@ -62,13 +62,13 @@ namespace Disco.BI.DocumentTemplateBI
public string DataScope { get; private set; }
public static bool IsDocumentUniqueIdentifier(string UniqueIdentifier)
{
return UniqueIdentifier.StartsWith("Disco|", System.StringComparison.InvariantCultureIgnoreCase);
return UniqueIdentifier.StartsWith("Disco|", System.StringComparison.OrdinalIgnoreCase);
}
public DocumentUniqueIdentifier(string TemplateTypeId, string DataId, string CreatorId, DateTime TimeStamp, int? Page = null, string Tag = null)
{
var creatorId = (string.IsNullOrEmpty(CreatorId) || CreatorId.IndexOf('\\') > -1)
? CreatorId
: string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, CreatorId);
: string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, CreatorId);
this.Tag = Tag;
this.TemplateTypeId = TemplateTypeId;
@@ -100,7 +100,7 @@ namespace Disco.BI.DocumentTemplateBI
{
var creatorId = s[4];
if (!string.IsNullOrWhiteSpace(creatorId) && creatorId.IndexOf('\\') < 0)
creatorId = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, creatorId);
creatorId = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, creatorId);
this.CreatorId = creatorId;
}
@@ -193,7 +193,7 @@ namespace Disco.BI.DocumentTemplateBI
// Patch for existing documents (before DBv13 - Multi-Domain Support)
// Add default domain to User Ids
if (this.DataId.IndexOf('\\') < 0)
this.DataId = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, this.DataId);
this.DataId = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, this.DataId);
User u = Database.Users.Find(this.DataId);
if (u != null)
@@ -28,7 +28,7 @@ namespace Disco.BI.Expressions.Extensions
}
public static FileImageExpressionResult JobAttachmentFirstImage(Job Job, DiscoDataContext Database)
{
var attachment = Job.JobAttachments.FirstOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase));
var attachment = Job.JobAttachments.FirstOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase));
if (attachment != null)
{
var filename = attachment.RepositoryFilename(Database);
@@ -39,7 +39,7 @@ namespace Disco.BI.Expressions.Extensions
}
public static FileImageExpressionResult JobAttachmentLastImage(Job Job, DiscoDataContext Database)
{
var attachment = Job.JobAttachments.LastOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase));
var attachment = Job.JobAttachments.LastOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase));
if (attachment != null)
{
var filename = attachment.RepositoryFilename(Database);
@@ -52,7 +52,7 @@ namespace Disco.BI.Expressions.Extensions
{
if (JobAttachment == null)
throw new ArgumentNullException("JobAttachment");
if (!JobAttachment.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase))
if (!JobAttachment.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("Invalid Image MimeType for Attachment");
var filename = JobAttachment.RepositoryFilename(Database);
@@ -65,7 +65,7 @@ namespace Disco.BI.Expressions.Extensions
if (Job.JobAttachments == null)
throw new ArgumentException("Job.JobAttachments is null", "Job");
var attachments = Job.JobAttachments.Where(a => a.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase)).ToList();
var attachments = Job.JobAttachments.Where(a => a.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)).ToList();
if (attachments.Count > 0)
{
@@ -81,7 +81,7 @@ namespace Disco.BI.Expressions.Extensions
if (JobAttachments == null)
throw new ArgumentNullException("JobAttachments");
var attachments = JobAttachments.Cast<JobAttachment>().Where(a => a.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase)).ToList();
var attachments = JobAttachments.Cast<JobAttachment>().Where(a => a.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)).ToList();
if (attachments.Count > 0)
{
+6 -7
View File
@@ -6,7 +6,6 @@ using Disco.Models.Repository;
using System.Collections.Generic;
using System;
using System.IO;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Users;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
@@ -16,7 +15,7 @@ namespace Disco.BI.Extensions
public static class DeviceExtensions
{
public static string ComputerNameRender(this Device device, DiscoDataContext Database, ActiveDirectoryDomain Domain)
public static string ComputerNameRender(this Device device, DiscoDataContext Database, ADDomain Domain)
{
if (Domain == null)
throw new ArgumentNullException("Domain");
@@ -56,12 +55,12 @@ namespace Disco.BI.Extensions
public static bool UpdateLastNetworkLogonDate(this Device Device)
{
return Disco.Services.Interop.ActiveDirectory.Internal.ADUpdateLastNetworkLogonDateJob.UpdateLastNetworkLogonDate(Device);
return Disco.Services.Interop.ActiveDirectory.ADTaskUpdateNetworkLogonDates.UpdateLastNetworkLogonDate(Device);
}
public static DeviceAttachment CreateAttachment(this Device Device, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
{
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
DeviceAttachment da = new DeviceAttachment()
@@ -180,7 +179,7 @@ namespace Disco.BI.Extensions
// Update AD Account
if (!string.IsNullOrEmpty(d.DeviceDomainId))
{
var adMachineAccount = ActiveDirectory.RetrieveMachineAccount(d.DeviceDomainId);
var adMachineAccount = ActiveDirectory.RetrieveADMachineAccount(d.DeviceDomainId);
if (adMachineAccount != null)
{
adMachineAccount.SetDescription(d);
@@ -190,10 +189,10 @@ namespace Disco.BI.Extensions
return newDua;
}
public static ActiveDirectoryMachineAccount ActiveDirectoryAccount(this Device Device, params string[] AdditionalProperties)
public static ADMachineAccount ActiveDirectoryAccount(this Device Device, params string[] AdditionalProperties)
{
if (!string.IsNullOrEmpty(Device.DeviceDomainId))
return ActiveDirectory.RetrieveMachineAccount(Device.DeviceDomainId, AdditionalProperties: AdditionalProperties);
return ActiveDirectory.RetrieveADMachineAccount(Device.DeviceDomainId, AdditionalProperties: AdditionalProperties);
else
return null;
}
+2 -2
View File
@@ -16,7 +16,7 @@ namespace Disco.BI.Extensions
{
public static JobAttachment CreateAttachment(this Job Job, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
{
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
JobAttachment ja = new JobAttachment()
@@ -177,7 +177,7 @@ namespace Disco.BI.Extensions
}
foreach (var c in addedComponents)
{
if (!j.JobComponents.Any(jc => jc.Description.Equals(c.Description, StringComparison.InvariantCultureIgnoreCase)))
if (!j.JobComponents.Any(jc => jc.Description.Equals(c.Description, StringComparison.OrdinalIgnoreCase)))
{ // Job Component with matching Description doesn't exist.
Database.JobComponents.Add(new JobComponent()
{
+4 -4
View File
@@ -6,7 +6,7 @@ using Disco.Models.Repository;
using Disco.Data.Repository;
using System.IO;
using Disco.Models.BI.DocumentTemplates;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Interop.ActiveDirectory;
namespace Disco.BI.Extensions
{
@@ -14,7 +14,7 @@ namespace Disco.BI.Extensions
{
public static UserAttachment CreateAttachment(this User User, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
{
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
UserAttachment ua = new UserAttachment()
@@ -57,9 +57,9 @@ namespace Disco.BI.Extensions
{
return u.DeviceUserAssignments.Where(dua => !dua.UnassignedDate.HasValue).ToList();
}
public static ActiveDirectoryUserAccount ActiveDirectoryAccount(this User User, params string[] AdditionalProperties)
public static ADUserAccount ActiveDirectoryAccount(this User User, params string[] AdditionalProperties)
{
return Disco.Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(User.UserId, AdditionalProperties);
return ActiveDirectory.RetrieveADUserAccount(User.UserId, AdditionalProperties);
}
public static bool CanCreateJob(this User u)
+1 -1
View File
@@ -166,7 +166,7 @@ namespace Disco.BI.Extensions
}
public static void SaveJpg(this Image Source, int Quality, Stream OutStream)
{
ImageCodecInfo jpgCodec = ImageCodecInfo.GetImageEncoders().Where(c => c.MimeType.Equals("image/jpeg", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
ImageCodecInfo jpgCodec = ImageCodecInfo.GetImageEncoders().Where(c => c.MimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
if (jpgCodec != null)
{
if (Quality < 0 || Quality > 100)
+13 -13
View File
@@ -1,18 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Models.Repository;
using Disco.BI.Expressions;
using Disco.BI.Extensions;
using Disco.Data.Repository;
using Disco.Models.BI.DocumentTemplates;
using System.IO;
using iTextSharp.text.pdf;
using System.Collections.Concurrent;
using Disco.BI.Expressions;
using System.Collections;
using Disco.BI.Extensions;
using Disco.Models.BI.Expressions;
using Disco.Models.Repository;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Users;
using iTextSharp.text.pdf;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Disco.BI.Interop.Pdf
{
@@ -67,7 +67,7 @@ namespace Disco.BI.Interop.Pdf
{
string dataObjectId = DataObjectsIds[idIndex];
if (!dataObjectId.Contains('\\'))
dataObjectId = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + dataObjectId;
dataObjectId = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + dataObjectId;
DataObjects[idIndex] = UserService.GetUser(DataObjectsIds[idIndex], Database, true);
if (DataObjects[idIndex] == null)
@@ -123,7 +123,7 @@ namespace Disco.BI.Interop.Pdf
foreach (string pdfFieldKey in pdfStamper.AcroFields.Fields.Keys)
{
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.InvariantCultureIgnoreCase))
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.OrdinalIgnoreCase))
{
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
string fieldValue = dt.UniqueIdentifier(Data, CreatorUser.UserId, TimeStamp);
+2 -2
View File
@@ -22,8 +22,8 @@ namespace Disco.Client.Interop
using (DirectoryEntry member = new DirectoryEntry(memberRef))
{
var memberPath = member.Path;
if (memberPath.Equals(string.Format("WinNT://{0}/{1}", UserDomain, Username), StringComparison.InvariantCultureIgnoreCase) ||
memberPath.Equals(string.Format("WinNT://{0}", UserSID), StringComparison.InvariantCultureIgnoreCase))
if (memberPath.Equals(string.Format("WinNT://{0}/{1}", UserDomain, Username), StringComparison.OrdinalIgnoreCase) ||
memberPath.Equals(string.Format("WinNT://{0}", UserSID), StringComparison.OrdinalIgnoreCase))
return false;
}
}
+1 -1
View File
@@ -34,7 +34,7 @@ namespace Disco.Client.Interop
// Determine Primary Adapters
// Lan
PrimaryLanNetworkAdapter = NetworkAdapters.Where(n => !n.IsWLanAdapter && n.NetConnectionId.StartsWith("Local Area Connection", StringComparison.InvariantCultureIgnoreCase)).OrderByDescending(n => n.Speed).FirstOrDefault();
PrimaryLanNetworkAdapter = NetworkAdapters.Where(n => !n.IsWLanAdapter && n.NetConnectionId.StartsWith("Local Area Connection", StringComparison.OrdinalIgnoreCase)).OrderByDescending(n => n.Speed).FirstOrDefault();
// Might be too restrictive - remove name restriction just in case.
if (PrimaryLanNetworkAdapter == null)
PrimaryLanNetworkAdapter = NetworkAdapters.Where(n => !n.IsWLanAdapter).OrderByDescending(n => n.Speed).FirstOrDefault();
+3 -3
View File
@@ -127,9 +127,9 @@ namespace Disco.Client.Interop
// Added 2012-11-22 G# - Lenovo IdeaPad Serial SHIM
// http://www.discoict.com.au/forum/feature-requests/2012/11/serial-number-detection-on-ideapads.aspx
if (string.IsNullOrWhiteSpace(DeviceSerialNumber) ||
(DeviceManufacturer.Equals("LENOVO", StringComparison.InvariantCultureIgnoreCase) &&
(DeviceModel.Equals("S10-3", StringComparison.InvariantCultureIgnoreCase) // S10-3
|| DeviceModel.Equals("2957", StringComparison.InvariantCultureIgnoreCase)))) // S10-2
(DeviceManufacturer.Equals("LENOVO", StringComparison.OrdinalIgnoreCase) &&
(DeviceModel.Equals("S10-3", StringComparison.OrdinalIgnoreCase) // S10-3
|| DeviceModel.Equals("2957", StringComparison.OrdinalIgnoreCase)))) // S10-2
{
try
{
@@ -74,14 +74,14 @@ namespace Disco.ClientBootstrapper.Interop
// Only Copy Certain Files
// Copy Wireless Certificates
if (fileName.StartsWith("WLAN_Cert_Root_", StringComparison.InvariantCultureIgnoreCase) ||
fileName.StartsWith("WLAN_Cert_Intermediate_", StringComparison.InvariantCultureIgnoreCase) ||
fileName.StartsWith("WLAN_Cert_Personal_", StringComparison.InvariantCultureIgnoreCase))
if (fileName.StartsWith("WLAN_Cert_Root_", StringComparison.OrdinalIgnoreCase) ||
fileName.StartsWith("WLAN_Cert_Intermediate_", StringComparison.OrdinalIgnoreCase) ||
fileName.StartsWith("WLAN_Cert_Personal_", StringComparison.OrdinalIgnoreCase))
File.Copy(file, Path.Combine(InstallLocation, fileName));
// Copy Wireless Profiles
if (fileName.StartsWith("WLAN_Profile_", StringComparison.InvariantCultureIgnoreCase) &&
fileName.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase))
if (fileName.StartsWith("WLAN_Profile_", StringComparison.OrdinalIgnoreCase) &&
fileName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
File.Copy(file, Path.Combine(InstallLocation, fileName));
}
@@ -194,7 +194,7 @@ namespace Disco.ClientBootstrapper.Interop
if (string.IsNullOrWhiteSpace(InstallLocation))
InstallLocation = Path.Combine(Path.GetPathRoot(Environment.SystemDirectory), "Disco");
if (InstallLocation.EndsWith(".wim", StringComparison.InvariantCultureIgnoreCase))
if (InstallLocation.EndsWith(".wim", StringComparison.OrdinalIgnoreCase))
{
// Offline File System (WIM)
Program.Status.UpdateStatus("Installing Bootstrapper (Offline)", "Installing", string.Format("Install Location: {0}", InstallLocation));
@@ -216,7 +216,7 @@ namespace Disco.ClientBootstrapper.Interop
using (var wimImage = wim[i])
wimImageInfo.LoadXml(wimImage.ImageInformation);
var wimImageInfoName = wimImageInfo.SelectSingleNode("//IMAGE/NAME");
if (wimImageInfoName != null && wimImageInfoName.InnerText.Equals(WimImageId, StringComparison.InvariantCultureIgnoreCase))
if (wimImageInfoName != null && wimImageInfoName.InnerText.Equals(WimImageId, StringComparison.OrdinalIgnoreCase))
{
wimImageIndex = i + 1;
Program.Status.UpdateStatus(null, "Analysing WIM", string.Format("Found Image Id '{0}' at Index {1}", WimImageId, wimImageIndex));
@@ -28,7 +28,7 @@ namespace Disco.Data.Configuration.Modules
}
}
public bool? SearchEntireForest
public bool? SearchAllForestServers
{
get { return GetFromJson<bool?>(null); }
set { SetAsJson(value); }
+1 -1
View File
@@ -423,7 +423,7 @@ DELETE [Users] WHERE [Id]=@IdExisting;";
if (System.IO.Directory.Exists(userAttachmentsDirectory))
{
var files = System.IO.Directory.EnumerateFiles(userAttachmentsDirectory, "*.*", System.IO.SearchOption.AllDirectories)
.Where(p => !p.StartsWith(filePrefix, StringComparison.InvariantCultureIgnoreCase) && (p.EndsWith("_thumb.jpg") || p.EndsWith("_file"))).ToList();
.Where(p => !p.StartsWith(filePrefix, StringComparison.OrdinalIgnoreCase) && (p.EndsWith("_thumb.jpg") || p.EndsWith("_file"))).ToList();
foreach (var file in files)
{
+1 -9
View File
@@ -38,7 +38,6 @@
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.Entity" />
<Reference Include="System.DirectoryServices" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@@ -47,9 +46,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="BI\Job\LocationModes.cs" />
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryDomain.cs" />
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryOrganisationalUnit.cs" />
<Compile Include="Interop\ActiveDirectory\ActiveDirectorySearchResult.cs" />
<Compile Include="Services\Authorization\IAuthorizationToken.cs" />
<Compile Include="Services\Authorization\IClaimNavigatorItem.cs" />
<Compile Include="Services\Authorization\IRoleToken.cs" />
@@ -76,10 +72,6 @@
<Compile Include="ClientServices\Enrol.cs" />
<Compile Include="ClientServices\WhoAmI.cs" />
<Compile Include="ClientServices\WhoAmIResponse.cs" />
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryMachineAccount.cs" />
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryGroup.cs" />
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryUserAccount.cs" />
<Compile Include="Interop\ActiveDirectory\IActiveDirectoryObject.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Repository\ConfigurationItem.cs" />
<Compile Include="Repository\Device\Device.cs" />
@@ -172,7 +164,7 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_StartDate="2011/7/1" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildAction="Both" />
<UserProperties BuildVersion_BuildAction="Both" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
@@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Models.Interop.ActiveDirectory
{
public class ActiveDirectoryDomain
{
public string DnsName { get; private set; }
public string NetBiosName { get; private set; }
public string DistinguishedName { get; private set; }
public List<string> SearchContainers { get; private set; }
public ActiveDirectoryDomain(string DnsName, string NetBiosName, string DistinguishedName, List<string> SearchContainers)
{
this.DnsName = DnsName;
this.NetBiosName = NetBiosName;
this.DistinguishedName = DistinguishedName;
this.SearchContainers = SearchContainers;
}
public void UpdateSearchContainers(IEnumerable<string> Containers)
{
this.SearchContainers = Containers.ToList();
}
}
}
@@ -1,21 +0,0 @@
using System.Collections.Generic;
namespace Disco.Models.Interop.ActiveDirectory
{
public class ActiveDirectoryGroup : IActiveDirectoryObject
{
public string Domain { get; set; }
public string SamAccountName { get; set; }
public string DistinguishedName { get; set; }
public string SecurityIdentifier { get; set; }
public string CommonName { get; set; }
public string Name { get; set; }
public string DisplayName { get { return this.Name; } }
public List<string> MemberOf { get; set; }
public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } }
}
}
@@ -1,36 +0,0 @@
using Disco.Models.Repository;
using System;
using System.Collections.Generic;
namespace Disco.Models.Interop.ActiveDirectory
{
public class ActiveDirectoryMachineAccount : IActiveDirectoryObject
{
public string Domain { get; set; }
public string SamAccountName { get; set; }
public string SecurityIdentifier { get; set; }
public string DistinguishedName { get; set; }
public string Path { get; set; }
public string Name { get; set; }
public string DisplayName { get { return this.Name; } }
public string DnsName { get; set; }
public Guid NetbootGUID { get; set; }
public bool IsCriticalSystemObject { get; set; }
public Dictionary<string, object[]> LoadedProperties { get; set; }
public User ToRepositoryUser()
{
return new User
{
UserId = this.Domain + "\\" + this.SamAccountName,
DisplayName = this.Name
};
}
public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } }
}
}
@@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Models.Interop.ActiveDirectory
{
public class ActiveDirectoryOrganisationalUnit
{
public string Name { get; set; }
public string Domain { get; set; }
public string DistinguishedName { get; set; }
public List<ActiveDirectoryOrganisationalUnit> Children { get; set; }
}
}
@@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Models.Interop.ActiveDirectory
{
public class ActiveDirectorySearchResult
{
public ActiveDirectoryDomain Domain { get; set; }
public string SearchRoot { get; set; }
public SearchResult Result { get; set; }
}
}
@@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Models.Repository;
namespace Disco.Models.Interop.ActiveDirectory
{
public class ActiveDirectoryUserAccount : IActiveDirectoryObject
{
public string Domain { get; set; }
public string SamAccountName { get; set; }
public string DistinguishedName { get; set; }
public string SecurityIdentifier { get; set; }
public string Path { get; set; }
public string Name { get; set; }
public string DisplayName { get; set; }
public string Email { get; set; }
public string Surname { get; set; }
public string GivenName { get; set; }
public string Phone { get; set; }
public List<string> Groups { get; set; }
public Dictionary<string, object[]> LoadedProperties { get; set; }
public User ToRepositoryUser()
{
return new User
{
UserId = this.Domain + "\\" + this.SamAccountName,
DisplayName = this.DisplayName,
Surname = this.Surname,
GivenName = this.GivenName,
EmailAddress = this.Email,
PhoneNumber = this.Phone,
};
}
public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } }
}
}
@@ -1,16 +0,0 @@

namespace Disco.Models.Interop.ActiveDirectory
{
public interface IActiveDirectoryObject
{
string DistinguishedName { get; set; }
string SecurityIdentifier { get; set; }
string Domain { get; set; }
string SamAccountName { get; set; }
string NetBiosId { get; }
string Name { get; set; }
string DisplayName { get; }
}
}
+6
View File
@@ -72,6 +72,9 @@ namespace Disco.Models.Repository
{
get
{
if (DeviceDomainId == null)
return null;
var index = DeviceDomainId.IndexOf('\\');
return index < 0 ? DeviceDomainId : DeviceDomainId.Substring(index + 1);
}
@@ -82,6 +85,9 @@ namespace Disco.Models.Repository
{
get
{
if (DeviceDomainId == null)
return null;
var index = DeviceDomainId.IndexOf('\\');
return index < 0 ? null : DeviceDomainId.Substring(0, index);
}
+1 -1
View File
@@ -66,7 +66,7 @@ namespace Disco.Models.Repository
public void UpdateSelf(User u)
{
if (!this.UserId.Equals(u.UserId, StringComparison.InvariantCultureIgnoreCase))
if (!this.UserId.Equals(u.UserId, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("User Id's do not match", "u");
if (this.Surname != u.Surname)
@@ -7,6 +7,7 @@ using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Disco.Services.Interop.ActiveDirectory;
namespace Disco.Services.Authorization
{
@@ -18,12 +19,12 @@ namespace Disco.Services.Authorization
#region Token Builders
public static AuthorizationToken BuildToken(User User, List<string> GroupMembership)
public static AuthorizationToken BuildToken(User User, IEnumerable<string> GroupMembership)
{
return new AuthorizationToken()
{
User = User,
GroupMembership = GroupMembership,
GroupMembership = GroupMembership.ToList(),
RoleTokens = RoleCache.GetRoleTokens(GroupMembership, User)
};
}
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Disco.Services.Interop.ActiveDirectory;
namespace Disco.Services.Authorization.Roles
{
@@ -49,19 +50,19 @@ namespace Disco.Services.Authorization.Roles
private static IEnumerable<string> GenerateAdministratorSubjectIds(DiscoDataContext Database)
{
var domainNetBiosName = Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName;
var domainNetBiosName = ActiveDirectory.Context.PrimaryDomain.NetBiosName;
var configuredSubjectIds = Database.DiscoConfiguration.Administrators.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Contains(@"\") ? s : string.Format(@"{0}\{1}", domainNetBiosName, s));
return RequiredAdministratorSubjectIds
.Concat(configuredSubjectIds)
.Distinct(StringComparer.InvariantCultureIgnoreCase)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(s => s);
}
public static IEnumerable<string> RequiredAdministratorSubjectIds
{
get
{
var domainNetBiosName = Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName;
var domainNetBiosName = ActiveDirectory.Context.PrimaryDomain.NetBiosName;
return _RequiredAdministratorSubjectIds.Select(s => string.Format(@"{0}\{1}", domainNetBiosName, s));
}
}
@@ -79,7 +80,7 @@ namespace Disco.Services.Authorization.Roles
SubjectIds = SubjectIds
.Where(s => !string.IsNullOrWhiteSpace(s))
.Concat(RequiredAdministratorSubjectIds)
.Distinct(StringComparer.InvariantCultureIgnoreCase)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(s => s);
var subjectIdsString = string.Join(",", SubjectIds);
@@ -136,17 +137,15 @@ namespace Disco.Services.Authorization.Roles
}
internal static RoleToken GetRoleToken(string SecurityGroup)
{
return _Cache.FirstOrDefault(t => t.SubjectIdHashes.Contains(SecurityGroup.ToLower()));
return _Cache.FirstOrDefault(t => t.SubjectIdHashes.Contains(SecurityGroup));
}
internal static List<IRoleToken> GetRoleTokens(IEnumerable<string> SecurityGroup)
{
var securityGroups = SecurityGroup.Select(sg => sg.ToLower());
return _Cache.Where(t => securityGroups.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast<IRoleToken>().ToList();
return _Cache.Where(t => SecurityGroup.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast<IRoleToken>().ToList();
}
internal static List<IRoleToken> GetRoleTokens(IEnumerable<string> SecurityGroup, User User)
{
var subjectIds = (new string[] { User.UserId }).Concat(SecurityGroup).Select(sg => sg.ToLower());
var subjectIds = SecurityGroup.Concat(new string[] { User.UserId });
return _Cache.Where(t => subjectIds.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast<IRoleToken>().ToList();
}
@@ -30,7 +30,7 @@ namespace Disco.Services.Authorization.Roles
return new RoleToken()
{
Role = Role,
SubjectIdHashes = new HashSet<string>(sg.Select(i => i.ToLower())),
SubjectIdHashes = new HashSet<string>(sg.Select(i => i.ToLower()), StringComparer.OrdinalIgnoreCase),
SubjectIds = sg.ToList(),
Claims = Claims
};
+22 -5
View File
@@ -174,12 +174,29 @@
<Compile Include="Authorization\Roles\RoleToken.cs" />
<Compile Include="Extensions\DateTimeExtensions.cs" />
<Compile Include="Extensions\StringExtensions.cs" />
<None Include="Interop\_ActiveDirectory\ActiveDirectory.cs" />
<None Include="Interop\_ActiveDirectory\ActiveDirectoryExtensions.cs" />
<None Include="Interop\_ActiveDirectory\Internal\ADDiscoverForestServers.cs" />
<None Include="Interop\_ActiveDirectory\Internal\ADGroupCache.cs" />
<None Include="Interop\_ActiveDirectory\Internal\ADInterop.cs" />
<None Include="Interop\_ActiveDirectory\Internal\ADUpdateLastNetworkLogonDateJob.cs" />
<Compile Include="Interop\ActiveDirectory\ActiveDirectory.cs" />
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryContext.cs" />
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryExtensions.cs" />
<Compile Include="Interop\ActiveDirectory\Internal\ADDiscoverForestServers.cs" />
<Compile Include="Interop\ActiveDirectory\Internal\ADGroupCache.cs" />
<Compile Include="Interop\ActiveDirectory\Internal\ADInterop.cs" />
<Compile Include="Interop\ActiveDirectory\Internal\ADUpdateLastNetworkLogonDateJob.cs" />
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryGroupCache.cs" />
<Compile Include="Interop\ActiveDirectory\ADDirectoryEntry.cs" />
<Compile Include="Interop\ActiveDirectory\ADDiscoverForestServers.cs" />
<Compile Include="Interop\ActiveDirectory\ADDomain.cs" />
<Compile Include="Interop\ActiveDirectory\ADDomainController.cs" />
<Compile Include="Interop\ActiveDirectory\ADGroup.cs" />
<Compile Include="Interop\ActiveDirectory\ADHelpers.cs" />
<Compile Include="Interop\ActiveDirectory\ADMachineAccount.cs" />
<Compile Include="Interop\ActiveDirectory\ADOrganisationalUnit.cs" />
<Compile Include="Interop\ActiveDirectory\ADSearchResult.cs" />
<Compile Include="Interop\ActiveDirectory\ADSite.cs" />
<Compile Include="Interop\ActiveDirectory\ADTaskUpdateNetworkLogonDates.cs" />
<Compile Include="Interop\ActiveDirectory\ADUserAccount.cs" />
<Compile Include="Interop\ActiveDirectory\IADObject.cs" />
<Compile Include="Jobs\JobExtensions.cs" />
<Compile Include="Jobs\JobLists\JobTableExtensions.cs" />
<Compile Include="Jobs\JobQueues\Cache.cs" />
@@ -286,7 +303,7 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<UserProperties BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_BuildAction="Both" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildAction="Both" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" />
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Interop.ActiveDirectory
{
public class ADDirectoryEntry : IDisposable
{
public ADDomain Domain { get; private set; }
public ADDomainController DomainController { get; private set; }
public DirectoryEntry Entry { get; private set; }
internal ADDirectoryEntry(ADDomain Domain, ADDomainController DomainController, DirectoryEntry Entry)
{
if (Domain == null)
throw new ArgumentNullException("Domain");
if (DomainController == null)
throw new ArgumentNullException("DomainController");
if (Entry == null)
throw new ArgumentNullException("Entry");
this.Domain = Domain;
this.DomainController = DomainController;
this.Entry = Entry;
}
public void Dispose()
{
if (Entry != null)
{
Entry.Dispose();
Entry = null;
}
}
public override string ToString()
{
if (this.Entry != null)
return this.Entry.Path;
else
return base.ToString();
}
}
}
@@ -7,23 +7,25 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Interop.ActiveDirectory.Internal
namespace Disco.Services.Interop.ActiveDirectory
{
public class ADDiscoverForestServers : ScheduledTask
{
public override string TaskName { get { return "Active Directory - Discover Forest Servers"; } }
public override bool SingleInstanceTask { get { return true; } }
public override bool CancelInitiallySupported { get { return false; } }
internal static List<string> ForestServers { get; set; }
private static object _scheduleLock = new object();
protected override void ExecuteTask()
{
var forestServers = DiscoverForestServers();
ADInterop._ForestServers = forestServers;
ADDiscoverForestServers.ForestServers = forestServers;
// Restrict Searching Entire Forest if to many servers
using (DiscoDataContext Database = new DiscoDataContext())
{
var searchEntireForest = Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest;
var searchEntireForest = Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers;
// Check explicitly configured: No
if (!searchEntireForest.HasValue || searchEntireForest.Value)
@@ -32,12 +34,12 @@ namespace Disco.Services.Interop.ActiveDirectory.Internal
if (forestServers.Count > ActiveDirectory.MaxForestServerSearch)
{
// Update Database
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = false;
Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers = false;
}
else
{
// Default
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = true;
Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers = true;
}
Database.SaveChanges();
@@ -52,12 +54,59 @@ namespace Disco.Services.Interop.ActiveDirectory.Internal
return taskStatus;
else
{
var t = new ADDiscoverForestServers();
return t.ScheduleTask();
lock (_scheduleLock)
{
taskStatus = ScheduledTasks.GetTaskStatuses(typeof(ADDiscoverForestServers)).Where(ts => ts.IsRunning).FirstOrDefault();
if (taskStatus != null)
return taskStatus;
else
{
var t = new ADDiscoverForestServers();
return t.ScheduleTask();
}
}
}
}
internal static List<string> DiscoverForestServers()
public static List<string> LoadForestServersBlocking()
{
if (ADDiscoverForestServers.ForestServers != null)
return ADDiscoverForestServers.ForestServers;
ScheduledTaskStatus status;
lock (_scheduleLock)
{
if (ADDiscoverForestServers.ForestServers != null)
return ADDiscoverForestServers.ForestServers;
status = ADDiscoverForestServers.ScheduleNow();
}
status.CompletionTask.Wait();
return ForestServers;
}
public static Task<List<string>> LoadForestServersAsync()
{
if (ADDiscoverForestServers.ForestServers != null)
return Task.FromResult(ADDiscoverForestServers.ForestServers);
ScheduledTaskStatus status;
lock (_scheduleLock)
{
if (ADDiscoverForestServers.ForestServers != null)
return Task.FromResult(ADDiscoverForestServers.ForestServers);
status = ADDiscoverForestServers.ScheduleNow();
}
return status.CompletionTask.ContinueWith(t =>
{
return ADDiscoverForestServers.ForestServers;
});
}
private static List<string> DiscoverForestServers()
{
using (var computerDomain = Domain.GetComputerDomain())
{
@@ -0,0 +1,383 @@
using Disco.Services.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Disco.Services.Interop.ActiveDirectory
{
public class ADDomain
{
private const int DomainMaintanceIntervalMinutes = 15;
private const int SearchExceptionRetryMax = 4;
private ActiveDirectoryContext context;
private ConcurrentStack<ADDomainController> domainControllers;
private int domainControllerRoundRobin = -1;
private object domainMaintainLock = new object();
private DateTime domainMaintenanceNext;
public Domain Domain { get; private set; }
public IEnumerable<ADDomainController> DomainControllers
{
get
{
return domainControllers.ToArray();
}
}
public string Name { get; private set; }
public string NetBiosName { get; private set; }
public string DistinguishedName { get; private set; }
public string ConfigurationNamingContext { get; private set; }
public SecurityIdentifier SecurityIdentifier { get; private set; }
public List<string> SearchContainers { get; private set; }
public ADDomain(ActiveDirectoryContext Context, Domain Domain)
{
this.context = Context;
this.Domain = Domain;
this.SearchContainers = null;
this.domainControllers = null;
this.domainMaintenanceNext = DateTime.Now.AddMinutes(DomainMaintanceIntervalMinutes);
this.Initialize();
}
private void Initialize()
{
this.Name = Domain.Name;
var dc = Domain.FindDomainController();
string ldapPath = string.Format("LDAP://{0}/", dc.Name);
using (var adRootDSE = new DirectoryEntry(ldapPath + "RootDSE"))
{
this.DistinguishedName = adRootDSE.Properties["defaultNamingContext"][0].ToString();
this.ConfigurationNamingContext = adRootDSE.Properties["configurationNamingContext"][0].ToString();
}
using (var adDomainRoot = new DirectoryEntry(ldapPath + this.DistinguishedName))
{
this.SecurityIdentifier = new SecurityIdentifier((byte[])(adDomainRoot.Properties["objectSid"][0]), 0);
}
using (var configSearchRoot = new DirectoryEntry(ldapPath + "CN=Partitions," + this.ConfigurationNamingContext))
{
var configSearchFilter = string.Format("(&(objectcategory=Crossref)(dnsRoot={0})(netBIOSName=*))", this.Name);
using (var configSearcher = new DirectorySearcher(configSearchRoot, configSearchFilter, new string[] { "NetBIOSName" }, System.DirectoryServices.SearchScope.OneLevel))
{
SearchResult configResult = configSearcher.FindOne();
if (configResult != null)
this.NetBiosName = configResult.Properties["NetBIOSName"][0].ToString();
else
this.NetBiosName = null;
}
}
}
#region Domain Controllers
public IEnumerable<ADDomainController> GetAllReachableDomainControllers()
{
return this.Domain.FindAllDomainControllers().WhereReachable().Select(dc => new ADDomainController(this.context, dc, this, dc.SiteName == this.context.Site.Name, false));
}
public IEnumerable<ADDomainController> GetReachableSiteDomainControllers()
{
return this.DomainControllers.Where(dc => dc.IsSiteServer && dc.DomainController.IsReachable());
}
public ADDomainController GetAvailableDomainController(bool RequireWritable = false)
{
if (this.domainMaintenanceNext < DateTime.Now)
MaintainDomainControllers();
IEnumerable<ADDomainController> availableServers;
// Try Site Servers first
availableServers = AvilableDomainControllers(RequireSiteServer: true, RequireWritable: RequireWritable);
if (!availableServers.Any())
{
// No Site Servers available - try all
availableServers = AvilableDomainControllers(RequireSiteServer: false, RequireWritable: RequireWritable);
if (!availableServers.Any())
{
lock (domainMaintainLock)
{
availableServers = AvilableDomainControllers(RequireSiteServer: false, RequireWritable: RequireWritable);
if (!availableServers.Any())
return DiscoverAvailableDomainController(RequireWritable);
}
}
}
switch (availableServers.Count())
{
case 1:
// 1 Available DC
return availableServers.First();
default:
// Multiple DCs Available - Round Robin
int drr = Interlocked.Increment(ref domainControllerRoundRobin);
int dcrrValue = drr % availableServers.Count();
if (drr > availableServers.Count())
domainControllerRoundRobin = -1;
return availableServers.ElementAt(dcrrValue);
}
}
private IEnumerable<ADDomainController> AvilableDomainControllers(bool RequireSiteServer, bool RequireWritable)
{
IEnumerable<ADDomainController> query = this.DomainControllers.Where(dc => dc.IsAvailable);
if (RequireSiteServer)
query = query.Where(dc => dc.IsSiteServer);
if (RequireWritable)
query = query.Where(dc => dc.IsWritable);
return query;
}
private ADDomainController DiscoverAvailableDomainController(bool RequireWritable)
{
LocatorOptions locatorOptions;
if (RequireWritable)
locatorOptions = LocatorOptions.ForceRediscovery | LocatorOptions.WriteableRequired;
else
locatorOptions = LocatorOptions.ForceRediscovery;
var dc = this.Domain.FindDomainController(locatorOptions);
var dcName = dc.Name;
var existingDC = this.DomainControllers.FirstOrDefault(edc => edc.Name == dcName);
if (existingDC != null)
{
// DC already in scope
// Native API indicates writable
if (RequireWritable)
existingDC.IsWritable = true;
// Native API indicates it is available
existingDC.IsAvailable = true;
return existingDC;
}
else
{
// New DC discovered
var adDC = new ADDomainController(this.context, dc, this, dc.SiteName == this.context.Site.Name, RequireWritable);
// Add DC to Available Servers
this.domainControllers.Push(adDC);
return adDC;
}
}
private void MaintainDomainControllers()
{
lock (domainMaintainLock)
{
var servers = this.domainControllers.ToList();
var nonSiteServersPresent = servers.Any(s => !s.IsSiteServer);
if (nonSiteServersPresent)
{
var siteServersAvailable = servers.Any(s => s.IsSiteServer && s.IsAvailable);
var nonSiteServersUnavailable = servers.Any(s => !s.IsSiteServer && !s.IsAvailable);
if (siteServersAvailable)
{
// Remove non-site servers
UpdateDomainControllers(servers.Where(s => s.IsSiteServer));
}
else if (nonSiteServersUnavailable)
{
// Remove unavailable non-site servers
UpdateDomainControllers(servers.Where(s => s.IsSiteServer || s.IsAvailable));
}
}
this.domainMaintenanceNext = DateTime.Now.AddMinutes(DomainMaintanceIntervalMinutes);
}
}
internal void UpdateDomainControllers(IEnumerable<ADDomainController> DomainControllers)
{
this.domainControllers = new ConcurrentStack<ADDomainController>(DomainControllers);
}
#endregion
public ADDirectoryEntry RetrieveDirectoryEntry(string DistinguishedName, string[] LoadProperties = null)
{
if (string.IsNullOrWhiteSpace(DistinguishedName))
throw new ArgumentNullException("DistinguishedName");
if (!DistinguishedName.EndsWith(this.DistinguishedName, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException(string.Format("The Distinguished Name ({0}) isn't a member of this domain [{1}]", DistinguishedName, this.Name), "DistinguishedName");
var dc = GetAvailableDomainController();
return dc.RetrieveDirectoryEntry(DistinguishedName, LoadProperties);
}
#region Searching
public IEnumerable<ADSearchResult> SearchEntireDomain(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
{
return SearchInternal(this.DistinguishedName, LdapFilter, LoadProperties, ResultLimit);
}
public IEnumerable<ADSearchResult> SearchScope(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
{
var searchScope = this.SearchContainers;
// No scope set, search entire domain
if (searchScope == null)
return SearchEntireDomain(LdapFilter, LoadProperties, ResultLimit);
switch (searchScope.Count)
{
case 0: // Ignore domain
return Enumerable.Empty<ADSearchResult>();
case 1: // Single-search
return SearchInternal(searchScope[0], LdapFilter, LoadProperties, ResultLimit);
default: // Multi-search - Parallelize
var queryTasks = searchScope.Select(scope =>
Task<IEnumerable<ADSearchResult>>.Factory.StartNew(() =>
SearchInternal(scope, LdapFilter, LoadProperties, ResultLimit))).ToArray();
// Block
Task.WaitAll(queryTasks);
var results = queryTasks.SelectMany(t => t.Result);
if (ResultLimit.HasValue)
results = results.Take(ResultLimit.Value);
return results;
}
}
internal IEnumerable<ADSearchResult> SearchInternal(string SearchRoot, string LdapFilter, string[] LoadProperties, int? ResultLimit)
{
if (string.IsNullOrEmpty(SearchRoot))
throw new ArgumentNullException("SearchRoot");
if (string.IsNullOrEmpty(LdapFilter))
throw new ArgumentNullException("LdapFilter");
if (ResultLimit.HasValue && ResultLimit.Value < 1)
throw new ArgumentOutOfRangeException("ResultLimit", "The ResultLimit must be 1 or greater");
// Search with recovery
var exceptionCount = 0;
Queue<Exception> exceptions = null;
do
{
var domainController = GetAvailableDomainController();
try
{
return domainController.SearchInternal(SearchRoot, LdapFilter, LoadProperties, ResultLimit);
}
catch (Exception ex)
{
if (exceptions == null)
exceptions = new Queue<Exception>(SearchExceptionRetryMax);
exceptions.Enqueue(ex);
exceptionCount++;
// Set offline for DomainControllerUnavailableMinutes
domainController.IsAvailable = false;
SystemLog.LogWarning(string.Format("A domain controller [{0}] is offline. It will be retried after {1}. Error: {2} [{3}]", domainController.Name, domainController.AvailableWhen.Value.ToShortTimeString(), ex.Message, ex.GetType().Name));
}
} while (exceptionCount < SearchExceptionRetryMax);
throw new AggregateException(
new Exception[] { new Exception(string.Format("Unable to perform Active Directory Search after {0} attempts", exceptionCount)) }
.Concat(exceptions));
}
#endregion
internal void UpdateSearchContainers(List<string> Containers)
{
this.SearchContainers = Containers ?? new List<string>();
}
internal void UpdateSearchEntireDomain()
{
this.SearchContainers = null;
}
#region Helpers
public string DefaultComputerContainer
{
get
{
return string.Format("CN=Computers,{0}", this.DistinguishedName);
}
}
public string FriendlyDistinguishedNamePath(string DistinguishedName)
{
if (!DistinguishedName.EndsWith(this.DistinguishedName, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException(string.Format("The Distinguished Name [{0}] doesn't exist within this domain [{1}]", DistinguishedName, this.DistinguishedName));
StringBuilder name = new StringBuilder();
name.Append('[').Append(this.NetBiosName).Append(']');
var subDN = DistinguishedName.Substring(0, DistinguishedName.Length - this.DistinguishedName.Length);
var subDNComponents = subDN.Split(',');
subDNComponents
.Where(c => !string.IsNullOrWhiteSpace(c))
.Reverse()
.Select(c => c.Substring(c.IndexOf('=') + 1))
.ToList()
.ForEach(c => name.Append(" > ").Append(c));
return name.ToString();
}
#endregion
public override string ToString()
{
return string.Format("{0} [{1}]", this.Name, this.NetBiosName);
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is ADDomain))
return false;
else
return this.DistinguishedName == ((ADDomain)obj).DistinguishedName;
}
public override int GetHashCode()
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.DistinguishedName);
}
}
}
@@ -0,0 +1,424 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Net.NetworkInformation;
using System.Security.Principal;
using System.Text;
namespace Disco.Services.Interop.ActiveDirectory
{
public class ADDomainController
{
private const string LdapPathTemplate = @"LDAP://{0}/{1}";
private ActiveDirectoryContext context;
public DomainController DomainController { get; private set; }
public ADDomain Domain { get; private set; }
public string Name { get; private set; }
public string SiteName { get; private set; }
public bool IsSiteServer { get; private set; }
public bool IsWritable { get; internal set; }
public DateTime? AvailableWhen { get; private set; }
public bool IsAvailable
{
get
{
var aw = AvailableWhen;
if (aw.HasValue && aw.Value < DateTime.Now)
AvailableWhen = null;
return !aw.HasValue;
}
internal set
{
if (value)
AvailableWhen = null;
else
AvailableWhen = DateTime.Now.AddMinutes(ActiveDirectory.DomainControllerUnavailableMinutes);
}
}
public ADDomainController(ActiveDirectoryContext Context, DomainController DomainController, ADDomain Domain, bool IsSiteServer, bool IsWritable)
{
this.context = Context;
this.Domain = Domain;
this.DomainController = DomainController;
this.Name = DomainController.Name;
this.SiteName = DomainController.SiteName;
this.IsSiteServer = IsSiteServer;
this.IsWritable = IsWritable;
this.AvailableWhen = null;
}
public ADDirectoryEntry RetrieveDirectoryEntry(string DistinguishedName, string[] LoadProperties = null)
{
if (string.IsNullOrWhiteSpace(DistinguishedName))
throw new ArgumentNullException("DistinguishedName");
if (!DistinguishedName.EndsWith(this.Domain.DistinguishedName, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException(string.Format("The Distinguished Name ({0}) isn't a member of this domain [{1}]", DistinguishedName, this.Domain.Name), "DistinguishedName");
var entry = new DirectoryEntry(string.Format(LdapPathTemplate, this.Name, DistinguishedName));
if (LoadProperties != null)
entry.RefreshCache(LoadProperties);
return new ADDirectoryEntry(this.Domain, this, entry);
}
#region Searching
public IEnumerable<ADSearchResult> SearchEntireDomain(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
{
return SearchInternal(Domain.DistinguishedName, LdapFilter, LoadProperties, ResultLimit);
}
public IEnumerable<ADSearchResult> SearchScope(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
{
var searchScope = this.Domain.SearchContainers;
// No scope set, search entire domain
if (searchScope == null)
return SearchEntireDomain(LdapFilter, LoadProperties, ResultLimit);
// Ignore domain
if (searchScope.Count == 0)
return Enumerable.Empty<ADSearchResult>();
// Multi-search
var results = searchScope.SelectMany(scope => SearchInternal(scope, LdapFilter, LoadProperties, ResultLimit));
if (ResultLimit.HasValue)
results = results.Take(ResultLimit.Value);
return results;
}
internal IEnumerable<ADSearchResult> SearchInternal(string SearchRoot, string LdapFilter, string[] LoadProperties, int? ResultLimit)
{
if (string.IsNullOrEmpty(SearchRoot))
throw new ArgumentNullException("SearchRoot");
if (string.IsNullOrEmpty(LdapFilter))
throw new ArgumentNullException("LdapFilter");
if (ResultLimit.HasValue && ResultLimit.Value < 1)
throw new ArgumentOutOfRangeException("ResultLimit", "The ResultLimit must be 1 or greater");
using (ADDirectoryEntry rootEntry = this.RetrieveDirectoryEntry(SearchRoot))
{
using (DirectorySearcher searcher = new DirectorySearcher(rootEntry.Entry, LdapFilter, LoadProperties, System.DirectoryServices.SearchScope.Subtree))
{
searcher.PageSize = 500;
if (ResultLimit.HasValue)
searcher.SizeLimit = ResultLimit.Value;
return searcher.FindAll().Cast<SearchResult>().Select(result => new ADSearchResult(Domain, this, SearchRoot, LdapFilter, result));
}
}
}
#endregion
#region AD Objects
#region User Accounts
public ADUserAccount RetrieveADUserAccount(string Id, string[] AdditionalProperties = null)
{
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
? ADUserAccount.LoadProperties.Concat(AdditionalProperties).ToArray()
: ADUserAccount.LoadProperties;
var result = RetrieveBySamAccountName(Id, ADUserAccount.LdapSamAccountNameFilterTemplate, loadProperites);
if (result == null)
return null;
else
return result.AsADUserAccount(false, AdditionalProperties);
}
#endregion
#region Machine Accounts
public ADMachineAccount RetrieveADMachineAccount(string Id, System.Guid? UUIDNetbootGUID, System.Guid? MacAddressNetbootGUID, string[] AdditionalProperties = null)
{
if (string.IsNullOrWhiteSpace(Id))
throw new ArgumentNullException("Id");
// Add $ identifier for machine accounts
if (!Id.EndsWith("$"))
Id += "$";
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
? ADMachineAccount.LoadProperties.Concat(AdditionalProperties).ToArray()
: ADMachineAccount.LoadProperties;
ADSearchResult adResult;
adResult = RetrieveBySamAccountName(Id, ADMachineAccount.LdapSamAccountNameFilterTemplate, loadProperites);
if (adResult == null && (UUIDNetbootGUID.HasValue || MacAddressNetbootGUID.HasValue))
{
string ldapFilter;
if (UUIDNetbootGUID.HasValue && MacAddressNetbootGUID.HasValue)
{
ldapFilter = string.Format(ADMachineAccount.LdapNetbootGuidDoubleFilterTemplate, UUIDNetbootGUID.Value.ToLdapQueryFormat(), MacAddressNetbootGUID.Value.ToLdapQueryFormat());
}
else if (UUIDNetbootGUID.HasValue)
{
ldapFilter = string.Format(ADMachineAccount.LdapNetbootGuidSingleFilterTemplate, UUIDNetbootGUID.Value.ToLdapQueryFormat());
}
else // MacAddressNetbootGUID.HasValue
{
ldapFilter = string.Format(ADMachineAccount.LdapNetbootGuidSingleFilterTemplate, MacAddressNetbootGUID.Value.ToLdapQueryFormat());
}
adResult = this.SearchEntireDomain(ldapFilter, loadProperites, ActiveDirectory.SingleSearchResult).FirstOrDefault();
}
if (adResult != null)
return adResult.AsADMachineAccount(AdditionalProperties);
else
return null; // Not Found
}
public ADMachineAccount RetrieveADMachineAccount(string Id, string[] AdditionalProperties = null)
{
return RetrieveADMachineAccount(Id, null, null, AdditionalProperties);
}
public ADMachineAccount RetrieveADMachineAccount(string Id, System.Guid? NetbootGUID, string[] AdditionalProperties = null)
{
return RetrieveADMachineAccount(Id, NetbootGUID, null, AdditionalProperties);
}
#endregion
#region Groups
public ADGroup RetrieveADGroup(string Id)
{
var result = RetrieveBySamAccountName(Id, ADGroup.LdapSamAccountNameFilterTemplate, ADGroup.LoadProperties);
if (result == null)
return null;
else
return result.AsADGroup();
}
public ADGroup RetrieveADGroupByDistinguishedName(string DistinguishedName)
{
using (var groupEntry = this.RetrieveDirectoryEntry(DistinguishedName, ADGroup.LoadProperties))
{
if (groupEntry == null)
return null;
return groupEntry.AsADGroup();
}
}
public ADGroup RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier SecurityIdentifier)
{
if (SecurityIdentifier == null)
throw new ArgumentNullException("SecurityIdentifier");
if (!SecurityIdentifier.IsEqualDomainSid(this.Domain.SecurityIdentifier))
throw new ArgumentException(string.Format("The specified Security Identifier [{0}] does not belong to this domain [{1}]", SecurityIdentifier.ToString(), this.Domain.Name), "SecurityIdentifier");
var sidBinaryString = SecurityIdentifier.ToBinaryString();
string ldapFilter = string.Format(ADGroup.LdapSecurityIdentifierFilterTemplate, sidBinaryString);
var result = this.SearchEntireDomain(ldapFilter, ADGroup.LoadProperties, ActiveDirectory.SingleSearchResult).FirstOrDefault();
if (result == null)
return null;
else
return result.AsADGroup();
}
#endregion
#region Object
private const string ObjectLdapSamAccountNameFilter = "(&(|(objectCategory=Person)(objectCategory=Computer)(objectCategory=Group))(sAMAccountName={0}))";
private static readonly string[] ObjectLoadProperties = { "objectCategory" };
private static readonly string[] ObjectLoadPropertiesAll = ObjectLoadProperties.Concat(ADUserAccount.LoadProperties).Concat(ADMachineAccount.LoadProperties).Concat(ADGroup.LoadProperties).Distinct().ToArray();
public IADObject RetrieveADObject(string Id, bool Quick)
{
var result = RetrieveBySamAccountName(Id, ObjectLdapSamAccountNameFilter, ObjectLoadPropertiesAll);
if (result == null)
return null;
else
{
var objectCategory = result.Value<string>("objectCategory");
objectCategory = objectCategory.Substring(0, objectCategory.IndexOf(',')).ToLower();
switch (objectCategory)
{
case "cn=person":
return result.AsADUserAccount(Quick, null);
case "cn=computer":
return result.AsADMachineAccount(null);
case "cn=group":
return result.AsADGroup();
default:
throw new InvalidOperationException("Unexpected objectCategory");
}
}
}
#endregion
#region Organisational Units
private const string OrganisationalUnitsLdapFilter = "(objectCategory=organizationalUnit)";
private static readonly string[] OrganisationalUnitsLoadProperties = { "name", "distinguishedName" };
public List<ADOrganisationalUnit> RetrieveADOrganisationalUnitStructure()
{
Dictionary<string, List<ADOrganisationalUnit>> resultTree = new Dictionary<string, List<ADOrganisationalUnit>>();
var unsortedOrganisationalUnits = this.SearchEntireDomain(OrganisationalUnitsLdapFilter, OrganisationalUnitsLoadProperties)
.Select(r => r.AsADOrganisationalUnit()).ToList();
var indexedOrganisationalUnits = unsortedOrganisationalUnits.ToDictionary(k => k.DistinguishedName);
var indexedChildren = unsortedOrganisationalUnits
.GroupBy(ou => ou.DistinguishedName.Substring(ou.DistinguishedName.IndexOf(',') + 1))
.ToDictionary(g => g.Key, g => g.ToList());
// Link Children
foreach (var ouChildren in indexedChildren)
{
ADOrganisationalUnit ouParent;
if (indexedOrganisationalUnits.TryGetValue(ouChildren.Key, out ouParent))
{
ouParent.Children = ouChildren.Value;
}
}
return indexedChildren[Domain.DistinguishedName];
}
#endregion
private ADSearchResult RetrieveBySamAccountName(string Id, string LdapFilterTemplate, string[] LoadProperties)
{
var splitId = UserExtensions.SplitUserId(Id);
if (!this.Domain.NetBiosName.Equals(splitId.Item1, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException(string.Format("The Id [{0}] is invalid for this domain [{1}]", Id, this.Domain.Name), "Id");
var ldapFilter = string.Format(LdapFilterTemplate, splitId.Item2);
return this.SearchEntireDomain(ldapFilter, LoadProperties, ActiveDirectory.SingleSearchResult).FirstOrDefault();
}
#endregion
#region Actions
public bool IsReachable()
{
using (Ping p = new Ping())
{
var pr = p.Send(this.Name, 1000);
return (pr.Status == IPStatus.Success);
}
}
public string OfflineDomainJoinProvision(string ComputerSamAccountName, string OrganisationalUnit, ref ADMachineAccount MachineAccount, out string DiagnosticInformation)
{
if (MachineAccount != null && MachineAccount.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", MachineAccount.DistinguishedName));
if (!this.IsWritable)
throw new InvalidOperationException(string.Format("The domain controller [{0}] is not writable. This action (Offline Domain Join Provision) requires a writable domain controller.", this.Name));
StringBuilder diagnosticInfo = new StringBuilder();
string DJoinResult = null;
if (!string.IsNullOrWhiteSpace(ComputerSamAccountName))
ComputerSamAccountName = ComputerSamAccountName.TrimEnd('$');
if (!string.IsNullOrWhiteSpace(ComputerSamAccountName) && ComputerSamAccountName.Contains('\\'))
ComputerSamAccountName = ComputerSamAccountName.Substring(ComputerSamAccountName.IndexOf('\\') + 1);
if (string.IsNullOrWhiteSpace(ComputerSamAccountName) || ComputerSamAccountName.Length > 24)
throw new System.ArgumentException("Invalid Computer Name; > 0 and <= 24", "ComputerName");
// Ensure Specified OU Exists
if (!string.IsNullOrEmpty(OrganisationalUnit))
{
try
{
using (var deOU = this.RetrieveDirectoryEntry(OrganisationalUnit, new string[] { "distinguishedName" }))
{
if (deOU == null)
throw new Exception(string.Format("OU's Directory Entry couldn't be found at [{0}]", OrganisationalUnit));
}
}
catch (Exception ex)
{
throw new ArgumentException(string.Format("An error occurred while trying to locate the specified OU: {0}", OrganisationalUnit), "OrganisationalUnit", ex);
}
}
if (MachineAccount != null)
MachineAccount.DeleteAccount(this);
string tempFileName = System.IO.Path.GetTempFileName();
string argumentOU = (!string.IsNullOrWhiteSpace(OrganisationalUnit)) ? string.Format(" /MACHINEOU \"{0}\"", OrganisationalUnit) : string.Empty;
string arguments = string.Format("/PROVISION /DOMAIN \"{0}\" /DCNAME \"{1}\" /MACHINE \"{2}\"{3} /REUSE /SAVEFILE \"{4}\"",
this.Domain.Name,
this.Name,
ComputerSamAccountName,
argumentOU,
tempFileName
);
ProcessStartInfo commandStarter = new ProcessStartInfo("DJOIN.EXE", arguments)
{
CreateNoWindow = true,
ErrorDialog = false,
LoadUserProfile = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
diagnosticInfo.AppendFormat("{0} {1}", "DJOIN.EXE", arguments);
diagnosticInfo.AppendLine();
string stdOutput;
string stdError;
using (Process commandProc = Process.Start(commandStarter))
{
commandProc.WaitForExit(20000);
stdOutput = commandProc.StandardOutput.ReadToEnd();
stdError = commandProc.StandardError.ReadToEnd();
}
if (!string.IsNullOrWhiteSpace(stdOutput))
diagnosticInfo.AppendLine(stdOutput);
if (!string.IsNullOrWhiteSpace(stdError))
diagnosticInfo.AppendLine(stdError);
if (System.IO.File.Exists(tempFileName))
{
DJoinResult = System.Convert.ToBase64String(System.IO.File.ReadAllBytes(tempFileName));
System.IO.File.Delete(tempFileName);
}
if (string.IsNullOrWhiteSpace(DJoinResult))
throw new System.InvalidOperationException(string.Format("Domain Join Unsuccessful{0}Error: {1}{0}Output: {2}", System.Environment.NewLine, stdError, stdOutput));
DiagnosticInformation = diagnosticInfo.ToString();
// Reload Machine Account
MachineAccount = this.RetrieveADMachineAccount(string.Format(@"{0}\{1}", this.Domain.NetBiosName, ComputerSamAccountName), (MachineAccount == null ? null : MachineAccount.LoadedProperties.Keys.ToArray()));
return DJoinResult;
}
#endregion
public override string ToString()
{
return this.Name;
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is ADDomainController))
return false;
else
return this.Name == ((ADDomainController)obj).Name;
}
public override int GetHashCode()
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.Name);
}
}
}
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Security.Principal;
namespace Disco.Services.Interop.ActiveDirectory
{
public class ADGroup : IADObject
{
internal static readonly string[] LoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "memberOf" };
internal const string LdapSearchFilterTemplate = "(&(objectCategory=Group)(|(sAMAccountName=*{0}*)(name=*{0}*)(cn=*{0}*)))";
internal const string LdapSamAccountNameFilterTemplate = "(&(objectCategory=Group)(sAMAccountName={0}))";
internal const string LdapSecurityIdentifierFilterTemplate = "(&(objectCategory=Group)(objectSid={0}))";
public ADDomain Domain { get; private set; }
public string DistinguishedName { get; private set; }
public SecurityIdentifier SecurityIdentifier { get; private set; }
public string Id { get { return string.Format(@"{0}\{1}", Domain.NetBiosName, SamAccountName); } }
public string SamAccountName { get; private set; }
public string Name { get; private set; }
public string DisplayName { get { return this.Name; } }
public List<string> MemberOf { get; private set; }
private ADGroup(ADDomain Domain, string DistinguishedName, SecurityIdentifier SecurityIdentifier, string SamAccountName, string Name, List<string> MemberOf)
{
this.Domain = Domain;
this.DistinguishedName = DistinguishedName;
this.SecurityIdentifier = SecurityIdentifier;
this.SamAccountName = SamAccountName;
this.Name = Name;
this.MemberOf = MemberOf;
}
public static ADGroup FromSearchResult(ADSearchResult SearchResult)
{
if (SearchResult == null)
throw new ArgumentNullException("SearchResult");
var name = SearchResult.Value<string>("name");
var distinguishedName = SearchResult.Value<string>("distinguishedName");
var sAMAccountName = SearchResult.Value<string>("sAMAccountName");
var objectSid = new SecurityIdentifier(SearchResult.Value<byte[]>("objectSid"), 0);
var memberOf = SearchResult.Values<string>("memberOf").ToList();
return new ADGroup(SearchResult.Domain, distinguishedName, objectSid, sAMAccountName, name, memberOf);
}
public static ADGroup FromDirectoryEntry(ADDirectoryEntry DirectoryEntry)
{
if (DirectoryEntry == null)
throw new ArgumentNullException("DirectoryEntry");
var properties = DirectoryEntry.Entry.Properties;
var name = properties.Value<string>("name");
var distinguishedName = properties.Value<string>("distinguishedName");
var sAMAccountName = properties.Value<string>("sAMAccountName");
var objectSid = new SecurityIdentifier(properties.Value<byte[]>("objectSid"), 0);
var memberOf = properties.Values<string>("memberOf").ToList();
return new ADGroup(DirectoryEntry.Domain, distinguishedName, objectSid, sAMAccountName, name, memberOf);
}
public override string ToString()
{
return this.Id;
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is ADGroup))
return false;
else
return this.DistinguishedName == ((ADGroup)obj).DistinguishedName;
}
public override int GetHashCode()
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.DistinguishedName);
}
}
}
@@ -0,0 +1,66 @@
using System.Security.Principal;
using System.Text;
namespace Disco.Services.Interop.ActiveDirectory
{
internal static class ADHelpers
{
internal static byte[] ToBytes(this SecurityIdentifier Sid)
{
var sidBytes = new byte[Sid.BinaryLength];
Sid.GetBinaryForm(sidBytes, 0);
return sidBytes;
}
internal static SecurityIdentifier BuildPrimaryGroupSid(SecurityIdentifier UserSid, int PrimaryGroupId)
{
var groupSid = UserSid.ToBytes();
int ridOffset = groupSid.Length - 4;
int groupId = PrimaryGroupId;
for (int i = 0; i < 4; i++)
{
groupSid[ridOffset + i] = (byte)(groupId & 0xFF);
groupId >>= 8;
}
return new SecurityIdentifier(groupSid, 0);
}
internal static string ToBinaryString(this SecurityIdentifier Sid)
{
StringBuilder escapedSid = new StringBuilder();
foreach (var sidByte in Sid.ToBytes())
{
escapedSid.Append('\\');
escapedSid.Append(sidByte.ToString("x2"));
}
return escapedSid.ToString();
}
internal static string EscapeLdapQuery(string query)
{
return query.Replace("*", "\\2a").Replace("(", "\\28").Replace(")", "\\29").Replace("\\", "\\5c").Replace("NUL", "\\00").Replace("/", "\\2f");
}
internal static string ToLdapQueryFormat(this System.Guid g)
{
checked
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
byte[] array = g.ToByteArray();
for (int i = 0; i < array.Length; i++)
{
byte b = array[i];
sb.Append("\\");
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
}
}
}
@@ -0,0 +1,361 @@
using Disco.Models.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
namespace Disco.Services.Interop.ActiveDirectory
{
public class ADMachineAccount : IADObject
{
internal static readonly string[] LoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "dNSHostName", "netbootGUID", "isCriticalSystemObject" };
internal const string LdapSamAccountNameFilterTemplate = "(&(objectCategory=computer)(sAMAccountName={0}))";
internal const string LdapNetbootGuidSingleFilterTemplate = "(&(objectCategory=computer)(netbootGUID={0}))";
internal const string LdapNetbootGuidDoubleFilterTemplate = "(&(objectCategory=computer)(|(netbootGUID={0})(netbootGUID={1})))";
public ADDomain Domain { get; private set; }
public string DistinguishedName { get; private set; }
public SecurityIdentifier SecurityIdentifier { get; private set; }
public string Id { get { return string.Format(@"{0}\{1}", Domain.NetBiosName, SamAccountName); } }
public string SamAccountName { get; private set; }
public string Name { get; private set; }
public string DisplayName { get { return this.Name; } }
public string DnsName { get; private set; }
public Guid NetbootGUID { get; private set; }
public bool IsCriticalSystemObject { get; private set; }
public Dictionary<string, object[]> LoadedProperties { get; private set; }
public string ParentDistinguishedName
{
get
{
return DistinguishedName.Substring(DistinguishedName.IndexOf(',') + 1);
}
}
private ADMachineAccount(ADDomain Domain, string DistinguishedName, SecurityIdentifier SecurityIdentifier, string SamAccountName, string Name, string DnsName, Guid NetbootGUID, bool IsCriticalSystemObject, Dictionary<string, object[]> LoadedProperties)
{
this.Domain = Domain;
this.DistinguishedName = DistinguishedName;
this.SecurityIdentifier = SecurityIdentifier;
this.SamAccountName = SamAccountName;
this.Name = Name;
this.DnsName = DnsName;
this.NetbootGUID = NetbootGUID;
this.IsCriticalSystemObject = IsCriticalSystemObject;
this.LoadedProperties = LoadedProperties;
}
public static ADMachineAccount FromSearchResult(ADSearchResult SearchResult, string[] AdditionalProperties)
{
if (SearchResult == null)
throw new ArgumentNullException("SearchResult");
string name = SearchResult.Value<string>("name");
string sAMAccountName = SearchResult.Value<string>("sAMAccountName");
string distinguishedName = SearchResult.Value<string>("distinguishedName");
var objectSid = new SecurityIdentifier(SearchResult.Value<byte[]>("objectSid"), 0);
var dNSName = SearchResult.Value<string>("dNSHostName");
if (dNSName == null)
dNSName = string.Format("{0}.{1}", sAMAccountName.TrimEnd('$'), SearchResult.Domain.Name);
bool isCriticalSystemObject = SearchResult.Value<bool>("isCriticalSystemObject");
var netbootGUID = default(Guid);
byte[] netbootGuidBytes = SearchResult.Value<byte[]>("netbootGUID");
if (netbootGuidBytes != null)
netbootGUID = new Guid(netbootGuidBytes);
// Additional Properties
Dictionary<string, object[]> additionalProperties;
if (AdditionalProperties != null)
additionalProperties = AdditionalProperties
.Select(p => Tuple.Create(p, SearchResult.Values<object>(p).ToArray()))
.ToDictionary(t => t.Item1, t => t.Item2);
else
{
additionalProperties = new Dictionary<string, object[]>();
}
return new ADMachineAccount(
SearchResult.Domain,
distinguishedName,
objectSid,
sAMAccountName,
name,
dNSName,
netbootGUID,
isCriticalSystemObject,
additionalProperties);
}
public User ToRepositoryUser()
{
return new User
{
UserId = this.Id,
DisplayName = this.Name
};
}
public object GetPropertyValue(string PropertyName, int Index = 0)
{
switch (PropertyName.ToLower())
{
case "name":
return this.Name;
case "samaccountname":
return this.SamAccountName;
case "distinguishedname":
return this.DistinguishedName;
case "objectsid":
return this.SecurityIdentifier.ToString();
case "netbootguid":
return this.NetbootGUID;
default:
object[] adProperty;
if (this.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
return adProperty[Index];
else
return null;
}
}
#region Actions
public void DeleteAccount(ADDomainController WritableDomainController)
{
if (this.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account [{0}] is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
if (!WritableDomainController.IsWritable)
throw new InvalidOperationException(string.Format("The domain controller [{0}] is not writable. This action (Offline Domain Join Provision) requires a writable domain controller.", this.Name));
using (ADDirectoryEntry entry = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
{
entry.Entry.DeleteTree();
}
}
public void DeleteAccount()
{
this.DeleteAccount(Domain.GetAvailableDomainController(RequireWritable: true));
}
private void SetNetbootGUID(ADDomainController WritableDomainController, System.Guid updatedNetbootGUID)
{
if (this.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
using (var deAccount = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
{
var netbootGUIDProp = deAccount.Entry.Properties["netbootGUID"];
bool flag = netbootGUIDProp.Count > 0;
if (flag)
{
netbootGUIDProp.Clear();
}
netbootGUIDProp.Add(updatedNetbootGUID.ToByteArray());
deAccount.Entry.CommitChanges();
}
}
public void SetDescription(ADDomainController WritableDomainController, string Description)
{
using (var deAccount = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
{
var descriptionProp = deAccount.Entry.Properties["description"];
if (descriptionProp.Count > 0)
{
descriptionProp.Clear();
}
if (!string.IsNullOrEmpty(Description))
{
descriptionProp.Add(Description);
}
deAccount.Entry.CommitChanges();
}
}
public void SetDescription(string Description)
{
this.SetDescription(Domain.GetAvailableDomainController(RequireWritable: true), Description);
}
public void SetDescription(ADDomainController WritableDomainController, Device Device)
{
System.Text.StringBuilder descriptionBuilder = new System.Text.StringBuilder();
if (Device.AssignedUserId != null)
{
descriptionBuilder.Append(Device.AssignedUser.UserId).Append(" (").Append(Device.AssignedUser.DisplayName).Append("); ");
}
if (Device.DeviceModelId.HasValue)
{
descriptionBuilder.Append(Device.DeviceModel.Description).Append("; ");
}
descriptionBuilder.Append(Device.DeviceProfile.Description).Append(";");
string description = descriptionBuilder.ToString().Trim();
if (description.Length > 1024)
description = description.Substring(0, 1024);
this.SetDescription(WritableDomainController, description);
}
public void SetDescription(Device Device)
{
this.SetDescription(Domain.GetAvailableDomainController(RequireWritable: true), Device);
}
public void DisableAccount(ADDomainController WritableDomainController)
{
if (this.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
using (var deAccount = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
{
int accountControl = (int)deAccount.Entry.Properties["userAccountControl"][0];
int updatedAccountControl = (accountControl | 2);
if (accountControl != updatedAccountControl)
{
deAccount.Entry.Properties["userAccountControl"][0] = updatedAccountControl;
deAccount.Entry.CommitChanges();
}
}
}
public void DisableAccount()
{
this.DisableAccount(Domain.GetAvailableDomainController(RequireWritable: true));
}
public void EnableAccount(ADDomainController WritableDomainController)
{
if (this.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
using (var deAccount = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
{
int accountControl = (int)deAccount.Entry.Properties["userAccountControl"][0];
if ((accountControl & 2) == 2)
{
int updatedAccountControl = (accountControl ^ 2);
deAccount.Entry.Properties["userAccountControl"][0] = updatedAccountControl;
deAccount.Entry.CommitChanges();
}
}
}
public void EnableAccount()
{
this.EnableAccount(Domain.GetAvailableDomainController(RequireWritable: true));
}
public bool UpdateNetbootGUID(ADDomainController WritableDomainController, string UUID, string MACAddress)
{
if (this.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
Guid netbootGUID = Guid.Empty;
if (!string.IsNullOrWhiteSpace(UUID))
{
netbootGUID = NetbootGUIDFromUUID(UUID);
}
else if (!string.IsNullOrWhiteSpace(MACAddress))
{
netbootGUID = NetbootGUIDFromMACAddress(MACAddress);
}
if (netbootGUID != System.Guid.Empty && netbootGUID != this.NetbootGUID)
{
this.SetNetbootGUID(WritableDomainController, netbootGUID);
return true;
}
else
{
return false;
}
}
public void UpdateNetbootGUID(string UUID, string MACAddress)
{
this.UpdateNetbootGUID(Domain.GetAvailableDomainController(RequireWritable: true), UUID, MACAddress);
}
public static System.Guid NetbootGUIDFromUUID(string UUID)
{
return new Guid(UUID);
}
public static System.Guid NetbootGUIDFromMACAddress(string MACAddress)
{
string strippedMACAddress = MACAddress.Trim().Replace(":", string.Empty).Replace("-", string.Empty);
bool flag = strippedMACAddress.Length == 12;
System.Guid NetbootGUIDFromMACAddress;
if (flag)
{
System.Guid guid = new System.Guid(string.Format("00000000-0000-0000-0000-{0}", strippedMACAddress));
NetbootGUIDFromMACAddress = guid;
}
else
{
NetbootGUIDFromMACAddress = System.Guid.Empty;
}
return NetbootGUIDFromMACAddress;
}
public void MoveOrganisationalUnit(ADDomainController WritableDomainController, string NewOrganisationUnit)
{
if (this.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
var parentDistinguishedName = this.ParentDistinguishedName;
if (parentDistinguishedName != null && !parentDistinguishedName.Equals(NewOrganisationUnit, StringComparison.OrdinalIgnoreCase))
{
// If no OU provided, place in default Computers container
if (string.IsNullOrWhiteSpace(NewOrganisationUnit))
NewOrganisationUnit = Domain.DefaultComputerContainer;
if (!NewOrganisationUnit.EndsWith(Domain.DistinguishedName, StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException(string.Format("Unable to move AD Account from one domain [{0}] to another [{1}].", this.DistinguishedName, NewOrganisationUnit));
using (ADDirectoryEntry ou = WritableDomainController.RetrieveDirectoryEntry(NewOrganisationUnit))
{
using (ADDirectoryEntry i = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
{
i.Entry.UsePropertyCache = false;
i.Entry.MoveTo(ou.Entry);
// Update Distinguished Name
this.DistinguishedName = i.Entry.Properties["distinguishedName"][0].ToString();
}
}
}
}
public void MoveOrganisationalUnit(string NewOrganisationUnit)
{
this.MoveOrganisationalUnit(Domain.GetAvailableDomainController(RequireWritable: true), NewOrganisationUnit);
}
#endregion
public override string ToString()
{
return this.Id;
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is ADMachineAccount))
return false;
else
return this.DistinguishedName == ((ADMachineAccount)obj).DistinguishedName;
}
public override int GetHashCode()
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.DistinguishedName);
}
}
}
@@ -0,0 +1,46 @@
using System.Collections.Generic;
namespace Disco.Services.Interop.ActiveDirectory
{
public class ADOrganisationalUnit
{
public ADDomain Domain { get; private set; }
public string DistinguishedName { get; private set; }
public string Name { get; private set; }
public List<ADOrganisationalUnit> Children { get; internal set; }
private ADOrganisationalUnit(ADDomain Domain, string DistinguishedName, string Name, List<ADOrganisationalUnit> Children)
{
this.Domain = Domain;
this.DistinguishedName = DistinguishedName;
this.Name = Name;
this.Children = Children;
}
public static ADOrganisationalUnit FromSearchResult(ADSearchResult SearchResult)
{
string distinguishedName = SearchResult.Value<string>("distinguishedName");
string name = SearchResult.Value<string>("name");
return new ADOrganisationalUnit(SearchResult.Domain, distinguishedName, name, null);
}
public override string ToString()
{
return this.Name;
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is ADOrganisationalUnit))
return false;
else
return this.DistinguishedName == ((ADOrganisationalUnit)obj).DistinguishedName;
}
public override int GetHashCode()
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.DistinguishedName);
}
}
}
@@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
namespace Disco.Services.Interop.ActiveDirectory
{
public class ADSearchResult
{
private SearchResult _result;
public ADDomain Domain { get; private set; }
public ADDomainController DomainController { get; private set; }
public string SearchPath { get; private set; }
public string LdapFilter { get; private set; }
public string LdapPath { get; private set; }
public string DistinguishedName { get; private set; }
public ADSearchResult(ADDomain Domain, ADDomainController DomainController, string SearchPath, string LdapFilter, SearchResult Result)
{
this._result = Result;
this.Domain = Domain;
this.DomainController = DomainController;
this.SearchPath = SearchPath;
this.LdapFilter = LdapFilter;
this.LdapPath = _result.Path;
this.DistinguishedName = Value<string>("dn");
}
public bool Contains(string PropertyName)
{
return _result.Properties.Contains(PropertyName);
}
public T Value<T>(string PropertyName)
{
var p = Values<T>(PropertyName);
return p.FirstOrDefault();
}
public IEnumerable<T> Values<T>(string PropertyName)
{
var p = _result.Properties[PropertyName];
return p.OfType<T>();
}
public override string ToString()
{
return this.LdapPath;
}
}
}
@@ -0,0 +1,49 @@
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
namespace Disco.Services.Interop.ActiveDirectory
{
public class ADSite
{
private ActiveDirectoryContext context;
public ActiveDirectorySite Site { get; private set; }
public string Name { get; private set; }
public List<ADDomainController> DomainControllers { get; private set; }
public ADSite(ActiveDirectoryContext Context, ActiveDirectorySite Site)
{
this.context = Context;
this.Site = Site;
this.Name = Site.Name;
this.DomainControllers = null;
}
internal void UpdateDomainControllers(IEnumerable<ADDomainController> DomainControllers)
{
this.DomainControllers = DomainControllers.ToList();
}
public override string ToString()
{
return this.Name;
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is ADSite))
return false;
else
return this.Name == ((ADSite)obj).Name;
}
public override int GetHashCode()
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.Name);
}
}
}
@@ -0,0 +1,205 @@
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 ADTaskUpdateNetworkLogonDates : 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)
{
// ActiveDirectoryUpdateLastNetworkLogonDateJob @ 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(ADTaskUpdateNetworkLogonDates)).Where(s => s.IsRunning).FirstOrDefault();
if (existingTask != null)
return existingTask;
var instance = new ADTaskUpdateNetworkLogonDates();
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))
{
var context = ActiveDirectory.Context;
var deviceSamAccountName = UserExtensions.SplitUserId(Device.DeviceDomainId).Item2 + "$";
var ldapFilter = string.Format(ldapFilterTemplate, ADHelpers.EscapeLdapQuery(deviceSamAccountName));
var domain = context.GetDomainFromId(Device.DeviceDomainId);
IEnumerable<ADDomainController> domainControllers;
if (context.SearchAllForestServers)
domainControllers = domain.GetAllReachableDomainControllers();
else
domainControllers = domain.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;
}
private static void UpdateLastNetworkLogonDates(DiscoDataContext Database, ScheduledTaskStatus 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;
}
}
}
}
}
}
@@ -0,0 +1,173 @@
using Disco.Models.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
namespace Disco.Services.Interop.ActiveDirectory
{
public class ADUserAccount : IADObject
{
internal const string LdapSamAccountNameFilterTemplate = "(&(objectCategory=Person)(sAMAccountName={0}))";
internal const string LdapSearchFilterTemplate = "(&(objectCategory=Person)(objectClass=user)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))";
internal static readonly string[] LoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "displayName", "sn", "givenName", "memberOf", "primaryGroupID", "mail", "telephoneNumber" };
internal static readonly string[] QuickLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "displayName", "sn", "givenName", "mail", "telephoneNumber" };
public ADDomain Domain { get; private set; }
public string DistinguishedName { get; private set; }
public SecurityIdentifier SecurityIdentifier { get; private set; }
public string Id { get { return string.Format(@"{0}\{1}", Domain.NetBiosName, SamAccountName); } }
public string SamAccountName { get; private set; }
public string Name { get; private set; }
public string DisplayName { get; private set; }
public string Surname { get; private set; }
public string GivenName { get; private set; }
public string Email { get; private set; }
public string Phone { get; private set; }
public List<ADGroup> Groups { get; private set; }
public Dictionary<string, object[]> LoadedProperties { get; private set; }
private ADUserAccount(ADDomain Domain, string DistinguishedName, SecurityIdentifier SecurityIdentifier, string SamAccountName,
string Name, string DisplayName, string Surname, string GivenName, string Email, string Phone,
List<ADGroup> Groups, Dictionary<string, object[]> LoadedProperties)
{
this.Domain = Domain;
this.DistinguishedName = DistinguishedName;
this.SecurityIdentifier = SecurityIdentifier;
this.SamAccountName = SamAccountName;
this.Name = Name;
this.DisplayName = DisplayName;
this.Surname = Surname;
this.GivenName = GivenName;
this.Email = Email;
this.Phone = Phone;
this.Groups = Groups;
this.LoadedProperties = LoadedProperties;
}
public static ADUserAccount FromSearchResult(ADSearchResult SearchResult, bool Quick, string[] AdditionalProperties)
{
if (SearchResult == null)
throw new ArgumentNullException("SearchResult");
string name = SearchResult.Value<string>("name");
string sAMAccountName = SearchResult.Value<string>("sAMAccountName");
string distinguishedName = SearchResult.Value<string>("distinguishedName");
var objectSid = new SecurityIdentifier(SearchResult.Value<byte[]>("objectSid"), 0);
var displayName = SearchResult.Value<string>("displayName") ?? sAMAccountName;
var surname = SearchResult.Value<string>("sn");
string givenName = SearchResult.Value<string>("givenName");
string email = SearchResult.Value<string>("mail");
string phone = SearchResult.Value<string>("telephoneNumber");
List<ADGroup> groups = null;
// Don't load Groups when doing a quick search
if (!Quick)
{
int primaryGroupID = (int)SearchResult.Value<int>("primaryGroupID");
var primaryGroupSid = ADHelpers.BuildPrimaryGroupSid(objectSid, primaryGroupID);
var memberGroups = SearchResult.Values<string>("memberOf");
var primaryGroup = ActiveDirectory.GroupCache.GetGroup(primaryGroupSid);
var groupDistinguishedNames =
new string[] { primaryGroup.DistinguishedName }
.Concat(memberGroups);
groups = ActiveDirectory.GroupCache.GetRecursiveGroups(groupDistinguishedNames).ToList();
}
// Additional Properties
Dictionary<string, object[]> additionalProperties;
if (AdditionalProperties != null)
additionalProperties = AdditionalProperties
.Select(p => Tuple.Create(p, SearchResult.Values<object>(p).ToArray()))
.ToDictionary(t => t.Item1, t => t.Item2);
else
{
additionalProperties = new Dictionary<string, object[]>();
}
return new ADUserAccount(
SearchResult.Domain,
distinguishedName,
objectSid,
sAMAccountName,
name,
displayName,
surname,
givenName,
email,
phone,
groups,
additionalProperties);
}
public object GetPropertyValue(string PropertyName, int Index = 0)
{
switch (PropertyName.ToLower())
{
case "name":
return this.Name;
case "samaccountname":
return this.SamAccountName;
case "distinguishedname":
return this.DistinguishedName;
case "objectsid":
return this.SecurityIdentifier.ToString();
case "sn":
return this.Surname;
case "givenname":
return this.GivenName;
case "mail":
return this.Email;
case "telephonenumber":
return this.Phone;
default:
object[] adProperty;
if (this.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
return adProperty[Index];
else
return null;
}
}
public User ToRepositoryUser()
{
return new User
{
UserId = this.Id,
DisplayName = this.DisplayName,
Surname = this.Surname,
GivenName = this.GivenName,
EmailAddress = this.Email,
PhoneNumber = this.Phone,
};
}
public override string ToString()
{
return this.Id;
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is ADUserAccount))
return false;
else
return this.DistinguishedName == ((ADUserAccount)obj).DistinguishedName;
}
public override int GetHashCode()
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.DistinguishedName);
}
}
}
@@ -1,595 +1,226 @@
using Disco.Data.Repository;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Interop.ActiveDirectory.Internal;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Diagnostics;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Interop.ActiveDirectory
{
public static class ActiveDirectory
{
private const int SingleSearchResult = 1;
public const int SingleSearchResult = 1;
public const int DefaultSearchResultLimit = 30;
public const int MaxForestServerSearch = 30;
public const int DomainControllerUnavailableMinutes = 10;
private static ActiveDirectoryContext context;
private static ActiveDirectoryGroupCache groupCache;
private static object contextInitializingLock = new object();
public static void Initialize(DiscoDataContext Database)
{
ADInterop.Initialize(Database);
}
public static void UpdateSearchContainers(DiscoDataContext Database, List<string> Containers)
{
ADInterop.UpdateSearchContainers(Database, Containers);
}
public static bool UpdateSearchEntireForest(DiscoDataContext Database, bool SearchEntireForest)
{
return ADInterop.UpdateSearchEntireForest(Database, SearchEntireForest);
}
public static ActiveDirectoryDomain PrimaryDomain
{
get
lock (contextInitializingLock)
{
return ADInterop.PrimaryDomain;
}
}
public static IEnumerable<ActiveDirectoryDomain> Domains
{
get
{
return ADInterop.Domains.ToList();
context = new ActiveDirectoryContext(Database);
groupCache = new ActiveDirectoryGroupCache();
}
}
public static ActiveDirectorySite Site
public static ActiveDirectoryContext Context
{
get
{
return ADInterop.Site;
}
}
public static ActiveDirectoryDomain GetDomainByDistinguishedName(string DistinguishedName)
{
return ADInterop.GetDomainByDistinguishedName(DistinguishedName);
}
public static ActiveDirectoryDomain GetDomainByNetBiosName(string NetBiosName)
{
return ADInterop.GetDomainByNetBiosName(NetBiosName);
}
public static ActiveDirectoryDomain GetDomainByDnsName(string DnsName)
{
return ADInterop.GetDomainByDnsName(DnsName);
}
public static ActiveDirectoryDomain GetDomainFromId(string Id)
{
return ADInterop.GetDomainFromId(Id);
}
public static List<string> LoadForestServers()
{
return ADInterop.LoadForestServers();
}
public static Task<List<string>> LoadForestServersAsync()
{
return ADInterop.LoadForestServersAsync();
}
public static bool SearchEntireForest
{
get
{
return ADInterop.SearchEntireForest;
}
}
#region Machine Account
private static readonly string[] MachineLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "dNSHostName", "netbootGUID", "isCriticalSystemObject" };
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(DomainController DomainController, string Id, params string[] AdditionalProperties)
{
return RetrieveMachineAccount(DomainController, Id, (System.Guid?)null, (System.Guid?)null, AdditionalProperties);
}
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(string Id, params string[] AdditionalProperties)
{
return RetrieveMachineAccount(Id, (System.Guid?)null, (System.Guid?)null, AdditionalProperties);
}
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(DomainController DomainController, string Id, System.Guid? UUIDNetbootGUID, params string[] AdditionalProperties)
{
return RetrieveMachineAccount(DomainController, Id, UUIDNetbootGUID, (System.Guid?)null, AdditionalProperties);
}
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(string Id, System.Guid? UUIDNetbootGUID, params string[] AdditionalProperties)
{
return RetrieveMachineAccount(Id, UUIDNetbootGUID, (System.Guid?)null, AdditionalProperties);
}
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(string Id, System.Guid? UUIDNetbootGUID, System.Guid? MacAddressNetbootGUID, params string[] AdditionalProperties)
{
return RetrieveMachineAccount(null, Id, UUIDNetbootGUID, MacAddressNetbootGUID, AdditionalProperties);
}
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(DomainController DomainController, string Id, System.Guid? UUIDNetbootGUID, System.Guid? MacAddressNetbootGUID, params string[] AdditionalProperties)
{
if (string.IsNullOrWhiteSpace(Id))
throw new ArgumentNullException("Id");
// Add $ identifier for machine accounts
if (!Id.EndsWith("$"))
Id += "$";
const string ldapFilterTemplate = "(&(objectCategory=computer)(sAMAccountName={0}))";
const string ldapNetbootGuidFilterTemplate = "(&(objectCategory=computer)(netbootGUID={0}))";
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
? MachineLoadProperties.Concat(AdditionalProperties).ToArray()
: MachineLoadProperties;
ActiveDirectorySearchResult adResult;
var splitId = UserExtensions.SplitUserId(Id);
var ldapSamAccountFilter = string.Format(ldapFilterTemplate, splitId.Item2);
var domain = ADInterop.GetDomainFromId(Id);
adResult = ADInterop.SearchAll(domain, DomainController, ldapSamAccountFilter, SingleSearchResult, loadProperites).FirstOrDefault();
if (adResult == null && (UUIDNetbootGUID.HasValue || MacAddressNetbootGUID.HasValue))
{
if (UUIDNetbootGUID.HasValue)
if (context == null)
{
var ldapFilter = string.Format(ldapNetbootGuidFilterTemplate, ADInterop.FormatGuidForLdapQuery(UUIDNetbootGUID.Value));
adResult = ADInterop.SearchAll(domain, DomainController, ldapFilter, SingleSearchResult, loadProperites).FirstOrDefault();
lock (contextInitializingLock)
{
if (context == null)
throw new InvalidOperationException("Active Directory interoperability hasn't been initialized");
}
}
if (adResult == null && MacAddressNetbootGUID.HasValue)
{
var ldapFilter = string.Format(ldapNetbootGuidFilterTemplate, ADInterop.FormatGuidForLdapQuery(MacAddressNetbootGUID.Value));
adResult = ADInterop.SearchAll(domain, DomainController, ldapFilter, SingleSearchResult, loadProperites).FirstOrDefault();
}
}
if (adResult != null)
return adResult.AsMachineAccount(AdditionalProperties);
return context;
}
}
public static ActiveDirectoryGroupCache GroupCache
{
get
{
if (groupCache == null)
{
lock (contextInitializingLock)
{
if (groupCache == null)
throw new InvalidOperationException("Active Directory interoperability hasn't been initialized");
}
}
return groupCache;
}
}
#region User Accounts
public static ADUserAccount RetrieveADUserAccount(string Id, params string[] AdditionalProperties)
{
var domain = Context.GetDomainFromId(Id);
return domain.GetAvailableDomainController().RetrieveADUserAccount(Id, AdditionalProperties);
}
public static IEnumerable<ADUserAccount> SearchADUserAccounts(string Term, bool Quick, int? ResultLimit = ActiveDirectory.DefaultSearchResultLimit, params string[] AdditionalProperties)
{
if (string.IsNullOrWhiteSpace(Term))
throw new ArgumentNullException("Term");
ADDomain searchDomain;
var term = RelevantSearchTerm(Term, out searchDomain);
if (string.IsNullOrWhiteSpace(term))
return Enumerable.Empty<ADUserAccount>();
var ldapFilter = string.Format(ADUserAccount.LdapSearchFilterTemplate, ADHelpers.EscapeLdapQuery(term));
IEnumerable<ADSearchResult> searchResults;
if (searchDomain != null)
searchResults = searchDomain.SearchScope(ldapFilter, ADGroup.LoadProperties, ResultLimit);
else
return null; // Not Found
}
searchResults = Context.SearchScope(ldapFilter, ADGroup.LoadProperties, ResultLimit);
private static ActiveDirectoryMachineAccount AsMachineAccount(this ActiveDirectorySearchResult item, string[] AdditionalProperties)
{
string name = item.Result.Properties["name"][0].ToString();
string sAMAccountName = item.Result.Properties["sAMAccountName"][0].ToString();
string distinguishedName = item.Result.Properties["distinguishedName"][0].ToString();
string objectSid = ADInterop.ConvertBytesToSDDLString((byte[])item.Result.Properties["objectSid"][0]);
var dNSNameProperty = item.Result.Properties["dNSHostName"];
string dNSName = null;
if (dNSNameProperty.Count > 0)
dNSName = dNSNameProperty[0].ToString();
else
dNSName = string.Format("{0}.{1}", sAMAccountName.TrimEnd('$'), item.Domain.DnsName);
bool isCriticalSystemObject = (bool)item.Result.Properties["isCriticalSystemObject"][0];
System.Guid netbootGUIDResult = default(System.Guid);
ResultPropertyValueCollection netbootGUIDProp = item.Result.Properties["netbootGUID"];
if (netbootGUIDProp.Count > 0)
{
netbootGUIDResult = new System.Guid((byte[])netbootGUIDProp[0]);
}
// Additional Properties
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
if (AdditionalProperties != null)
foreach (string propertyName in AdditionalProperties)
{
var property = item.Result.Properties[propertyName];
var propertyValues = new List<object>();
for (int index = 0; index < property.Count; index++)
propertyValues.Add(property[index]);
additionalProperties.Add(propertyName, propertyValues.ToArray());
}
return new ActiveDirectoryMachineAccount
{
Name = name,
DistinguishedName = distinguishedName,
SamAccountName = sAMAccountName,
SecurityIdentifier = objectSid,
NetbootGUID = netbootGUIDResult,
Path = item.Result.Path,
Domain = item.Domain.NetBiosName,
DnsName = dNSName,
IsCriticalSystemObject = isCriticalSystemObject,
LoadedProperties = additionalProperties
};
}
public static string OfflineDomainJoinProvision(ActiveDirectoryDomain Domain, DomainController DomainController, string ComputerName, string OrganisationalUnit, ref ActiveDirectoryMachineAccount MachineAccount, out string DiagnosticInformation)
{
const string ldapFilterTemplate = "(&(objectCategory=computer)(sAMAccountName={0}))";
if (MachineAccount != null && MachineAccount.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", MachineAccount.DistinguishedName));
if (MachineAccount != null)
MachineAccount.DeleteAccount(DomainController);
var computerId = UserExtensions.SplitUserId(ComputerName);
var offlineJoinResult = ADInterop.OfflineDomainJoinProvision(Domain, DomainController, computerId.Item2, OrganisationalUnit, out DiagnosticInformation);
// Reload newly created Account
string[] loadAdditionalProperties = (MachineAccount != null && MachineAccount.LoadedProperties != null && MachineAccount.LoadedProperties.Count > 0)
? MachineAccount.LoadedProperties.Keys.ToArray()
: null;
MachineAccount = null;
string[] loadProperites = (loadAdditionalProperties != null)
? MachineLoadProperties.Concat(loadAdditionalProperties).ToArray()
: MachineLoadProperties;
var ldapSamAccountName = computerId.Item2.EndsWith("$") ? computerId.Item2 : computerId.Item2 + "$";
var ldapFilter = string.Format(ldapFilterTemplate, ldapSamAccountName);
var ldapResult = ADInterop.SearchAll(Domain, DomainController, ldapFilter, 1, loadProperites).FirstOrDefault();
if (ldapResult != null)
MachineAccount = ldapResult.AsMachineAccount(loadAdditionalProperties);
return offlineJoinResult;
return searchResults.Select(result => result.AsADUserAccount(Quick, AdditionalProperties));
}
#endregion
#region User Account
private static readonly string[] UserLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "displayName", "sn", "givenName", "memberOf", "primaryGroupID", "mail", "telephoneNumber" };
private static readonly string[] UserQuickLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "displayName", "sn", "givenName", "mail", "telephoneNumber" };
public static ActiveDirectoryUserAccount RetrieveUserAccount(string Id, params string[] AdditionalProperties)
#region Machine Accounts
public static ADMachineAccount RetrieveADMachineAccount(string Id, params string[] AdditionalProperties)
{
const string ldapFilter = "(&(objectCategory=Person)(sAMAccountName={0}))";
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
? UserLoadProperties.Concat(AdditionalProperties).ToArray()
: UserLoadProperties;
return SearchBySamAccountName(Id, ldapFilter, loadProperites).Select(result => result.AsUserAccount(false, AdditionalProperties)).FirstOrDefault();
var domain = Context.GetDomainFromId(Id);
return domain.GetAvailableDomainController().RetrieveADMachineAccount(Id, AdditionalProperties);
}
public static IEnumerable<ActiveDirectoryUserAccount> SearchUserAccounts(string Term, params string[] AdditionalProperties)
public static ADMachineAccount RetrieveADMachineAccount(string Id, System.Guid? NetbootGUID, params string[] AdditionalProperties)
{
return SearchUserAccounts(Term, false, AdditionalProperties);
var domain = Context.GetDomainFromId(Id);
return domain.GetAvailableDomainController().RetrieveADMachineAccount(Id, NetbootGUID, AdditionalProperties);
}
public static IEnumerable<ActiveDirectoryUserAccount> SearchUserAccounts(string Term, bool Quick, params string[] AdditionalProperties)
public static ADMachineAccount RetrieveADMachineAccount(string Id, System.Guid? UUIDNetbootGUID, System.Guid? MacAddressNetbootGUID, params string[] AdditionalProperties)
{
const int resultLimit = 30; // Default Search Limit
if (string.IsNullOrWhiteSpace(Term))
throw new ArgumentNullException("Term");
// Apply Domain Restriction
ActiveDirectoryDomain searchDomain = null;
Term = ApplySearchTermDomainRestriction(Term, out searchDomain);
if (string.IsNullOrWhiteSpace(Term))
return Enumerable.Empty<ActiveDirectoryUserAccount>();
string ldapFilter = string.Format("(&(objectCategory=Person)(objectClass=user)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))", ADInterop.EscapeLdapQuery(Term));
string[] loadProperites = Quick
? UserQuickLoadProperties
: UserLoadProperties;
if (AdditionalProperties != null && AdditionalProperties.Length > 0)
loadProperites.Concat(AdditionalProperties).ToArray();
IEnumerable<ActiveDirectorySearchResult> searchResults;
if (searchDomain == null)
searchResults = ADInterop.SearchScope(ldapFilter, resultLimit, loadProperites);
else
searchResults = ADInterop.SearchScope(searchDomain, ldapFilter, resultLimit, loadProperites);
return searchResults.Select(result => result.AsUserAccount(Quick, AdditionalProperties));
}
private static ActiveDirectoryUserAccount AsUserAccount(this ActiveDirectorySearchResult item, bool Quick, string[] AdditionalProperties)
{
string name = item.Result.Properties["name"][0].ToString();
string username = item.Result.Properties["sAMAccountName"][0].ToString();
string distinguishedName = item.Result.Properties["distinguishedName"][0].ToString();
byte[] objectSid = (byte[])item.Result.Properties["objectSid"][0];
string objectSidSDDL = ADInterop.ConvertBytesToSDDLString(objectSid);
List<string> groups = null;
ResultPropertyValueCollection displayNameProp = item.Result.Properties["displayName"];
string displayName = username;
if (displayNameProp.Count > 0)
displayName = displayNameProp[0].ToString();
string surname = null;
ResultPropertyValueCollection surnameProp = item.Result.Properties["sn"];
if (surnameProp.Count > 0)
surname = surnameProp[0].ToString();
string givenName = null;
ResultPropertyValueCollection givenNameProp = item.Result.Properties["givenName"];
if (givenNameProp.Count > 0)
givenName = givenNameProp[0].ToString();
string email = null;
ResultPropertyValueCollection emailProp = item.Result.Properties["mail"];
if (emailProp.Count > 0)
email = emailProp[0].ToString();
string phone = null;
ResultPropertyValueCollection phoneProp = item.Result.Properties["telephoneNumber"];
if (phoneProp.Count > 0)
phone = phoneProp[0].ToString();
// Don't load Groups when doing a quick search
if (!Quick)
{
int primaryGroupID = (int)item.Result.Properties["primaryGroupID"][0];
string primaryGroupSid = ADInterop.ConvertBytesToSDDLString(ADInterop.BuildPrimaryGroupSid(objectSid, primaryGroupID));
var groupDistinguishedNames = item.Result.Properties["memberOf"].Cast<string>().ToList();
groupDistinguishedNames.Add(ADGroupCache.GetGroupsDistinguishedNameForSecurityIdentifier(primaryGroupSid));
groups = ADGroupCache.GetGroups(groupDistinguishedNames).ToList();
}
// Additional Properties
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
if (AdditionalProperties != null && AdditionalProperties.Length > 0)
foreach (string propertyName in AdditionalProperties)
{
var property = item.Result.Properties[propertyName];
var propertyValues = new List<object>();
for (int index = 0; index < property.Count; index++)
propertyValues.Add(property[index]);
additionalProperties.Add(propertyName, propertyValues.ToArray());
}
return new ActiveDirectoryUserAccount
{
Domain = item.Domain.NetBiosName,
Name = name,
Surname = surname,
GivenName = givenName,
Email = email,
Phone = phone,
DistinguishedName = distinguishedName,
SamAccountName = username,
DisplayName = displayName,
SecurityIdentifier = objectSidSDDL,
Groups = groups,
Path = item.Result.Path,
LoadedProperties = additionalProperties
};
var domain = Context.GetDomainFromId(Id);
return domain.GetAvailableDomainController().RetrieveADMachineAccount(Id, UUIDNetbootGUID, MacAddressNetbootGUID, AdditionalProperties);
}
#endregion
#region Groups
private static readonly string[] GroupLoadProperties = { "name", "distinguishedName", "cn", "sAMAccountName", "objectSid", "memberOf" };
public static ActiveDirectoryGroup RetrieveGroup(string Id)
public static ADGroup RetrieveADGroup(string Id)
{
const string ldapFilter = "(&(objectCategory=Group)(objectSid={0}))";
return SearchBySamAccountName(Id, ldapFilter, GroupLoadProperties).Select(result => result.AsGroup()).FirstOrDefault();
var domain = Context.GetDomainFromId(Id);
return domain.GetAvailableDomainController().RetrieveADGroup(Id);
}
public static ActiveDirectoryGroup RetrieveGroupWithDistinguishedName(string DistinguishedName)
public static ADGroup RetrieveADGroupByDistinguishedName(string DistinguishedName)
{
ActiveDirectoryDomain domain;
using (var groupEntry = ADInterop.RetrieveDirectoryEntry(DistinguishedName, out domain))
{
if (groupEntry == null)
return null;
return groupEntry.AsGroup(domain);
}
var domain = Context.GetDomainFromDistinguishedName(DistinguishedName);
return domain.GetAvailableDomainController().RetrieveADGroupByDistinguishedName(DistinguishedName);
}
public static ActiveDirectoryGroup RetrieveGroupWithSecurityIdentifier(string SecurityIdentifier)
public static ADGroup RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier SecurityIdentifier)
{
const int resultLimit = 1;
if (string.IsNullOrWhiteSpace(SecurityIdentifier))
throw new ArgumentNullException("SecurityIdentifier");
var sidBytes = ADInterop.ConvertSDDLStringToBytes(SecurityIdentifier);
var sidBinaryString = ADInterop.ConvertBytesToBinarySidString(sidBytes);
string ldapFilter = string.Format("(&(objectCategory=Group)(objectSid={0}))", sidBinaryString);
return ADInterop.SearchAll(ldapFilter, resultLimit, null).Select(result => result.AsGroup()).FirstOrDefault();
var domain = Context.GetDomainFromSecurityIdentifier(SecurityIdentifier);
return domain.GetAvailableDomainController().RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier);
}
public static IEnumerable<ActiveDirectoryGroup> SearchGroups(string Term)
{
const int resultLimit = 30; // Default Search Limit
public static IEnumerable<ADGroup> SearchADGroups(string Term, int? ResultLimit = ActiveDirectory.DefaultSearchResultLimit)
{
if (string.IsNullOrWhiteSpace(Term))
throw new ArgumentNullException("Term");
// Apply Domain Restriction
ActiveDirectoryDomain searchDomain = null;
Term = ApplySearchTermDomainRestriction(Term, out searchDomain);
ADDomain searchDomain;
var term = RelevantSearchTerm(Term, out searchDomain);
if (string.IsNullOrWhiteSpace(Term))
return Enumerable.Empty<ActiveDirectoryGroup>();
if (string.IsNullOrWhiteSpace(term))
return Enumerable.Empty<ADGroup>();
string ldapFilter = string.Format("(&(objectCategory=Group)(|(sAMAccountName=*{0}*)(name=*{0}*)(cn=*{0}*)))", ADInterop.EscapeLdapQuery(Term));
var ldapFilter= string.Format(ADGroup.LdapSearchFilterTemplate, ADHelpers.EscapeLdapQuery(term));
IEnumerable<ActiveDirectorySearchResult> searchResults;
if (searchDomain == null)
searchResults = ADInterop.SearchScope(ldapFilter, resultLimit, GroupLoadProperties);
IEnumerable<ADSearchResult> searchResults;
if (searchDomain != null)
searchResults = searchDomain.SearchScope(ldapFilter, ADGroup.LoadProperties, ResultLimit);
else
searchResults = ADInterop.SearchScope(searchDomain, ldapFilter, resultLimit, GroupLoadProperties);
searchResults = Context.SearchScope(ldapFilter, ADGroup.LoadProperties, ResultLimit);
return searchResults.Select(result => result.AsGroup());
return searchResults.Select(result => result.AsADGroup());
}
private static ActiveDirectoryGroup AsGroup(this ActiveDirectorySearchResult item)
{
var name = (string)item.Result.Properties["name"][0];
var distinguishedName = (string)item.Result.Properties["distinguishedName"][0];
var cn = (string)item.Result.Properties["cn"][0];
var sAMAccountName = (string)item.Result.Properties["sAMAccountName"][0];
var objectSid = ADInterop.ConvertBytesToSDDLString((byte[])item.Result.Properties["objectSid"][0]);
var memberOf = item.Result.Properties["memberOf"].Cast<string>().ToList();
#endregion
return new ActiveDirectoryGroup()
{
Domain = item.Domain.NetBiosName,
Name = name,
DistinguishedName = distinguishedName,
CommonName = cn,
SamAccountName = sAMAccountName,
SecurityIdentifier = objectSid,
MemberOf = memberOf
};
}
private static ActiveDirectoryGroup AsGroup(this DirectoryEntry item, ActiveDirectoryDomain Domain)
#region Organisational Units
public static IEnumerable<Tuple<ADDomain, List<ADOrganisationalUnit>>> RetrieveADOrganisationalUnitStructure()
{
var name = (string)item.Properties["name"][0];
var distinguishedName = (string)item.Properties["distinguishedName"][0];
var cn = (string)item.Properties["cn"][0];
var sAMAccountName = (string)item.Properties["sAMAccountName"][0];
var objectSid = ADInterop.ConvertBytesToSDDLString((byte[])item.Properties["objectSid"][0]);
var memberOf = item.Properties["memberOf"].Cast<string>().ToList();
return new ActiveDirectoryGroup()
{
Domain = Domain.NetBiosName,
Name = name,
DistinguishedName = distinguishedName,
CommonName = cn,
SamAccountName = sAMAccountName,
SecurityIdentifier = objectSid,
MemberOf = memberOf
};
return Context.Domains
.Select(d => d.GetAvailableDomainController())
.Select(dc => Tuple.Create(dc.Domain, dc.RetrieveADOrganisationalUnitStructure()));
}
#endregion
#region Object
private static readonly string[] ObjectLoadProperties = { "objectCategory" };
private static readonly string[] ObjectLoadPropertiesAll = ObjectLoadProperties.Concat(UserLoadProperties).Concat(MachineLoadProperties).Concat(GroupLoadProperties).Distinct().ToArray();
public static IActiveDirectoryObject RetrieveObject(string Id, bool Quick)
#region Objects
public static IADObject RetrieveADObject(string Id, bool Quick)
{
const string ldapFilter = "(&(|(objectCategory=Person)(objectCategory=Computer)(objectCategory=Group))(sAMAccountName={0}))";
return SearchBySamAccountName(Id, ldapFilter, ObjectLoadPropertiesAll)
.Select<ActiveDirectorySearchResult, IActiveDirectoryObject>(result =>
{
var objectCategory = (string)result.Result.Properties["objectCategory"][0];
objectCategory = objectCategory.Substring(0, objectCategory.IndexOf(',')).ToLower();
switch (objectCategory)
{
case "cn=person":
return result.AsUserAccount(Quick, null);
case "cn=computer":
return result.AsMachineAccount(null);
case "cn=group":
return result.AsGroup();
default:
throw new InvalidOperationException("Unexpected objectCategory");
}
}).FirstOrDefault();
var domain = Context.GetDomainFromId(Id);
return domain.GetAvailableDomainController().RetrieveADObject(Id, Quick);
}
#endregion
#region Organisation Units
#region Actions
public static List<ActiveDirectoryOrganisationalUnit> RetrieveOrganisationalUnitStructure(ActiveDirectoryDomain Domain)
public static string OfflineDomainJoinProvision(string ComputerSamAccountName, string OrganisationalUnit, ref ADMachineAccount MachineAccount, out string DiagnosticInformation)
{
using (DirectoryEntry domainRoot = ADInterop.RetrieveDirectoryEntry(Domain.DistinguishedName, out Domain))
{
return ActiveDirectory.RetrieveOrganisationalUnitStructureInternal(Domain, domainRoot);
}
}
private static List<ActiveDirectoryOrganisationalUnit> RetrieveOrganisationalUnitStructureInternal(ActiveDirectoryDomain Domain, DirectoryEntry Container)
{
Dictionary<string, List<ActiveDirectoryOrganisationalUnit>> resultTree = new Dictionary<string, List<ActiveDirectoryOrganisationalUnit>>();
var domain = Context.GetDomainFromDistinguishedName(OrganisationalUnit);
var writableDomainController = domain.GetAvailableDomainController(RequireWritable: true);
using (DirectorySearcher adSearcher = new DirectorySearcher(Container, "(objectCategory=organizationalUnit)", new string[]
{
"name",
"distinguishedName"
}, SearchScope.Subtree))
{
adSearcher.PageSize = 500;
using (SearchResultCollection adResults = adSearcher.FindAll())
{
resultTree = adResults.Cast<SearchResult>().Select(adResult =>
{
string i = adResult.Properties["name"][0].ToString();
string dn = adResult.Properties["distinguishedName"][0].ToString();
return new ActiveDirectoryOrganisationalUnit
{
Domain = Domain.NetBiosName,
Name = i,
DistinguishedName = dn,
};
}).GroupBy(ou => ou.DistinguishedName.Substring(ou.DistinguishedName.IndexOf(',') + 1)).ToDictionary(g => g.Key, g => g.ToList());
}
}
// Build Tree
var results = resultTree[Domain.DistinguishedName];
foreach (var child in results)
RetrieveOrganisationalUnitStructureChildrenInternal(child, resultTree);
return results;
}
private static void RetrieveOrganisationalUnitStructureChildrenInternal(ActiveDirectoryOrganisationalUnit OrganisationalUnit, Dictionary<string, List<ActiveDirectoryOrganisationalUnit>> ResultTree)
{
List<ActiveDirectoryOrganisationalUnit> children;
if (ResultTree.TryGetValue(OrganisationalUnit.DistinguishedName, out children))
{
foreach (var child in children)
RetrieveOrganisationalUnitStructureChildrenInternal(child, ResultTree);
OrganisationalUnit.Children = children;
}
return writableDomainController.OfflineDomainJoinProvision(ComputerSamAccountName, OrganisationalUnit, ref MachineAccount, out DiagnosticInformation);
}
#endregion
#region Helpers
private static IEnumerable<ActiveDirectorySearchResult> SearchBySamAccountName(string Id, string LdapFilterTemplate, string[] LoadProperties)
private static string RelevantSearchTerm(string Term, out ADDomain Domain)
{
var splitId = UserExtensions.SplitUserId(Id);
var ldapFilter = string.Format(LdapFilterTemplate, splitId.Item2);
var domains = ADInterop.GetDomainFromId(Id);
Domain = null;
return ADInterop.SearchAll(domains, ldapFilter, SingleSearchResult, LoadProperties);
}
private static string ApplySearchTermDomainRestriction(string Term, out ActiveDirectoryDomain Domain)
{
if (string.IsNullOrWhiteSpace(Term))
throw new ArgumentNullException("Term");
return null;
var domainIndex = Term.IndexOf('\\');
if (domainIndex >= 0)
var term = Term.Trim();
var domainSeperatorIndex = term.IndexOf('\\');
if (domainSeperatorIndex >= 0)
{
var domain = Term.Substring(0, domainIndex);
// Domain Search Restriction
if (!ADInterop.TryGetDomainByNetBiosName(domain, out Domain))
return null; // Domain not found - invalid search
if (Term.Length > (domainIndex + 1))
return Term.Substring(domainIndex + 1);
if (term.Length > domainSeperatorIndex + 1)
{
var netbiosName = term.Substring(0, domainSeperatorIndex);
if (Context.TryGetDomainByNetBiosName(netbiosName, out Domain))
{
return term.Substring(domainSeperatorIndex + 1);
}
else
{
return null; // Unknown Domain
}
}
else
return null; // Domain only, no Term
}
else
{
Domain = null;
return Term;
{
return null; // No term to search, only Domain
}
}
return term;
}
#endregion
}
}
}
@@ -0,0 +1,308 @@
using Disco.Data.Repository;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Interop.ActiveDirectory
{
public class ActiveDirectoryContext
{
public ADSite Site { get; private set; }
public ADDomain PrimaryDomain { get; private set; }
public List<ADDomain> Domains { get; private set; }
public List<string> ForestServers
{
get
{
return ADDiscoverForestServers.LoadForestServersBlocking();
}
}
private bool _SearchAllForestServers { get; set; }
public bool SearchAllForestServers
{
get
{
var fs = ADDiscoverForestServers.ForestServers;
if (fs != null && fs.Count > ActiveDirectory.MaxForestServerSearch)
return false; // Never
return _SearchAllForestServers;
}
}
#region Contructor/Initializing
internal ActiveDirectoryContext(DiscoDataContext Database)
{
Initialize(Database);
}
private void Initialize(DiscoDataContext Database)
{
// Search Entire Forest (default: true)
this._SearchAllForestServers = Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers ?? true;
// Determine Site
var computerSite = ActiveDirectorySite.GetComputerSite();
this.Site = new ADSite(this, computerSite);
// Determine Domains
var computerDomain = Domain.GetComputerDomain();
this.Domains = computerDomain.Forest.Domains
.Cast<Domain>()
.Select(d => new ADDomain(this, d))
.ToList();
this.PrimaryDomain = this.Domains.Where(d => d.Name == computerDomain.Name).First();
// Determine Search Scope Containers
ReinitializeSearchContainers(Database.DiscoConfiguration.ActiveDirectory.SearchContainers);
// Determine Domain Controllers
var siteDomainControllers = computerSite.Servers
.OfType<DomainController>()
.Where(dc => dc.IsReachable())
.Select(dc => new ADDomainController(this, dc, GetDomainByName(dc.Domain.Name), IsSiteServer: true, IsWritable: false));
Site.UpdateDomainControllers(siteDomainControllers);
this.Domains.ForEach(domain => domain.UpdateDomainControllers(siteDomainControllers.Where(dc => dc.Domain == domain)));
}
#endregion
#region Domain Getters
public bool TryGetDomainFromDistinguishedName(string DistinguishedName, out ADDomain Domain)
{
// Find closest match
Domain = this.Domains.Where(d => DistinguishedName.EndsWith(d.DistinguishedName, StringComparison.OrdinalIgnoreCase))
.OrderByDescending(d => d.DistinguishedName.Length).FirstOrDefault();
return (Domain != null);
}
public ADDomain GetDomainFromDistinguishedName(string DistinguishedName)
{
ADDomain domain;
if (!TryGetDomainFromDistinguishedName(DistinguishedName, out domain))
throw new ArgumentException(string.Format("The distinguished name is from an unknown domain: [{0}]", DistinguishedName), "DistinguishedName");
return domain;
}
public bool TryGetDomainByNetBiosName(string NetBiosName, out ADDomain Domain)
{
Domain = this.Domains.FirstOrDefault(d => d.NetBiosName.Equals(NetBiosName, StringComparison.OrdinalIgnoreCase));
return (Domain != null);
}
public ADDomain GetDomainByNetBiosName(string NetBiosName)
{
ADDomain domain;
if (!TryGetDomainByNetBiosName(NetBiosName, out domain))
throw new ArgumentException(string.Format("The domain for specified NetBios name is unknown [{0}]", NetBiosName), "NetBiosName");
return domain;
}
public bool TryGetDomainByName(string Name, out ADDomain Domain)
{
Domain = this.Domains.FirstOrDefault(d => d.Name.Equals(Name, StringComparison.OrdinalIgnoreCase));
return (Domain != null);
}
public ADDomain GetDomainByName(string Name)
{
ADDomain domain;
if (!TryGetDomainByName(Name, out domain))
throw new ArgumentException(string.Format("The domain for specified DNS name is unknown [{0}]", Name), "Name");
return domain;
}
public bool TryGetDomainFromSecurityIdentifier(SecurityIdentifier SecurityIdentifier, out ADDomain Domain)
{
Domain = this.Domains.FirstOrDefault(d => d.SecurityIdentifier.IsEqualDomainSid(SecurityIdentifier));
return (Domain != null);
}
public ADDomain GetDomainFromSecurityIdentifier(SecurityIdentifier SecurityIdentifier)
{
ADDomain domain;
if (!TryGetDomainFromSecurityIdentifier(SecurityIdentifier, out domain))
throw new ArgumentException(string.Format("The domain for specified Security Identifier is unknown [{0}]", SecurityIdentifier.ToString()), "SecurityIdentifier");
return domain;
}
public bool TryGetDomainFromId(string Id, out ADDomain Domain)
{
if (string.IsNullOrWhiteSpace(Id))
throw new ArgumentNullException("Id");
var idSplit = UserExtensions.SplitUserId(Id);
if (string.IsNullOrWhiteSpace(idSplit.Item1))
throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id");
return TryGetDomainByNetBiosName(idSplit.Item1, out Domain);
}
public ADDomain GetDomainFromId(string Id)
{
if (string.IsNullOrWhiteSpace(Id))
throw new ArgumentNullException("Id");
var idSplit = UserExtensions.SplitUserId(Id);
if (string.IsNullOrWhiteSpace(idSplit.Item1))
throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id");
return GetDomainByNetBiosName(idSplit.Item1);
}
#endregion
public ADDirectoryEntry RetrieveDirectoryEntry(string DistinguishedName, string[] LoadProperties = null)
{
if (string.IsNullOrWhiteSpace(DistinguishedName))
throw new ArgumentNullException("DistinguishedName");
var d = GetDomainFromDistinguishedName(DistinguishedName);
var dc = d.GetAvailableDomainController();
return dc.RetrieveDirectoryEntry(DistinguishedName, LoadProperties);
}
#region Searching
public IEnumerable<ADSearchResult> SearchEntireForest(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
{
var queries = this.Domains.Select(d => Tuple.Create(d, d.DistinguishedName));
return SearchInternal(queries, LdapFilter, LoadProperties, ResultLimit);
}
public IEnumerable<ADSearchResult> SearchScope(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
{
var queries = this.Domains.SelectMany(
d => d.SearchContainers ?? new List<string>() { d.DistinguishedName },
(d, scope) => Tuple.Create(d, scope));
return SearchInternal(queries, LdapFilter, LoadProperties, ResultLimit);
}
internal IEnumerable<ADSearchResult> SearchInternal(IEnumerable<Tuple<ADDomain, string>> Queries, string LdapFilter, string[] LoadProperties, int? ResultLimit)
{
var queries = Queries.ToList();
switch (queries.Count)
{
case 0: // Nothing Queried
return Enumerable.Empty<ADSearchResult>();
case 1: // Single-search
var querySingle = queries[0];
return querySingle.Item1.SearchInternal(querySingle.Item2, LdapFilter, LoadProperties, ResultLimit);
default: // Multi-search - Parallelize
var queryTasks = queries.Select(query =>
Task<IEnumerable<ADSearchResult>>.Factory.StartNew(() =>
query.Item1.SearchInternal(query.Item2, LdapFilter, LoadProperties, ResultLimit))).ToArray();
// Block
Task.WaitAll(queryTasks);
var results = queryTasks.SelectMany(t => t.Result);
if (ResultLimit.HasValue)
results = results.Take(ResultLimit.Value);
return results;
}
}
#endregion
#region Configuration
public bool UpdateSearchAllForestServers(DiscoDataContext Database, bool SearchAllForestServers)
{
if (SearchAllForestServers == false)
{
Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers = false;
this._SearchAllForestServers = false;
return true;
}
else
{
var forestServers = ADDiscoverForestServers.LoadForestServersBlocking();
if (forestServers.Count <= ActiveDirectory.MaxForestServerSearch)
{
Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers = true;
this._SearchAllForestServers = true;
return true;
}
else
{
Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers = false;
this._SearchAllForestServers = false;
return false;
}
}
}
public void UpdateSearchContainers(DiscoDataContext Database, IEnumerable<string> Containers)
{
Dictionary<string, List<string>> searchContainers = null;
if (Containers != null)
{
searchContainers = Containers
.Where(c => !string.IsNullOrWhiteSpace(c))
.Distinct()
.Select(c =>
{
ADDomain d;
if (TryGetDomainFromDistinguishedName(c, out d))
return Tuple.Create(d, c);
else
return null;
}).Where(i => i != null)
.GroupBy(i => i.Item1)
.ToDictionary(g => g.Key.Name.ToLower(), g => g.Select(i => i.Item2).ToList());
}
if (searchContainers == null || searchContainers.Count == 0)
{
Database.DiscoConfiguration.ActiveDirectory.SearchContainers = null;
ReinitializeSearchContainers(null);
}
else
{
Database.DiscoConfiguration.ActiveDirectory.SearchContainers = searchContainers;
ReinitializeSearchContainers(searchContainers);
}
}
private void ReinitializeSearchContainers(Dictionary<string, List<string>> Containers)
{
if (Containers == null)
{
// No search restrictions (search entire domain)
foreach (var domain in this.Domains)
domain.UpdateSearchEntireDomain();
}
else
{
// Restrict search containers
var searchContainerDomains = Containers.Join(this.Domains, ok => ok.Key, ik => ik.Name, (o, i) => Tuple.Create(o, i), StringComparer.OrdinalIgnoreCase);
foreach (var domainContainers in searchContainerDomains)
domainContainers.Item2.UpdateSearchContainers(domainContainers.Item1.Value);
// Ignore domains without configured containers
var unconfiguredContainers = this.Domains.Except(searchContainerDomains.Select(sc => sc.Item2));
foreach (var domain in unconfiguredContainers)
domain.UpdateSearchContainers(new List<string>());
}
}
#endregion
}
}
@@ -1,7 +1,4 @@
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Services.Interop.ActiveDirectory.Internal;
using System;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
@@ -16,23 +13,7 @@ namespace Disco.Services.Interop.ActiveDirectory
{
#region Domain/Directory Extensions
public static DomainController RetrieveWritableDomainController(this ActiveDirectoryDomain domain)
{
return ADInterop.RetrieveWritableDomainController(domain);
}
public static IEnumerable<DomainController> RetrieveReachableDomainControllers(this ActiveDirectorySite site, ActiveDirectoryDomain domain)
{
return site.Servers.OfType<DomainController>().Where(dc => dc.Reachable() && dc.Domain.Name.Equals(domain.DnsName));
}
public static IEnumerable<DomainController> RetrieveReachableDomainControllers(this ActiveDirectoryDomain domain)
{
var d = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain, domain.DnsName));
return d.FindAllDomainControllers().OfType<DomainController>().Where(dc => dc.Reachable());
}
public static bool Reachable(this DirectoryServer ds)
public static bool IsReachable(this DirectoryServer ds)
{
using (Ping p = new Ping())
{
@@ -41,351 +22,82 @@ namespace Disco.Services.Interop.ActiveDirectory
}
}
public static string GetFriendlyOrganisationalUnitName(this ActiveDirectoryDomain domain, string DistinguishedName)
public static IEnumerable<DomainController> WhereReachable(this DomainControllerCollection domainControllers)
{
if (!DistinguishedName.EndsWith(domain.DistinguishedName, StringComparison.InvariantCultureIgnoreCase))
throw new ArgumentException(string.Format("The Distinguished Name [{0}] doesn't exist within this domain [{1}]", DistinguishedName, domain.DistinguishedName));
StringBuilder name = new StringBuilder();
name.Append('[').Append(domain.NetBiosName).Append(']');
var subDN = DistinguishedName.Substring(0, DistinguishedName.Length - domain.DistinguishedName.Length);
var subDNComponents = subDN.Split(',');
subDNComponents
.Where(c => !string.IsNullOrWhiteSpace(c))
.Reverse()
.Select(c => c.Substring(c.IndexOf('=') + 1))
.ToList()
.ForEach(c => name.Append(" > ").Append(c));
return name.ToString();
return domainControllers.Cast<DomainController>().Where(dc => dc.IsReachable());
}
public static string GetDefaultComputerContainer(this ActiveDirectoryDomain domain)
public static IEnumerable<ADDomainController> WhereReachable(this IEnumerable<ADDomainController> domainControllers)
{
return string.Format("CN=Computers,{0}", domain.DistinguishedName);
return domainControllers.Where(dc => dc.DomainController.IsReachable());
}
// Directory Entry Properties (Generic Helpers)
public static T Value<T>(this PropertyCollection properties, string PropertyName)
{
var p = properties.Values<T>(PropertyName);
return p.FirstOrDefault();
}
public static IEnumerable<T> Values<T>(this PropertyCollection properties, string PropertyName)
{
var p = properties[PropertyName];
return p.OfType<T>();
}
#endregion
#region User Account Extensions
public static object GetPropertyValue(this ActiveDirectoryUserAccount account, string PropertyName, int Index = 0)
#region ADObject Builders
// User Accounts
public static ADUserAccount AsADUserAccount(this ADSearchResult SearchResult, bool Quick, string[] AdditionalProperties)
{
switch (PropertyName.ToLower())
{
case "name":
return account.Name;
case "samaccountname":
return account.SamAccountName;
case "distinguishedname":
return account.DistinguishedName;
case "objectsid":
return account.SecurityIdentifier;
case "sn":
return account.Surname;
case "givenname":
return account.GivenName;
case "mail":
return account.Email;
case "telephonenumber":
return account.Phone;
default:
object[] adProperty;
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
return adProperty[Index];
else
return null;
}
return ADUserAccount.FromSearchResult(SearchResult, Quick, AdditionalProperties);
}
#endregion
#region Machine Account Extensions
public static void DeleteAccount(this ActiveDirectoryMachineAccount account, DomainController DomainController)
public static IEnumerable<ADUserAccount> AsADUserAccounts(this IEnumerable<ADSearchResult> SearchResults, bool Quick, string[] AdditionalProperties)
{
if (account.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
using (DirectoryEntry deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
{
deAccount.DeleteObjectRecursive();
}
}
public static void DeleteAccount(this ActiveDirectoryMachineAccount account)
{
var domain = account.GetDomain();
using (var domainController = domain.RetrieveWritableDomainController())
{
account.DeleteAccount(domainController);
}
return SearchResults.Select(sr => ADUserAccount.FromSearchResult(sr, Quick, AdditionalProperties));
}
private static void SetNetbootGUID(this ActiveDirectoryMachineAccount account, DomainController DomainController, System.Guid updatedNetbootGUID)
// Machine Accounts
public static ADMachineAccount AsADMachineAccount(this ADSearchResult SearchResult, string[] AdditionalProperties)
{
if (account.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
using (DirectoryEntry deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
{
PropertyValueCollection netbootGUIDProp = deAccount.Properties["netbootGUID"];
bool flag = netbootGUIDProp.Count > 0;
if (flag)
{
netbootGUIDProp.Clear();
}
netbootGUIDProp.Add(updatedNetbootGUID.ToByteArray());
deAccount.CommitChanges();
}
return ADMachineAccount.FromSearchResult(SearchResult, AdditionalProperties);
}
public static void SetDescription(this ActiveDirectoryMachineAccount account, DomainController DomainController, string Description)
public static IEnumerable<ADMachineAccount> AsADMachineAccounts(this IEnumerable<ADSearchResult> SearchResults, string[] AdditionalProperties)
{
using (DirectoryEntry deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
{
PropertyValueCollection descriptionProp = deAccount.Properties["description"];
if (descriptionProp.Count > 0)
{
descriptionProp.Clear();
}
if (!string.IsNullOrEmpty(Description))
{
descriptionProp.Add(Description);
}
deAccount.CommitChanges();
}
}
public static void SetDescription(this ActiveDirectoryMachineAccount account, string Description)
{
var domain = account.GetDomain();
using (var domainController = domain.RetrieveWritableDomainController())
{
account.SetDescription(domainController, Description);
}
return SearchResults.Select(sr => ADMachineAccount.FromSearchResult(sr, AdditionalProperties));
}
public static void SetDescription(this ActiveDirectoryMachineAccount account, DomainController DomainController, Device Device)
// Groups
public static ADGroup AsADGroup(this ADSearchResult SearchResult)
{
System.Text.StringBuilder descriptionBuilder = new System.Text.StringBuilder();
if (Device.AssignedUserId != null)
{
descriptionBuilder.Append(Device.AssignedUser.UserId).Append(" (").Append(Device.AssignedUser.DisplayName).Append("); ");
}
if (Device.DeviceModelId.HasValue)
{
descriptionBuilder.Append(Device.DeviceModel.Description).Append("; ");
}
descriptionBuilder.Append(Device.DeviceProfile.Description).Append(";");
string description = descriptionBuilder.ToString().Trim();
if (description.Length > 1024)
description = description.Substring(0, 1024);
account.SetDescription(DomainController, description);
return ADGroup.FromSearchResult(SearchResult);
}
public static void SetDescription(this ActiveDirectoryMachineAccount account, Device Device)
public static IEnumerable<ADGroup> AsADGroups(this IEnumerable<ADSearchResult> SearchResults)
{
var domain = account.GetDomain();
using (var domainController = domain.RetrieveWritableDomainController())
{
account.SetDescription(domainController, Device);
}
return SearchResults.Select(sr => ADGroup.FromSearchResult(sr));
}
public static ADGroup AsADGroup(this ADDirectoryEntry DirectoryEntry)
{
return ADGroup.FromDirectoryEntry(DirectoryEntry);
}
public static IEnumerable<ADGroup> AsADGroups(this IEnumerable<ADDirectoryEntry> DirectoryEntries)
{
return DirectoryEntries.Select(de => ADGroup.FromDirectoryEntry(de));
}
public static void DisableAccount(this ActiveDirectoryMachineAccount account, DomainController DomainController)
// Organisational Units
public static ADOrganisationalUnit AsADOrganisationalUnit(this ADSearchResult SearchResult)
{
if (account.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
using (DirectoryEntry deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
{
int accountControl = (int)deAccount.Properties["userAccountControl"][0];
int updatedAccountControl = (accountControl | 2);
if (accountControl != updatedAccountControl)
{
deAccount.Properties["userAccountControl"][0] = updatedAccountControl;
deAccount.CommitChanges();
}
}
return ADOrganisationalUnit.FromSearchResult(SearchResult);
}
public static void DisableAccount(this ActiveDirectoryMachineAccount account)
public static IEnumerable<ADOrganisationalUnit> AsADOrganisationalUnit(this IEnumerable<ADSearchResult> SearchResults)
{
var domain = account.GetDomain();
using (var domainController = domain.RetrieveWritableDomainController())
{
account.DisableAccount(domainController);
}
}
public static void EnableAccount(this ActiveDirectoryMachineAccount account, DomainController DomainController)
{
if (account.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
using (DirectoryEntry deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
{
int accountControl = (int)deAccount.Properties["userAccountControl"][0];
if ((accountControl & 2) == 2)
{
int updatedAccountControl = (accountControl ^ 2);
deAccount.Properties["userAccountControl"][0] = updatedAccountControl;
deAccount.CommitChanges();
}
}
}
public static void EnableAccount(this ActiveDirectoryMachineAccount account)
{
var domain = account.GetDomain();
using (var domainController = domain.RetrieveWritableDomainController())
{
account.EnableAccount(domainController);
}
}
public static bool UpdateNetbootGUID(this ActiveDirectoryMachineAccount account, DomainController DomainController, string UUID, string MACAddress)
{
if (account.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
Guid netbootGUID = Guid.Empty;
if (!string.IsNullOrWhiteSpace(UUID))
{
netbootGUID = ActiveDirectoryExtensions.NetbootGUIDFromUUID(UUID);
}
else if (!string.IsNullOrWhiteSpace(MACAddress))
{
netbootGUID = ActiveDirectoryExtensions.NetbootGUIDFromMACAddress(MACAddress);
}
if (netbootGUID != System.Guid.Empty && netbootGUID != account.NetbootGUID)
{
account.SetNetbootGUID(DomainController, netbootGUID);
return true;
}
else
{
return false;
}
}
public static bool UpdateNetbootGUID(this ActiveDirectoryMachineAccount account, string UUID, string MACAddress)
{
var domain = account.GetDomain();
using (var domainController = domain.RetrieveWritableDomainController())
{
return account.UpdateNetbootGUID(domainController, UUID, MACAddress);
}
}
public static System.Guid NetbootGUIDFromMACAddress(string MACAddress)
{
string strippedMACAddress = MACAddress.Trim().Replace(":", string.Empty).Replace("-", string.Empty);
bool flag = strippedMACAddress.Length == 12;
System.Guid NetbootGUIDFromMACAddress;
if (flag)
{
System.Guid guid = new System.Guid(string.Format("00000000-0000-0000-0000-{0}", strippedMACAddress));
NetbootGUIDFromMACAddress = guid;
}
else
{
NetbootGUIDFromMACAddress = System.Guid.Empty;
}
return NetbootGUIDFromMACAddress;
}
public static System.Guid NetbootGUIDFromUUID(string UUID)
{
System.Guid result = new System.Guid(UUID);
return result;
}
public static object GetPropertyValue(this ActiveDirectoryMachineAccount account, string PropertyName, int Index = 0)
{
switch (PropertyName.ToLower())
{
case "name":
return account.Name;
case "samaccountname":
return account.SamAccountName;
case "distinguishedname":
return account.DistinguishedName;
case "objectsid":
return account.SecurityIdentifier;
case "netbootguid":
return account.NetbootGUID;
default:
object[] adProperty;
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
return adProperty[Index];
else
return null;
}
}
public static IPStatus PingComputer(this ActiveDirectoryMachineAccount account, int Timeout = 2000)
{
using (var p = new Ping())
{
PingReply reply = p.Send(account.DnsName, Timeout);
return reply.Status;
}
}
public static void MoveOrganisationalUnit(this ActiveDirectoryMachineAccount account, DomainController DomainController, string NewOrganisationUnit)
{
if (account.IsCriticalSystemObject)
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
var parentDistinguishedName = account.ParentDistinguishedName();
if (parentDistinguishedName != null && !parentDistinguishedName.Equals(NewOrganisationUnit, StringComparison.InvariantCultureIgnoreCase))
{
var domain = account.GetDomain();
// If no OU provided, place in default Computers container
if (string.IsNullOrWhiteSpace(NewOrganisationUnit))
NewOrganisationUnit = domain.GetDefaultComputerContainer();
if (!NewOrganisationUnit.EndsWith(domain.DistinguishedName, StringComparison.InvariantCultureIgnoreCase))
throw new InvalidOperationException(string.Format("Unable to move AD Account from one domain [{0}] to another [{1}].", account.DistinguishedName, NewOrganisationUnit));
using (DirectoryEntry ou = DomainController.RetrieveDirectoryEntry(NewOrganisationUnit))
{
using (DirectoryEntry i = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
{
i.UsePropertyCache = false;
i.MoveTo(ou);
}
}
}
}
public static string ParentDistinguishedName(this ActiveDirectoryMachineAccount account)
{
// Determine Parent
if (!string.IsNullOrWhiteSpace(account.DistinguishedName))
return account.DistinguishedName.Substring(account.DistinguishedName.IndexOf(",") + 1);
else
return null;
}
public static ActiveDirectoryDomain GetDomain(this ActiveDirectoryMachineAccount account)
{
var domain = ActiveDirectory.GetDomainByNetBiosName(account.Domain);
if (domain == null)
throw new InvalidOperationException(string.Format("Unable to find Domain [{0}] for account [{1}]", account.Domain, account.Name));
else
return domain;
return SearchResults.Select(sr => ADOrganisationalUnit.FromSearchResult(sr));
}
#endregion
}
}
@@ -0,0 +1,226 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Interop.ActiveDirectory
{
public class ActiveDirectoryGroupCache
{
private ConcurrentDictionary<SecurityIdentifier, Tuple<ADGroup, DateTime>> securityIdentifierCache;
private ConcurrentDictionary<string, Tuple<ADGroup, DateTime>> distinguishedNameCache;
private const long CacheTimeoutTicks = 6000000000; // 10 Minutes
private const int CacheCleanIntervalMinutes = 15;
private DateTime cacheCleanNext;
private object cacheCleanLock = new object();
private Task cacheCleanTask;
public ActiveDirectoryGroupCache()
{
this.securityIdentifierCache = new ConcurrentDictionary<SecurityIdentifier, Tuple<ADGroup, DateTime>>();
this.distinguishedNameCache = new ConcurrentDictionary<string, Tuple<ADGroup, DateTime>>(StringComparer.OrdinalIgnoreCase);
cacheCleanNext = DateTime.Now.AddMinutes(CacheCleanIntervalMinutes);
}
public ADGroup GetGroup(string DistinguishedName)
{
// Check Cache
Tuple<ADGroup, DateTime> groupRecord = TryDistinguishedNameCache(DistinguishedName);
if (groupRecord == null)
{
// Load from AD
var group = ActiveDirectory.RetrieveADGroupByDistinguishedName(DistinguishedName);
SetValue(group);
return group;
}
else
{
// Return from Cache
return groupRecord.Item1;
}
}
public ADGroup GetGroup(SecurityIdentifier SecurityIdentifier)
{
// Check Cache
Tuple<ADGroup, DateTime> groupRecord = TrySecurityIdentifierCache(SecurityIdentifier);
if (groupRecord == null)
{
// Load from AD
var group = ActiveDirectory.RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier);
SetValue(group);
return group;
}
else
{
// Return from Cache
return groupRecord.Item1;
}
}
public IEnumerable<ADGroup> GetRecursiveGroups(IEnumerable<string> DistinguishedNames)
{
List<ADGroup> groups = new List<ADGroup>();
foreach (var distinguishedName in DistinguishedNames)
foreach (var group in GetGroupsRecursive(distinguishedName, new Stack<ADGroup>()))
if (!groups.Contains(group))
{
groups.Add(group);
yield return group;
}
}
public IEnumerable<ADGroup> GetRecursiveGroups(string DistinguishedName)
{
foreach (var group in GetGroupsRecursive(DistinguishedName, new Stack<ADGroup>()))
yield return group;
}
private IEnumerable<ADGroup> GetGroupsRecursive(string DistinguishedName, Stack<ADGroup> RecursiveTree)
{
var group = GetGroup(DistinguishedName);
if (group != null && !RecursiveTree.Contains(group))
{
yield return group;
if (group.MemberOf != null)
{
RecursiveTree.Push(group);
foreach (var parentDistinguishedName in group.MemberOf)
foreach (var parentGroup in GetGroupsRecursive(parentDistinguishedName, RecursiveTree))
yield return parentGroup;
RecursiveTree.Pop();
}
}
}
private Tuple<ADGroup, DateTime> TryDistinguishedNameCache(string DistinguishedName)
{
Tuple<ADGroup, DateTime> groupRecord;
if (distinguishedNameCache.TryGetValue(DistinguishedName, out groupRecord))
{
if (groupRecord.Item2 > DateTime.Now)
return groupRecord;
else
{
if (distinguishedNameCache.TryRemove(DistinguishedName, out groupRecord))
securityIdentifierCache.TryRemove(groupRecord.Item1.SecurityIdentifier, out groupRecord);
}
}
return null;
}
private Tuple<ADGroup, DateTime> TrySecurityIdentifierCache(SecurityIdentifier SecurityIdentifier)
{
Tuple<ADGroup, DateTime> groupRecord;
if (securityIdentifierCache.TryGetValue(SecurityIdentifier, out groupRecord))
{
if (groupRecord.Item2 > DateTime.Now)
return groupRecord;
else
{
if (securityIdentifierCache.TryRemove(SecurityIdentifier, out groupRecord))
distinguishedNameCache.TryRemove(groupRecord.Item1.DistinguishedName, out groupRecord);
}
}
return null;
}
private bool SetValue(ADGroup Group)
{
Tuple<ADGroup, DateTime> groupRecord = Tuple.Create(Group, DateTime.Now.AddTicks(CacheTimeoutTicks));
Tuple<ADGroup, DateTime> oldGroupRecord;
var distinguishedName = Group.DistinguishedName;
var securityIdentifier = Group.SecurityIdentifier;
if (distinguishedNameCache.ContainsKey(distinguishedName))
{
if (distinguishedNameCache.TryGetValue(distinguishedName, out oldGroupRecord))
{
distinguishedNameCache.TryUpdate(distinguishedName, groupRecord, oldGroupRecord);
}
}
else
{
distinguishedNameCache.TryAdd(distinguishedName, groupRecord);
}
if (securityIdentifierCache.ContainsKey(securityIdentifier))
{
if (securityIdentifierCache.TryGetValue(securityIdentifier, out oldGroupRecord))
{
securityIdentifierCache.TryUpdate(securityIdentifier, groupRecord, oldGroupRecord);
}
}
else
{
securityIdentifierCache.TryAdd(securityIdentifier, groupRecord);
}
return true;
}
#region Stale Cache Clean
private void EnsureCleanCache()
{
if (cacheCleanTask == null && cacheCleanNext < DateTime.Now)
{
lock (cacheCleanLock)
{
if (cacheCleanTask == null && cacheCleanNext < DateTime.Now)
{
cacheCleanTask = Task.Factory.StartNew(CleanCache);
}
}
}
}
private void CleanCache()
{
DateTime now = DateTime.Now;
// Clean Cache
var dnKeys = distinguishedNameCache.Keys.ToArray();
foreach (var dnKey in dnKeys)
{
Tuple<ADGroup, DateTime> groupRecord;
if (distinguishedNameCache.TryGetValue(dnKey, out groupRecord))
{
if (groupRecord.Item2 <= now)
{
distinguishedNameCache.TryRemove(dnKey, out groupRecord);
}
}
}
// Clean SID Cache
var siKeys = securityIdentifierCache.Keys.ToArray();
foreach (var siKey in siKeys)
{
Tuple<ADGroup, DateTime> groupRecord;
if (securityIdentifierCache.TryGetValue(siKey, out groupRecord))
{
if (groupRecord.Item2 <= now)
{
securityIdentifierCache.TryRemove(siKey, out groupRecord);
}
}
}
// Schedule Next Clean
cacheCleanNext = now.AddMinutes(CacheCleanIntervalMinutes);
cacheCleanTask = null;
}
#endregion
}
}
@@ -0,0 +1,18 @@

using System.Security.Principal;
namespace Disco.Services.Interop.ActiveDirectory
{
public interface IADObject
{
ADDomain Domain { get; }
string DistinguishedName { get; }
SecurityIdentifier SecurityIdentifier { get; }
string Id { get; }
string SamAccountName { get; }
string Name { get; }
string DisplayName { get; }
}
}
@@ -1,226 +0,0 @@
using Disco.Data.Repository;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Tasks;
using Quartz;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Disco.Services.Interop.ActiveDirectory.Internal
{
public class ADGroupCache : ScheduledTask
{
private static ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>> _SecurityIdentifierCache = new ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>>();
private static ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>> _DistinguishedNameCache = new ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>>();
private const long CacheTimeoutTicks = 6000000000; // 10 Minutes
public static IEnumerable<string> GetGroups(IEnumerable<string> DistinguishedNames)
{
List<ActiveDirectoryGroup> groups = new List<ActiveDirectoryGroup>();
foreach (var distinguishedName in DistinguishedNames)
foreach (var group in GetGroupsRecursive(distinguishedName, new Stack<ActiveDirectoryGroup>()))
if (!groups.Contains(group))
{
groups.Add(group);
yield return group.NetBiosId;
}
}
public static IEnumerable<string> GetGroups(string DistinguishedName)
{
foreach (var group in GetGroupsRecursive(DistinguishedName, new Stack<ActiveDirectoryGroup>()))
yield return group.NetBiosId;
}
public static string GetGroupsDistinguishedNameForSecurityIdentifier(string SecurityIdentifier)
{
var group = GetGroupBySecurityIdentifier(SecurityIdentifier);
if (group == null)
return null;
else
return group.DistinguishedName;
}
private static IEnumerable<ActiveDirectoryGroup> GetGroupsRecursive(string DistinguishedName, Stack<ActiveDirectoryGroup> RecursiveTree)
{
var group = GetGroup(DistinguishedName);
if (group != null && !RecursiveTree.Contains(group))
{
yield return group;
if (group.MemberOf != null)
{
RecursiveTree.Push(group);
foreach (var parentDistinguishedName in group.MemberOf)
foreach (var parentGroup in GetGroupsRecursive(parentDistinguishedName, RecursiveTree))
yield return parentGroup;
RecursiveTree.Pop();
}
}
}
private static ActiveDirectoryGroup GetGroup(string DistinguishedName)
{
// Check Cache
Tuple<ActiveDirectoryGroup, DateTime> groupRecord = TryCache(DistinguishedName);
if (groupRecord == null)
{
// Load from AD
var group = ActiveDirectory.RetrieveGroupWithDistinguishedName(DistinguishedName);
SetValue(group);
return group;
}
else
{
// Return from Cache
return groupRecord.Item1;
}
}
private static ActiveDirectoryGroup GetGroupBySecurityIdentifier(string SecurityIdentifier)
{
// Check Cache
Tuple<ActiveDirectoryGroup, DateTime> groupRecord = TrySecurityIdentifierCache(SecurityIdentifier);
if (groupRecord == null)
{
// Load from AD
var group = ActiveDirectory.RetrieveGroupWithSecurityIdentifier(SecurityIdentifier);
SetValue(group);
return group;
}
else
{
// Return from Cache
return groupRecord.Item1;
}
}
private static Tuple<ActiveDirectoryGroup, DateTime> TryCache(string DistinguishedName)
{
string distinguishedName = DistinguishedName.ToLower();
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
if (_DistinguishedNameCache.TryGetValue(distinguishedName, out groupRecord))
{
if (groupRecord.Item2 > DateTime.Now)
return groupRecord;
else
{
if (_DistinguishedNameCache.TryRemove(distinguishedName, out groupRecord))
_SecurityIdentifierCache.TryRemove(groupRecord.Item1.SecurityIdentifier, out groupRecord);
}
}
return null;
}
private static Tuple<ActiveDirectoryGroup, DateTime> TrySecurityIdentifierCache(string SecurityIdentifier)
{
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
if (_SecurityIdentifierCache.TryGetValue(SecurityIdentifier, out groupRecord))
{
if (groupRecord.Item2 > DateTime.Now)
return groupRecord;
else
{
if (_SecurityIdentifierCache.TryRemove(SecurityIdentifier, out groupRecord))
_DistinguishedNameCache.TryRemove(groupRecord.Item1.DistinguishedName.ToLower(), out groupRecord);
}
}
return null;
}
private static bool SetValue(ActiveDirectoryGroup Group)
{
Tuple<ActiveDirectoryGroup, DateTime> groupRecord = new Tuple<ActiveDirectoryGroup, DateTime>(Group, DateTime.Now.AddTicks(CacheTimeoutTicks));
Tuple<ActiveDirectoryGroup, DateTime> oldGroupRecord;
string key = Group.DistinguishedName.ToLower();
if (_DistinguishedNameCache.ContainsKey(key))
{
if (_DistinguishedNameCache.TryGetValue(key, out oldGroupRecord))
{
_DistinguishedNameCache.TryUpdate(key, groupRecord, oldGroupRecord);
}
}
else
{
_DistinguishedNameCache.TryAdd(key, groupRecord);
}
string securityIdentifier = Group.SecurityIdentifier;
if (_SecurityIdentifierCache.ContainsKey(securityIdentifier))
{
if (_SecurityIdentifierCache.TryGetValue(securityIdentifier, out oldGroupRecord))
{
_SecurityIdentifierCache.TryUpdate(securityIdentifier, groupRecord, oldGroupRecord);
}
}
else
{
_SecurityIdentifierCache.TryAdd(securityIdentifier, groupRecord);
}
return true;
}
private static void CleanStaleCache()
{
// Clean Cache
var groupKeys = _DistinguishedNameCache.Keys.ToArray();
foreach (string groupKey in groupKeys)
{
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
if (_DistinguishedNameCache.TryGetValue(groupKey, out groupRecord))
{
if (groupRecord.Item2 <= DateTime.Now)
{
_DistinguishedNameCache.TryRemove(groupKey, out groupRecord);
}
}
}
// Clean SID Cache
groupKeys = _SecurityIdentifierCache.Keys.ToArray();
foreach (string groupKey in groupKeys)
{
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
if (_SecurityIdentifierCache.TryGetValue(groupKey, out groupRecord))
{
if (groupRecord.Item2 <= DateTime.Now)
{
_SecurityIdentifierCache.TryRemove(groupKey, out groupRecord);
}
}
}
}
public override string TaskName { get { return "AD Group Cache - Clean Stale Cache"; } }
public override bool SingleInstanceTask { get { return true; } }
public override bool CancelInitiallySupported { get { return false; } }
public override bool LogExceptionsOnly { get { return true; } }
public override void InitalizeScheduledTask(DiscoDataContext Database)
{
// Run @ every 15mins
// Next 15min interval
DateTime now = DateTime.Now;
int mins = (15 - (now.Minute % 15));
if (mins < 10)
mins += 15;
DateTimeOffset startAt = new DateTimeOffset(now).AddMinutes(mins).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
TriggerBuilder triggerBuilder = TriggerBuilder.Create().StartAt(startAt).
WithSchedule(SimpleScheduleBuilder.RepeatMinutelyForever(15));
this.ScheduleTask(triggerBuilder);
}
protected override void ExecuteTask()
{
CleanStaleCache();
}
}
}
@@ -1,682 +0,0 @@
using Disco.Data.Repository;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Tasks;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Interop.ActiveDirectory.Internal
{
internal static class ADInterop
{
public static List<ActiveDirectoryDomain> Domains { get; private set; }
public static ActiveDirectoryDomain PrimaryDomain { get; private set; }
public static ActiveDirectorySite Site { get; private set; }
internal static List<string> _ForestServers { get; set; }
private static bool _SearchEntireForest { get; set; }
private static bool _Initialized = false;
private static object _InitializeLock = new object();
#region Initialization
public static void Initialize(DiscoDataContext Database)
{
if (!_Initialized)
{
lock (_InitializeLock)
{
if (!_Initialized)
{
_SearchEntireForest = Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest ?? true; // Default True
using (var computerDomain = Domain.GetComputerDomain())
{
PrimaryDomain = GetDomainInternal(computerDomain, Database);
Domains = computerDomain.Forest.Domains.Cast<Domain>().Select(d =>
{
if (d.Name == PrimaryDomain.DnsName)
return PrimaryDomain;
else
return GetDomainInternal(d, Database);
}).ToList();
}
Site = ActiveDirectorySite.GetComputerSite();
}
}
}
}
private static ActiveDirectoryDomain GetDomainInternal(Domain d, DiscoDataContext Database)
{
string ldapPath = string.Format("LDAP://{0}/", d.Name);
string defaultNamingContext;
string configurationNamingContext;
string netBiosName;
using (var adRootDSE = new DirectoryEntry(ldapPath + "RootDSE"))
{
defaultNamingContext = adRootDSE.Properties["defaultNamingContext"][0].ToString();
configurationNamingContext = adRootDSE.Properties["configurationNamingContext"][0].ToString();
}
using (var configSearchRoot = new DirectoryEntry(ldapPath + "CN=Partitions," + configurationNamingContext))
{
var configSearchFilter = string.Format("(&(objectcategory=Crossref)(dnsRoot={0})(netBIOSName=*))", d.Name);
var configSearchLoadProperites = new string[] { "NetBIOSName" };
using (var configSearcher = new DirectorySearcher(configSearchRoot, configSearchFilter, configSearchLoadProperites, System.DirectoryServices.SearchScope.OneLevel))
{
SearchResult configResult = configSearcher.FindOne();
if (configResult != null)
netBiosName = configResult.Properties["NetBIOSName"][0].ToString();
else
netBiosName = null;
}
}
// Search Containers
var searchContainersAll = Database.DiscoConfiguration.ActiveDirectory.SearchContainers;
List<string> searchContainers = null;
if (searchContainersAll == null || searchContainersAll.Count == 0 || !searchContainersAll.TryGetValue(d.Name.ToLower(), out searchContainers))
searchContainers = new List<string>() { defaultNamingContext }; // No search constraints set - search entire tree
return new ActiveDirectoryDomain(d.Name, netBiosName, defaultNamingContext, searchContainers);
}
public static void UpdateSearchContainers(DiscoDataContext Database, IEnumerable<string> Containers)
{
Dictionary<string, List<string>> searchContainers = null;
if (Containers != null)
{
searchContainers = Containers
.Where(c => !string.IsNullOrWhiteSpace(c))
.Distinct()
.Select(c =>
{
ActiveDirectoryDomain d;
if (TryGetDomainByDistinguishedName(c, out d))
return Tuple.Create(d, c);
else
return null;
}).Where(i => i != null)
.GroupBy(i => i.Item1)
.ToDictionary(g => g.Key.DnsName.ToLower(), g => g.Select(i => i.Item2).ToList());
}
if (searchContainers == null || searchContainers.Count == 0)
{
Database.DiscoConfiguration.ActiveDirectory.SearchContainers = null;
// No search constraints set - search entire tree
Domains.ForEach(d => d.UpdateSearchContainers(new string[] { d.DistinguishedName }));
}
else
{
Database.DiscoConfiguration.ActiveDirectory.SearchContainers = searchContainers;
Domains.ForEach(d =>
{
List<string> domainContainers;
if (searchContainers.TryGetValue(d.DnsName.ToLower(), out domainContainers))
d.UpdateSearchContainers(domainContainers);
else
d.UpdateSearchContainers(Enumerable.Empty<string>());
});
}
}
public static bool UpdateSearchEntireForest(DiscoDataContext Database, bool SearchEntireForest)
{
if (SearchEntireForest == false)
{
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = false;
ADInterop._SearchEntireForest = false;
return true;
}
else
{
var forestServers = LoadForestServers();
if (forestServers.Count <= ActiveDirectory.MaxForestServerSearch)
{
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = true;
ADInterop._SearchEntireForest = true;
return true;
}
else
{
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = false;
ADInterop._SearchEntireForest = false;
return false;
}
}
}
#endregion
#region Domain Getters
public static bool TryGetDomainByDistinguishedName(string DistinguishedName, out ActiveDirectoryDomain Domain)
{
// Find closest match
Domain = ADInterop.Domains.Where(d => DistinguishedName.EndsWith(d.DistinguishedName, StringComparison.InvariantCultureIgnoreCase))
.OrderByDescending(d => d.DistinguishedName.Length).FirstOrDefault();
return (Domain != null);
}
public static ActiveDirectoryDomain GetDomainByDistinguishedName(string DistinguishedName)
{
ActiveDirectoryDomain domain;
if (!TryGetDomainByDistinguishedName(DistinguishedName, out domain))
throw new ArgumentException(string.Format("The domain is unknown distinguished name: [{0}]", DistinguishedName), "Id");
return domain;
}
public static bool TryGetDomainByNetBiosName(string NetBiosName, out ActiveDirectoryDomain Domain)
{
Domain = ADInterop.Domains.FirstOrDefault(d => d.NetBiosName.Equals(NetBiosName, StringComparison.InvariantCultureIgnoreCase));
return (Domain != null);
}
public static ActiveDirectoryDomain GetDomainByNetBiosName(string NetBiosName)
{
ActiveDirectoryDomain domain;
if (!TryGetDomainByNetBiosName(NetBiosName, out domain))
throw new ArgumentException(string.Format("The specified domain is unknown [{0}]", NetBiosName), "Id");
return domain;
}
public static bool TryGetDomainByDnsName(string DnsName, out ActiveDirectoryDomain Domain)
{
Domain = ADInterop.Domains.FirstOrDefault(d => d.DnsName.Equals(DnsName, StringComparison.InvariantCultureIgnoreCase));
return (Domain != null);
}
public static ActiveDirectoryDomain GetDomainByDnsName(string DnsName)
{
ActiveDirectoryDomain domain;
if (!TryGetDomainByDnsName(DnsName, out domain))
throw new ArgumentException(string.Format("The specified domain is unknown [{0}]", DnsName), "Id");
return domain;
}
public static bool TryGetDomainFromId(string Id, out ActiveDirectoryDomain Domain)
{
if (string.IsNullOrWhiteSpace(Id))
throw new ArgumentNullException("Id");
var idSplit = UserExtensions.SplitUserId(Id);
if (idSplit.Item1 == null)
throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id");
if (string.IsNullOrWhiteSpace(idSplit.Item1))
throw new ArgumentException(string.Format("The Id Domain was empty [{0}]", Id), "Id");
if (string.IsNullOrWhiteSpace(idSplit.Item2))
throw new ArgumentException(string.Format("The Id Name was empty [{0}]", Id), "Id");
return TryGetDomainByNetBiosName(idSplit.Item1, out Domain);
}
public static ActiveDirectoryDomain GetDomainFromId(string Id)
{
if (string.IsNullOrWhiteSpace(Id))
throw new ArgumentNullException("Id");
var idSplit = UserExtensions.SplitUserId(Id);
if (idSplit.Item1 == null)
throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id");
if (string.IsNullOrWhiteSpace(idSplit.Item1))
throw new ArgumentException(string.Format("The Id Domain was empty [{0}]", Id), "Id");
if (string.IsNullOrWhiteSpace(idSplit.Item2))
throw new ArgumentException(string.Format("The Id Name was empty [{0}]", Id), "Id");
return GetDomainByNetBiosName(idSplit.Item1);
}
public static List<string> LoadForestServers()
{
if (_ForestServers == null)
{
lock (_InitializeLock)
{
if (_ForestServers == null)
{
var status = ADDiscoverForestServers.ScheduleNow();
status.CompletionTask.Wait();
}
}
}
return _ForestServers;
}
public static Task<List<string>> LoadForestServersAsync()
{
if (_ForestServers != null)
return Task.FromResult(_ForestServers);
lock (_InitializeLock)
{
if (_ForestServers != null)
return Task.FromResult(_ForestServers);
// Invoke Scheduled Task
var status = ADDiscoverForestServers.ScheduleNow();
return status.CompletionTask.ContinueWith(t =>
{
return ADInterop._ForestServers.ToList();
});
}
}
public static bool SearchEntireForest
{
get
{
if (_ForestServers != null && _ForestServers.Count > ActiveDirectory.MaxForestServerSearch)
return false; // Never
return _SearchEntireForest;
}
}
#endregion
#region Searching
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(string LdapFilter, string[] LoadProperties)
{
return SearchAll(Domains, LdapFilter, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(string LdapFilter, int ResultLimit, string[] LoadProperties)
{
return SearchAll(Domains, LdapFilter, ResultLimit, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(IEnumerable<Tuple<ActiveDirectoryDomain, DomainController>> DomainsWithController, string LdapFilter, string[] LoadProperties)
{
return SearchAll(DomainsWithController, LdapFilter, null, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(IEnumerable<ActiveDirectoryDomain> Domains, string LdapFilter, string[] LoadProperties)
{
return SearchAll(Domains, LdapFilter, null, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, string[] LoadProperties)
{
return SearchAll(Domain, DomainController, LdapFilter, null, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(ActiveDirectoryDomain Domain, string LdapFilter, string[] LoadProperties)
{
return SearchAll(Domain, LdapFilter, null, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(IEnumerable<ActiveDirectoryDomain> Domains, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
if (Domains == null || Domains.Count() == 0)
return Enumerable.Empty<ActiveDirectorySearchResult>();
var queries = Domains.Select(d => Tuple.Create(d, (DomainController)null)).ToList();
return SearchAll(queries, LdapFilter, ResultLimit, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(IEnumerable<Tuple<ActiveDirectoryDomain, DomainController>> DomainsWithController, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
var queries = DomainsWithController.ToList();
IEnumerable<ActiveDirectorySearchResult> results;
switch (queries.Count)
{
case 0:
results = Enumerable.Empty<ActiveDirectorySearchResult>();
break;
case 1:
var singleQuery = queries.First();
results = SearchDomain(singleQuery.Item1, singleQuery.Item2, null, LdapFilter, ResultLimit, LoadProperties);
break;
default:
var taskFactory = new TaskFactory<IEnumerable<ActiveDirectorySearchResult>>();
var tasks = queries
.Select(query =>
taskFactory.StartNew(() =>
SearchDomain(query.Item1, query.Item2, null, LdapFilter, ResultLimit, LoadProperties))
).ToArray();
Task.WaitAll(tasks);
results = tasks.SelectMany(t => t.Result);
break;
}
if (ResultLimit.HasValue)
results = results.Take(ResultLimit.Value);
return results.ToList();
}
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(ActiveDirectoryDomain Domain, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
return SearchAll(Domain, null, LdapFilter, ResultLimit, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
return SearchDomain(Domain, DomainController, null, LdapFilter, ResultLimit, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(string LdapFilter, string[] LoadProperties)
{
return SearchScope(Domains, LdapFilter, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(string LdapFilter, int ResultLimit, string[] LoadProperties)
{
return SearchScope(Domains, LdapFilter, ResultLimit, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(IEnumerable<ActiveDirectoryDomain> Domains, string LdapFilter, string[] LoadProperties)
{
return SearchScope(Domains, LdapFilter, null, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(IEnumerable<Tuple<ActiveDirectoryDomain, DomainController>> DomainsWithController, string LdapFilter, string[] LoadProperties)
{
return SearchScope(DomainsWithController, LdapFilter, null, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(ActiveDirectoryDomain Domain, string LdapFilter, string[] LoadProperties)
{
return SearchScope(Domain, LdapFilter, null, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, string[] LoadProperties)
{
return SearchScope(Domain, DomainController, LdapFilter, null, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(IEnumerable<ActiveDirectoryDomain> Domains, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
return SearchScope(Domains.Select(d => Tuple.Create(d, (DomainController)null)), LdapFilter, ResultLimit, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(ActiveDirectoryDomain Domain, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
return SearchScope(Domain, null, LdapFilter, ResultLimit, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
if (Domain.SearchContainers == null || Domain.SearchContainers.Count == 0)
return Enumerable.Empty<ActiveDirectorySearchResult>();
var query = new List<Tuple<ActiveDirectoryDomain, DomainController>>() {
Tuple.Create(Domain, DomainController)
};
return SearchScope(query, LdapFilter, ResultLimit, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(IEnumerable<Tuple<ActiveDirectoryDomain, DomainController>> DomainsWithController, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
var queries = DomainsWithController.SelectMany(d => d.Item1.SearchContainers, (d, sc) => Tuple.Create(d.Item1, d.Item2, sc)).ToList();
IEnumerable<ActiveDirectorySearchResult> results;
switch (queries.Count)
{
case 0:
results = Enumerable.Empty<ActiveDirectorySearchResult>();
break;
case 1:
var singleQuery = queries.First();
results = SearchDomain(singleQuery.Item1, singleQuery.Item2, singleQuery.Item3, LdapFilter, ResultLimit, LoadProperties);
break;
default:
var taskFactory = new TaskFactory<IEnumerable<ActiveDirectorySearchResult>>();
var tasks = queries
.Select(query =>
taskFactory.StartNew(() =>
SearchDomain(query.Item1, query.Item2, query.Item3, LdapFilter, ResultLimit, LoadProperties).ToList())
).ToArray();
Task.WaitAll(tasks);
results = tasks.SelectMany(t => t.Result);
break;
}
if (ResultLimit.HasValue)
results = results.Take(ResultLimit.Value);
return results.ToList();
}
private static IEnumerable<ActiveDirectorySearchResult> SearchDomain(ActiveDirectoryDomain Domain, DomainController DomainController, string SearchRoot, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
string ldapServer;
if (DomainController != null)
{
ldapServer = DomainController.Name;
}
else
{
var domainDC = Site.RetrieveReachableDomainControllers(Domain).FirstOrDefault();
if (domainDC != null)
ldapServer = domainDC.Name;
else
ldapServer = Domain.DnsName;
}
string searchRoot = SearchRoot ?? Domain.DistinguishedName;
string ldapPath = string.Format(@"LDAP://{0}/{1}", ldapServer, searchRoot);
using (DirectoryEntry rootEntry = new DirectoryEntry(ldapPath))
{
using (DirectorySearcher searcher = new DirectorySearcher(rootEntry, LdapFilter, LoadProperties, System.DirectoryServices.SearchScope.Subtree))
{
searcher.PageSize = 500;
if (ResultLimit.HasValue)
searcher.SizeLimit = ResultLimit.Value;
return searcher.FindAll().Cast<SearchResult>().Select(result => new ActiveDirectorySearchResult()
{
Domain = Domain,
SearchRoot = searchRoot,
Result = result,
});
}
}
}
#endregion
public static string OfflineDomainJoinProvision(ActiveDirectoryDomain Domain, DomainController DomainController, string ComputerSamAccountName, string OrganisationalUnit, out string DiagnosticInformation)
{
StringBuilder diagnosticInfo = new StringBuilder();
string DJoinResult = null;
if (!string.IsNullOrWhiteSpace(ComputerSamAccountName))
ComputerSamAccountName = ComputerSamAccountName.TrimEnd('$');
if (string.IsNullOrWhiteSpace(ComputerSamAccountName) || ComputerSamAccountName.Length > 24)
throw new System.ArgumentException("Invalid Computer Name; > 0 and <= 24", "ComputerName");
// Ensure Specified OU Exists
if (!string.IsNullOrEmpty(OrganisationalUnit))
{
try
{
using (var deOU = DomainController.RetrieveDirectoryEntry(OrganisationalUnit))
{
if (deOU == null)
throw new Exception(string.Format("OU's Directory Entry couldn't be found at [{0}]", OrganisationalUnit));
}
}
catch (Exception ex)
{
throw new ArgumentException(string.Format("An error occurred while trying to locate the specified OU: {0}", OrganisationalUnit), "OrganisationalUnit", ex);
}
}
string tempFileName = System.IO.Path.GetTempFileName();
string argumentOU = (!string.IsNullOrWhiteSpace(OrganisationalUnit)) ? string.Format(" /MACHINEOU \"{0}\"", OrganisationalUnit) : string.Empty;
string arguments = string.Format("/PROVISION /DOMAIN \"{0}\" /DCNAME \"{1}\" /MACHINE \"{2}\"{3} /REUSE /SAVEFILE \"{4}\"",
Domain.DnsName,
DomainController.Name,
ComputerSamAccountName,
argumentOU,
tempFileName
);
ProcessStartInfo commandStarter = new ProcessStartInfo("DJOIN.EXE", arguments)
{
CreateNoWindow = true,
ErrorDialog = false,
LoadUserProfile = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
diagnosticInfo.AppendFormat("{0} {1}", "DJOIN.EXE", arguments);
diagnosticInfo.AppendLine();
string stdOutput;
string stdError;
using (Process commandProc = Process.Start(commandStarter))
{
commandProc.WaitForExit(20000);
stdOutput = commandProc.StandardOutput.ReadToEnd();
stdError = commandProc.StandardError.ReadToEnd();
}
if (!string.IsNullOrWhiteSpace(stdOutput))
diagnosticInfo.AppendLine(stdOutput);
if (!string.IsNullOrWhiteSpace(stdError))
diagnosticInfo.AppendLine(stdError);
if (System.IO.File.Exists(tempFileName))
{
DJoinResult = System.Convert.ToBase64String(System.IO.File.ReadAllBytes(tempFileName));
System.IO.File.Delete(tempFileName);
}
if (string.IsNullOrWhiteSpace(DJoinResult))
throw new System.InvalidOperationException(string.Format("Domain Join Unsuccessful{0}Error: {1}{0}Output: {2}", System.Environment.NewLine, stdError, stdOutput));
DiagnosticInformation = diagnosticInfo.ToString();
return DJoinResult;
}
public static DirectoryEntry RetrieveDirectoryEntry(string DistinguishedName, out ActiveDirectoryDomain Domain)
{
if (string.IsNullOrWhiteSpace(DistinguishedName))
throw new ArgumentNullException("DistinguishedName");
// Find Domain
var domain = GetDomainByDistinguishedName(DistinguishedName);
if (domain == null)
throw new ArgumentException(string.Format("Unknown domain for DistinguishedName: {0}", DistinguishedName), "DistinguishedName");
var domainDC = Site.RetrieveReachableDomainControllers(domain).FirstOrDefault();
var ldapServer = domainDC != null ? domainDC.Name : domain.DnsName;
Domain = domain;
return new DirectoryEntry(string.Format(@"LDAP://{0}/{1}", ldapServer, DistinguishedName));
}
public static DomainController RetrieveWritableDomainController(this ActiveDirectoryDomain domain)
{
var adContext = new DirectoryContext(DirectoryContextType.Domain, domain.DnsName);
using (var adDomain = Domain.GetDomain(adContext))
{
return adDomain.FindDomainController(LocatorOptions.WriteableRequired);
}
}
public static DirectoryEntry RetrieveDirectoryEntry(this DomainController domainController, string DistinguishedName)
{
return new DirectoryEntry(string.Format(@"LDAP://{0}/{1}", domainController.Name, DistinguishedName));
}
public static void DeleteObjectRecursive(this DirectoryEntry directoryEntry)
{
DeleteObjectRecursiveInternal(directoryEntry);
using (var deParent = directoryEntry.Parent)
{
deParent.Children.Remove(directoryEntry);
}
}
private static void DeleteObjectRecursiveInternal(DirectoryEntry directoryEntry)
{
List<DirectoryEntry> children = directoryEntry.Children.Cast<DirectoryEntry>().ToList();
foreach (var child in children)
{
DeleteObjectRecursive(child);
directoryEntry.Children.Remove(child);
child.Dispose();
}
}
#region Helpers
internal static string ConvertBytesToSDDLString(byte[] SID)
{
SecurityIdentifier sID = new SecurityIdentifier(SID, 0);
return sID.ToString();
}
internal static byte[] ConvertSDDLStringToBytes(string SidSsdlString)
{
SecurityIdentifier sID = new SecurityIdentifier(SidSsdlString);
var sidBytes = new byte[sID.BinaryLength];
sID.GetBinaryForm(sidBytes, 0);
return sidBytes;
}
internal static byte[] BuildPrimaryGroupSid(byte[] UserSID, int PrimaryGroupId)
{
var groupSid = (byte[])UserSID.Clone();
int ridOffset = groupSid.Length - 4;
int groupId = PrimaryGroupId;
for (int i = 0; i < 4; i++)
{
groupSid[ridOffset + i] = (byte)(groupId & 0xFF);
groupId >>= 8;
}
return groupSid;
}
internal static string ConvertBytesToBinarySidString(byte[] SID)
{
StringBuilder escapedSid = new StringBuilder();
foreach (var sidByte in SID)
{
escapedSid.Append('\\');
escapedSid.Append(sidByte.ToString("x2"));
}
return escapedSid.ToString();
}
internal static string EscapeLdapQuery(string query)
{
return query.Replace("*", "\\2a").Replace("(", "\\28").Replace(")", "\\29").Replace("\\", "\\5c").Replace("NUL", "\\00").Replace("/", "\\2f");
}
internal static string FormatGuidForLdapQuery(System.Guid g)
{
checked
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
byte[] array = g.ToByteArray();
for (int i = 0; i < array.Length; i++)
{
byte b = array[i];
sb.Append("\\");
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
}
#endregion
}
}
@@ -1,231 +0,0 @@
using Disco.Data.Repository;
using Disco.Models.Interop.ActiveDirectory;
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.Internal
{
public class ADUpdateLastNetworkLogonDateJob : 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)
{
// ActiveDirectoryUpdateLastNetworkLogonDateJob @ 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(ADUpdateLastNetworkLogonDateJob)).Where(s => s.IsRunning).FirstOrDefault();
if (existingTask != null)
return existingTask;
var instance = new ADUpdateLastNetworkLogonDateJob();
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))
{
var deviceSamAccountName = UserExtensions.SplitUserId(Device.DeviceDomainId).Item2 + "$";
var ldapFilter = string.Format(ldapFilterTemplate, ADInterop.EscapeLdapQuery(deviceSamAccountName));
var domain = ADInterop.GetDomainFromId(Device.DeviceDomainId);
IEnumerable<DomainController> domainControllers;
if (ADInterop.SearchEntireForest)
domainControllers = domain.RetrieveReachableDomainControllers();
else
domainControllers = ADInterop.Site.RetrieveReachableDomainControllers(domain);
lastLogon = domainControllers.Select(dc =>
{
using (var directoryRoot = dc.RetrieveDirectoryEntry(domain.DistinguishedName))
{
using (var directorySearcher = new DirectorySearcher(directoryRoot, ldapFilter, ldapProperties, SearchScope.Subtree))
{
var directoryResult = directorySearcher.FindOne();
if (directoryResult != null)
{
long lastLogonValue = default(long);
long lastLogonTimestampValue = default(long);
var lastLogonProperty = directoryResult.Properties["lastLogon"];
if (lastLogonProperty != null && lastLogonProperty.Count > 0)
lastLogonValue = (long)lastLogonProperty[0];
var lastLogonTimestampProperty = directoryResult.Properties["lastLogonTimestamp"];
if (lastLogonTimestampProperty != null && lastLogonTimestampProperty.Count > 0)
lastLogonTimestampValue = (long)lastLogonTimestampProperty[0];
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;
}
private static void UpdateLastNetworkLogonDates(DiscoDataContext Database, ScheduledTaskStatus status)
{
const string ldapFilter = "(objectCategory=Computer)";
string[] ldapProperties = new string[] { "sAMAccountName", "lastLogon" };
status.UpdateStatus(2, "Initializing", "Determining Domains and Available Domain Controllers");
// Determine Domain Controllers to Query
IEnumerable<Tuple<ActiveDirectoryDomain, DomainController>> domainControllers;
if (ADInterop.SearchEntireForest)
domainControllers = ADInterop.Domains.SelectMany(d => d.RetrieveReachableDomainControllers(), (d, dc) => Tuple.Create(d, dc));
else
domainControllers = ADInterop.Domains.SelectMany(d => ADInterop.Site.RetrieveReachableDomainControllers(d), (d, dc) => Tuple.Create(d, dc));
// Determine Queries
var requiredRueries = domainControllers
.Where(s => s.Item1.SearchContainers != null && s.Item1.SearchContainers.Count > 0)
.SelectMany(s => s.Item1.SearchContainers, (s, c) => Tuple.Create(s.Item1, s.Item2, c)).ToList();
var queries = Enumerable.Range(0, requiredRueries.Count).Select(i =>
{
var q = requiredRueries[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 / requiredRueries.Count));
status.UpdateStatus(progress, string.Format("Querying Domain [{0}] using controller [{1}]", domain.NetBiosName, domainController.Name), string.Format("Searching: {0}", searchRoot));
// Perform Query
using (var directoryRoot = domainController.RetrieveDirectoryEntry(searchRoot))
{
using (var directorySearcher = new DirectorySearcher(directoryRoot, ldapFilter, ldapProperties, SearchScope.Subtree))
{
directorySearcher.PageSize = 500;
var directoryResults = directorySearcher.FindAll();
if (directoryResults != null)
{
return directoryResults.Cast<SearchResult>().Select(result =>
{
var samAccountProperity = result.Properties["sAMAccountName"];
long lastLogonValue = default(long);
long lastLogonTimestampValue = default(long);
var lastLogonProperty = result.Properties["lastLogon"];
if (lastLogonProperty != null && lastLogonProperty.Count > 0)
lastLogonValue = (long)lastLogonProperty[0];
var lastLogonTimestampProperty = result.Properties["lastLogonTimestamp"];
if (lastLogonTimestampProperty != null && lastLogonTimestampProperty.Count > 0)
lastLogonTimestampValue = (long)lastLogonTimestampProperty[0];
long highedValue = Math.Max(lastLogonValue, lastLogonTimestampValue);
if (highedValue > 0)
{
var computerName = string.Format(@"{0}\{1}", domain.NetBiosName, samAccountProperity[0].ToString().TrimEnd('$'));
var lastLogon = new DateTime((DateTime.FromFileTime(highedValue).Ticks / 10000000L) * 10000000L);
return Tuple.Create(computerName, lastLogon);
}
else
return null;
}).Where(i => i != null).ToList();
}
else
{
return Enumerable.Empty<Tuple<string, DateTime>>();
}
}
}
}).GroupBy(r => r.Item1, StringComparer.InvariantCultureIgnoreCase).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;
}
}
}
}
}
}
@@ -274,12 +274,12 @@ namespace Disco.Services
Location = i,
References = o.ToList()
},
StringComparer.InvariantCultureIgnoreCase);
StringComparer.OrdinalIgnoreCase);
}
public static IEnumerable<JobLocationReference> JobLocationReferences(this IEnumerable<JobTableStatusItemModel> Items)
{
return Items.Where(i => !string.IsNullOrWhiteSpace(i.DeviceHeldLocation) && i.DeviceHeld.HasValue && !i.DeviceReturnedDate.HasValue)
.GroupBy(i => i.DeviceHeldLocation, StringComparer.InvariantCultureIgnoreCase)
.GroupBy(i => i.DeviceHeldLocation, StringComparer.OrdinalIgnoreCase)
.Select(i => new JobLocationReference()
{
Location = i.Key,
+1 -1
View File
@@ -56,7 +56,7 @@ namespace Disco.Services.Logging
var appDomain = AppDomain.CurrentDomain;
var logModuleTypes = (from a in appDomain.GetAssemblies()
where !a.GlobalAssemblyCache && !a.IsDynamic && a.FullName.StartsWith("Disco.", StringComparison.InvariantCultureIgnoreCase)
where !a.GlobalAssemblyCache && !a.IsDynamic && a.FullName.StartsWith("Disco.", StringComparison.OrdinalIgnoreCase)
from type in a.GetTypes()
where typeof(LogBase).IsAssignableFrom(type) && !type.IsAbstract
select type);
@@ -28,7 +28,7 @@ namespace Disco.Services.Plugins.Features.WarrantyProvider
public static PluginFeatureManifest FindPluginFeature(string PluginIdOrWarrantyProviderId)
{
var defs = Plugins.GetPluginFeatures(typeof(WarrantyProviderFeature));
var def = defs.FirstOrDefault(d => d.PluginManifest.Id.Equals(PluginIdOrWarrantyProviderId, StringComparison.InvariantCultureIgnoreCase));
var def = defs.FirstOrDefault(d => d.PluginManifest.Id.Equals(PluginIdOrWarrantyProviderId, StringComparison.OrdinalIgnoreCase));
if (def != null)
return def;
else
@@ -36,7 +36,7 @@ namespace Disco.Services.Plugins.Features.WarrantyProvider
{
using (var providerInstance = d.CreateInstance<WarrantyProviderFeature>())
{
if (providerInstance.WarrantyProviderId != null && providerInstance.WarrantyProviderId.Equals(PluginIdOrWarrantyProviderId, StringComparison.InvariantCultureIgnoreCase))
if (providerInstance.WarrantyProviderId != null && providerInstance.WarrantyProviderId.Equals(PluginIdOrWarrantyProviderId, StringComparison.OrdinalIgnoreCase))
{
return d;
}
+1 -1
View File
@@ -101,7 +101,7 @@ namespace Disco.Services.Plugins
// Check for Compatibility
var compatibilityData = Plugins.LoadCompatibilityData(database);
var pluginCompatibility = compatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(packageManifest.Id, StringComparison.InvariantCultureIgnoreCase) && packageManifest.Version == Version.Parse(i.Version));
var pluginCompatibility = compatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(packageManifest.Id, StringComparison.OrdinalIgnoreCase) && packageManifest.Version == Version.Parse(i.Version));
if (pluginCompatibility != null && !pluginCompatibility.Compatible)
throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] is not compatible: {2}", packageManifest.Id, packageManifest.VersionFormatted, pluginCompatibility.Reason));
+1 -1
View File
@@ -240,7 +240,7 @@ namespace Disco.Services.Plugins
foreach (string referenceFilename in Directory.EnumerateFiles(pluginLocation, "*.dll", SearchOption.TopDirectoryOnly))
{
if (!referenceFilename.Equals(assembly.Location, StringComparison.InvariantCultureIgnoreCase))
if (!referenceFilename.Equals(assembly.Location, StringComparison.OrdinalIgnoreCase))
{
// Ignore Excluded Assemblies
if (!PluginExcludedAssemblies.Contains(Path.GetFileNameWithoutExtension(referenceFilename)))
+4 -4
View File
@@ -302,7 +302,7 @@ namespace Disco.Services.Plugins
foreach (var serverItem in serverData.Plugins)
{
var serverItemVersion = Version.Parse(serverItem.Version);
var localItem = localItems.FirstOrDefault(i => i.Id.Equals(serverItem.Id, StringComparison.InvariantCultureIgnoreCase) && serverItemVersion == localItemVersions[i]);
var localItem = localItems.FirstOrDefault(i => i.Id.Equals(serverItem.Id, StringComparison.OrdinalIgnoreCase) && serverItemVersion == localItemVersions[i]);
if (localItem != null)
joinedItems.Remove(localItem);
@@ -373,7 +373,7 @@ namespace Disco.Services.Plugins
if (pluginManifest != null)
{
// Check Version Compatibility
var pluginCompatibility = compatibilityData.Value.Plugins.FirstOrDefault(i => i.Id.Equals(pluginManifest.Id, StringComparison.InvariantCultureIgnoreCase) && pluginManifest.Version == Version.Parse(i.Version));
var pluginCompatibility = compatibilityData.Value.Plugins.FirstOrDefault(i => i.Id.Equals(pluginManifest.Id, StringComparison.OrdinalIgnoreCase) && pluginManifest.Version == Version.Parse(i.Version));
if (pluginCompatibility != null && !pluginCompatibility.Compatible)
throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] is not compatible: {2}", pluginManifest.Id, pluginManifest.VersionFormatted, pluginCompatibility.Reason));
@@ -496,7 +496,7 @@ namespace Disco.Services.Plugins
// Check Compatibility
if (CompatibilityData == null)
CompatibilityData = LoadCompatibilityData(Database);
var pluginCompatibility = CompatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(packageManifest.Id, StringComparison.InvariantCultureIgnoreCase) && packageManifest.Version == Version.Parse(i.Version));
var pluginCompatibility = CompatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(packageManifest.Id, StringComparison.OrdinalIgnoreCase) && packageManifest.Version == Version.Parse(i.Version));
if (pluginCompatibility != null && !pluginCompatibility.Compatible)
throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] is not compatible: {2}", packageManifest.Id, packageManifest.VersionFormatted, pluginCompatibility.Reason));
@@ -595,7 +595,7 @@ namespace Disco.Services.Plugins
public static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.RequestingAssembly != null && args.RequestingAssembly.Location.StartsWith(PluginPath, StringComparison.InvariantCultureIgnoreCase) && _PluginManifests != null)
if (args.RequestingAssembly != null && args.RequestingAssembly.Location.StartsWith(PluginPath, StringComparison.OrdinalIgnoreCase) && _PluginManifests != null)
{
// Try best guess first
PluginManifest requestingPlugin = _PluginManifests.Values.Where(p => p.Type.Assembly == args.RequestingAssembly).FirstOrDefault();
+1 -1
View File
@@ -235,7 +235,7 @@ namespace Disco.Services.Plugins
{
// Check for Compatibility
var compatibilityData = Plugins.LoadCompatibilityData(database);
var pluginCompatibility = compatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(updateManifest.Id, StringComparison.InvariantCultureIgnoreCase) && updateManifest.Version == Version.Parse(i.Version));
var pluginCompatibility = compatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(updateManifest.Id, StringComparison.OrdinalIgnoreCase) && updateManifest.Version == Version.Parse(i.Version));
if (pluginCompatibility != null && !pluginCompatibility.Compatible)
throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] is not compatible: {2}", updateManifest.Id, updateManifest.VersionFormatted, pluginCompatibility.Reason));
+1 -2
View File
@@ -1,5 +1,4 @@
using Disco.Data.Repository;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Models.Services.Jobs.JobLists;
using Disco.Models.Services.Searching;
@@ -171,7 +170,7 @@ namespace Disco.Services.Searching
public static List<User> SearchUsersUpstream(string Term, int? LimitCount = null)
{
IEnumerable<ActiveDirectoryUserAccount> matches = ActiveDirectory.SearchUserAccounts(Term, Quick: true);
IEnumerable<ADUserAccount> matches = ActiveDirectory.SearchADUserAccounts(Term, Quick: true);
if (LimitCount.HasValue)
matches = matches.Take(LimitCount.Value);
+3 -3
View File
@@ -12,7 +12,7 @@ namespace Disco.Services
{
public static bool IsInPrimaryDomain(this User u)
{
return u.Domain.Equals(Disco.Services.Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName, StringComparison.InvariantCultureIgnoreCase);
return u.Domain.Equals(ActiveDirectory.Context.PrimaryDomain.NetBiosName, StringComparison.OrdinalIgnoreCase);
}
public static string FriendlyId(this User u)
@@ -23,8 +23,8 @@ namespace Disco.Services
public static string FriendlyUserId(string UserId)
{
var splitUserId = SplitUserId(UserId);
if (splitUserId.Item1 != null && splitUserId.Item1.Equals(ActiveDirectory.PrimaryDomain.NetBiosName, StringComparison.InvariantCultureIgnoreCase))
if (splitUserId.Item1 != null && splitUserId.Item1.Equals(ActiveDirectory.Context.PrimaryDomain.NetBiosName, StringComparison.OrdinalIgnoreCase))
return splitUserId.Item2;
else
return UserId;
+6 -7
View File
@@ -1,5 +1,4 @@
using Disco.Data.Repository;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Authorization.Roles;
@@ -206,9 +205,9 @@ namespace Disco.Services.Users
Cache.FlushCache();
}
internal static IEnumerable<ActiveDirectoryUserAccount> SearchUsers(DiscoDataContext Database, string Term)
internal static IEnumerable<ADUserAccount> SearchUsers(DiscoDataContext Database, string Term)
{
var adImportedUsers = ActiveDirectory.SearchUserAccounts(Term, Quick: true);
var adImportedUsers = ActiveDirectory.SearchADUserAccounts(Term, Quick: true);
foreach (var adU in adImportedUsers.Select(adU => adU.ToRepositoryUser()))
{
var existingUser = Database.Users.Find(adU.UserId);
@@ -230,7 +229,7 @@ namespace Disco.Services.Users
if (UserId.EndsWith("$"))
{
// Machine Account
var adAccount = ActiveDirectory.RetrieveMachineAccount(UserId);
var adAccount = ActiveDirectory.RetrieveADMachineAccount(UserId);
if (adAccount == null)
return null;
@@ -244,10 +243,10 @@ namespace Disco.Services.Users
{
// User Account
ActiveDirectoryUserAccount adAccount;
ADUserAccount adAccount;
try
{
adAccount = ActiveDirectory.RetrieveUserAccount(UserId);
adAccount = ActiveDirectory.RetrieveADUserAccount(UserId);
if (adAccount == null)
throw new ArgumentException(string.Format("Invalid Username: '{0}'; User not found in Active Directory", UserId), "Username");
@@ -280,7 +279,7 @@ namespace Disco.Services.Users
}
Database.SaveChanges();
var token = AuthorizationToken.BuildToken(user, adAccount.Groups);
var token = AuthorizationToken.BuildToken(user, adAccount.Groups.Select(g => g.Id));
return new Tuple<User, AuthorizationToken>(user, token);
}
@@ -1,5 +1,4 @@
using Disco.BI.Extensions;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Authorization.Roles;
@@ -16,7 +15,6 @@ namespace Disco.Web.Areas.API.Controllers
[DiscoAuthorize(Claims.DiscoAdminAccount)]
public partial class AuthorizationRoleController : AuthorizedDatabaseController
{
#region Properties
const string pName = "name";
@@ -111,14 +109,15 @@ namespace Disco.Web.Areas.API.Controllers
var subjects = Subjects
.Where(s => !string.IsNullOrWhiteSpace(s))
.Select(s => s.Trim())
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveADObject(s, Quick: true)))
.Where(s => s.Item2 is ADUserAccount || s.Item2 is ADGroup)
.ToList();
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
if (invalidSubjects.Count > 0)
throw new ArgumentException(string.Format("Subjects not found: {0}", string.Join(", ", invalidSubjects)), "Subjects");
var proposedSubjects = subjects.Select(s => s.Item2.NetBiosId).OrderBy(s => s).ToArray();
var proposedSubjects = subjects.Select(s => s.Item2.Id).OrderBy(s => s).ToArray();
var currentSubjects = AuthorizationRole.SubjectIds == null ? new string[0] : AuthorizationRole.SubjectIds.Split(',');
removedSubjects = currentSubjects.Except(proposedSubjects).ToArray();
addedSubjects = proposedSubjects.Except(currentSubjects).ToArray();
@@ -249,14 +248,15 @@ namespace Disco.Web.Areas.API.Controllers
var subjects = Subjects
.Where(s => !string.IsNullOrWhiteSpace(s))
.Select(s => s.Trim())
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveADObject(s, Quick: true)))
.Where(s => s.Item2 is ADUserAccount || s.Item2 is ADGroup)
.ToList();
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
if (invalidSubjects.Count > 0)
throw new ArgumentException(string.Format("Subjects not found: {0}", string.Join(", ", invalidSubjects)), "Subjects");
proposedSubjects = subjects.Select(s => s.Item2.NetBiosId).OrderBy(s => s).ToArray();
proposedSubjects = subjects.Select(s => s.Item2.Id).OrderBy(s => s).ToArray();
var currentSubjects = UserService.AdministratorSubjectIds;
removedSubjects = currentSubjects.Except(proposedSubjects).ToArray();
addedSubjects = proposedSubjects.Except(currentSubjects).ToArray();
@@ -275,31 +275,5 @@ namespace Disco.Web.Areas.API.Controllers
}
#endregion
public virtual ActionResult SearchSubjects(string term)
{
var groupResults = ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
var userResults = ActiveDirectory.SearchUserAccounts(term).Cast<IActiveDirectoryObject>();
var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName)
.Select(r => Models.AuthorizationRole.SubjectItem.FromActiveDirectoryObject(r)).ToList();
return Json(results, JsonRequestBehavior.AllowGet);
}
public virtual ActionResult Subject(string Id)
{
if (string.IsNullOrWhiteSpace(Id))
return Json(null, JsonRequestBehavior.AllowGet);
else if (!Id.Contains(@"\"))
Id = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, Id);
var subject = ActiveDirectory.RetrieveObject(Id, Quick: true);
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
return Json(null, JsonRequestBehavior.AllowGet);
else
return Json(Models.AuthorizationRole.SubjectItem.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
}
}
}
@@ -150,7 +150,7 @@ namespace Disco.Web.Areas.API.Controllers
// Update AD Account
if (!string.IsNullOrEmpty(device.DeviceDomainId) && device.DeviceDomainId.Length <= 24)
{
var adMachineAccount = ActiveDirectory.RetrieveMachineAccount(device.DeviceDomainId);
var adMachineAccount = ActiveDirectory.RetrieveADMachineAccount(device.DeviceDomainId);
if (adMachineAccount != null)
adMachineAccount.SetDescription(device);
}
@@ -410,7 +410,7 @@ namespace Disco.Web.Areas.API.Controllers
var thumbPath = da.RepositoryThumbnailFilename(Database);
if (System.IO.File.Exists(thumbPath))
{
if (thumbPath.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
if (thumbPath.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
return File(thumbPath, "image/png");
else
return File(thumbPath, "image/jpg");
@@ -433,7 +433,7 @@ namespace Disco.Web.Areas.API.Controllers
if (file.ContentLength > 0)
{
var contentType = file.ContentType;
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
contentType = BI.Interop.MimeTypes.ResolveMimeType(file.FileName);
var da = new Disco.Models.Repository.DeviceAttachment()
@@ -501,7 +501,7 @@ namespace Disco.Web.Areas.API.Controllers
var da = Database.DeviceAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault();
if (da != null)
{
if (da.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
if (da.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))
Authorization.RequireAny(Claims.Device.Actions.RemoveAnyAttachments, Claims.Device.Actions.RemoveOwnAttachments);
else
Authorization.Require(Claims.Device.Actions.RemoveAnyAttachments);
@@ -246,7 +246,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateOrganisationalUnit(Disco.Models.Repository.DeviceProfile deviceProfile, string OrganisationalUnit)
{
if (string.IsNullOrWhiteSpace(OrganisationalUnit))
OrganisationalUnit = ActiveDirectory.PrimaryDomain.GetDefaultComputerContainer();
OrganisationalUnit = ActiveDirectory.Context.PrimaryDomain.DefaultComputerContainer;
if (OrganisationalUnit != deviceProfile.OrganisationalUnit)
{
@@ -531,7 +531,7 @@ namespace Disco.Web.Areas.API.Controllers
// Enforce Restricted List Mode
var value = DeviceHeldLocation.Trim();
if (!Database.DiscoConfiguration.JobPreferences.LocationList.Contains(value, StringComparer.InvariantCultureIgnoreCase))
if (!Database.DiscoConfiguration.JobPreferences.LocationList.Contains(value, StringComparer.OrdinalIgnoreCase))
throw new ArgumentException("The location was not found in the list (Mode: Restricted List)");
}
@@ -545,7 +545,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateFlags(Job job, string Flags)
{
// Only User Management Job Supports Flags at the moment
if (!job.JobTypeId.Equals(JobType.JobTypeIds.UMgmt, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.UMgmt, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for User Management Jobs");
}
@@ -602,7 +602,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateNonWarrantyIsInsuranceClaim(Job job, string IsInsuranceClaim)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -641,7 +641,7 @@ namespace Disco.Web.Areas.API.Controllers
private Models.Job._DateChangeModel UpdateNonWarrantyAccountingChargeRequired(Job job, string AccountingChargeRequiredDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -675,7 +675,7 @@ namespace Disco.Web.Areas.API.Controllers
private Models.Job._DateChangeModel UpdateNonWarrantyAccountingChargeAdded(Job job, string AccountingChargeAddedDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -709,7 +709,7 @@ namespace Disco.Web.Areas.API.Controllers
private Models.Job._DateChangeModel UpdateNonWarrantyAccountingChargePaid(Job job, string AccountingChargePaidDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -743,7 +743,7 @@ namespace Disco.Web.Areas.API.Controllers
private Models.Job._DateChangeModel UpdateNonWarrantyPurchaseOrderRaised(Job job, string PurchaseOrderRaisedDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -786,7 +786,7 @@ namespace Disco.Web.Areas.API.Controllers
private Models.Job._DateChangeModel UpdateNonWarrantyPurchaseOrderSent(Job job, string PurchaseOrderSentDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -820,7 +820,7 @@ namespace Disco.Web.Areas.API.Controllers
private Models.Job._DateChangeModel UpdateNonWarrantyInvoiceReceived(Job job, string InvoiceReceivedDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -855,7 +855,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateNonWarrantyRepairerName(Job job, string RepairerName)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -873,7 +873,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateNonWarrantyRepairerLoggedDate(Job job, string RepairerLoggedDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -884,7 +884,7 @@ namespace Disco.Web.Areas.API.Controllers
}
else
{
if (RepairerLoggedDate.Equals("Now", StringComparison.InvariantCultureIgnoreCase))
if (RepairerLoggedDate.Equals("Now", StringComparison.OrdinalIgnoreCase))
{
job.JobMetaNonWarranty.RepairerLoggedDate = DateTime.Now;
}
@@ -906,7 +906,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateNonWarrantyRepairerReference(Job job, string RepairerReference)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -924,7 +924,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateNonWarrantyRepairerCompletedDate(Job job, string RepairerCompletedDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -935,7 +935,7 @@ namespace Disco.Web.Areas.API.Controllers
}
else
{
if (RepairerCompletedDate.Equals("Now", StringComparison.InvariantCultureIgnoreCase))
if (RepairerCompletedDate.Equals("Now", StringComparison.OrdinalIgnoreCase))
{
job.JobMetaNonWarranty.RepairerCompletedDate = DateTime.Now;
}
@@ -962,7 +962,7 @@ namespace Disco.Web.Areas.API.Controllers
private Models.Job._DateChangeModel UpdateInsuranceClaimFormSentDate(Job job, string ClaimFormSentDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -973,7 +973,7 @@ namespace Disco.Web.Areas.API.Controllers
}
else
{
if (ClaimFormSentDate.Equals("Now", StringComparison.InvariantCultureIgnoreCase))
if (ClaimFormSentDate.Equals("Now", StringComparison.OrdinalIgnoreCase))
{
job.JobMetaInsurance.ClaimFormSentDate = DateTime.Now;
}
@@ -1004,7 +1004,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsuranceDateOfPurchase(Job job, string DateOfPurchase)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1028,7 +1028,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsuranceOtherInterestedParties(Job job, string OtherInterestedParties)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1047,7 +1047,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsuranceRecoverReduceAction(Job job, string RecoverReduceAction)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1066,7 +1066,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsurancePoliceNotifiedCrimeReportNo(Job job, string PoliceNotifiedCrimeReportNo)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1085,7 +1085,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsurancePoliceNotifiedDate(Job job, string PoliceNotifiedDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1109,7 +1109,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsurancePoliceNotifiedStation(Job job, string PoliceNotifiedStation)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1128,7 +1128,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsurancePoliceNotified(Job job, string PoliceNotified)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1146,7 +1146,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsurancePropertyLastSeenDate(Job job, string PropertyLastSeenDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1173,7 +1173,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsuranceBurglaryTheftMethodOfEntry(Job job, string BurglaryTheftMethodOfEntry)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1192,7 +1192,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsuranceWitnessesNamesAddresses(Job job, string WitnessesNamesAddresses)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1211,7 +1211,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsuranceThirdPartyCausedWhy(Job job, string ThirdPartyCausedWhy)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1230,7 +1230,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsuranceThirdPartyCausedName(Job job, string ThirdPartyCausedName)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1249,7 +1249,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsuranceThirdPartyCaused(Job job, string ThirdPartyCaused)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1267,7 +1267,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsuranceDescription(Job job, string Description)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1286,7 +1286,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsuranceEventLocation(Job job, string EventLocation)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1305,7 +1305,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateInsuranceLossOrDamageDate(Job job, string LossOrDamageDate)
{
// Validate Is NonWarranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
}
@@ -1334,7 +1334,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateWarrantyExternalName(Job job, string ExternalName)
{
// Validate Is Warranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware Warranty Jobs");
}
@@ -1353,7 +1353,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateWarrantyExternalLoggedDate(Job job, string ExternalLoggedDate)
{
// Validate Is Warranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware Warranty Jobs");
}
@@ -1380,7 +1380,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateWarrantyExternalReference(Job job, string ExternalReference)
{
// Validate Is Warranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware Warranty Jobs");
}
@@ -1399,7 +1399,7 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateWarrantyExternalCompletedDate(Job job, string ExternalCompletedDate)
{
// Validate Is Warranty Job
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.InvariantCultureIgnoreCase))
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("This property can only be set for Hardware Warranty Jobs");
}
@@ -1410,7 +1410,7 @@ namespace Disco.Web.Areas.API.Controllers
}
else
{
if (ExternalCompletedDate.Equals("Now", StringComparison.InvariantCultureIgnoreCase))
if (ExternalCompletedDate.Equals("Now", StringComparison.OrdinalIgnoreCase))
{
job.JobMetaWarranty.ExternalCompletedDate = DateTime.Now;
}
@@ -1876,7 +1876,7 @@ namespace Disco.Web.Areas.API.Controllers
var jl = Database.JobLogs.Find(id);
if (jl != null)
{
if (jl.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
if (jl.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))
Authorization.RequireAny(Claims.Job.Actions.RemoveAnyLogs, Claims.Job.Actions.RemoveOwnLogs);
else
Authorization.Require(Claims.Job.Actions.RemoveAnyLogs);
@@ -1921,7 +1921,7 @@ namespace Disco.Web.Areas.API.Controllers
var thumbFileInfo = new FileInfo(thumbPath);
if (thumbFileInfo.Exists && thumbFileInfo.Length > 0)
{
if (thumbPath.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
if (thumbPath.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
return File(thumbPath, "image/png");
else
return File(thumbPath, "image/jpg");
@@ -1944,7 +1944,7 @@ namespace Disco.Web.Areas.API.Controllers
if (file.ContentLength > 0)
{
var contentType = file.ContentType;
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
contentType = BI.Interop.MimeTypes.ResolveMimeType(file.FileName);
var ja = new Disco.Models.Repository.JobAttachment()
@@ -2012,7 +2012,7 @@ namespace Disco.Web.Areas.API.Controllers
var ja = Database.JobAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault();
if (ja != null)
{
if (ja.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
if (ja.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))
Authorization.RequireAny(Claims.Job.Actions.RemoveAnyAttachments, Claims.Job.Actions.RemoveOwnAttachments);
else
Authorization.Require(Claims.Job.Actions.RemoveAnyAttachments);
@@ -2148,7 +2148,7 @@ namespace Disco.Web.Areas.API.Controllers
{
case Disco.Models.BI.Job.LocationModes.Unrestricted:
var jobDateThreshold = DateTime.Now.AddYears(-1);
locations = Database.Jobs.Where(j => (j.OpenedDate > jobDateThreshold || !j.ClosedDate.HasValue) && j.DeviceHeldLocation != null).Select(j => j.DeviceHeldLocation).Distinct().OrderBy(l => l).ToList().Where(l => !string.IsNullOrWhiteSpace(l)).Select(l => l.Trim()).Distinct(StringComparer.InvariantCultureIgnoreCase).OrderBy(l => l).ToList();
locations = Database.Jobs.Where(j => (j.OpenedDate > jobDateThreshold || !j.ClosedDate.HasValue) && j.DeviceHeldLocation != null).Select(j => j.DeviceHeldLocation).Distinct().OrderBy(l => l).ToList().Where(l => !string.IsNullOrWhiteSpace(l)).Select(l => l.Trim()).Distinct(StringComparer.OrdinalIgnoreCase).OrderBy(l => l).ToList();
break;
case Disco.Models.BI.Job.LocationModes.OptionalList:
case Disco.Models.BI.Job.LocationModes.RestrictedList:
@@ -53,7 +53,7 @@ namespace Disco.Web.Areas.API.Controllers
var list = LocationList
.Where(i => !string.IsNullOrWhiteSpace(i))
.Select(i => i.Trim())
.Distinct(StringComparer.InvariantCultureIgnoreCase)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(i => i);
Database.DiscoConfiguration.JobPreferences.LocationList = list.ToList();
@@ -93,7 +93,7 @@ namespace Disco.Web.Areas.API.Controllers
list = list
.Where(l => !string.IsNullOrWhiteSpace(l))
.Select(l => l.Trim())
.Distinct(StringComparer.InvariantCultureIgnoreCase)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(i => i);
Database.DiscoConfiguration.JobPreferences.LocationList = list.ToList();
@@ -1,5 +1,4 @@
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Jobs.JobQueues;
using Disco.Services.Web;
@@ -291,14 +290,15 @@ namespace Disco.Web.Areas.API.Controllers
var subjects = Subjects
.Where(s => !string.IsNullOrWhiteSpace(s))
.Select(s => s.Trim())
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveADObject(s, Quick: true)))
.Where(s => s.Item2 is ADUserAccount || s.Item2 is ADGroup)
.ToList();
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
if (invalidSubjects.Count > 0)
throw new ArgumentException(string.Format("Subjects not found: {0}", string.Join(", ", invalidSubjects)), "Subjects");
var proposedSubjects = subjects.Select(s => s.Item2.NetBiosId).OrderBy(s => s).ToArray();
var proposedSubjects = subjects.Select(s => s.Item2.Id).OrderBy(s => s).ToArray();
subjectIds = string.Join(",", proposedSubjects);
@@ -370,28 +370,5 @@ namespace Disco.Web.Areas.API.Controllers
}
}
#endregion
[DiscoAuthorize(Claims.Config.JobQueue.Configure)]
public virtual ActionResult SearchSubjects(string term)
{
var groupResults = ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
var userResults = ActiveDirectory.SearchUserAccounts(term).Cast<IActiveDirectoryObject>();
var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName)
.Select(r => Models.JobQueue.SubjectItem.FromActiveDirectoryObject(r)).ToList();
return Json(results, JsonRequestBehavior.AllowGet);
}
[DiscoAuthorize(Claims.Config.JobQueue.Configure)]
public virtual ActionResult Subject(string Id)
{
var subject = ActiveDirectory.RetrieveObject(Id, Quick: true);
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
return Json(null, JsonRequestBehavior.AllowGet);
else
return Json(Models.JobQueue.SubjectItem.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
}
}
}
@@ -1,6 +1,5 @@
using Disco.BI.Extensions;
using Disco.Data.Configuration;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Web;
@@ -20,7 +19,7 @@ namespace Disco.Web.Areas.API.Controllers
[DiscoAuthorize(Claims.Config.System.Show)]
public virtual ActionResult UpdateLastNetworkLogonDates()
{
var taskStatus = Disco.Services.Interop.ActiveDirectory.Internal.ADUpdateLastNetworkLogonDateJob.ScheduleImmediately();
var taskStatus = Disco.Services.Interop.ActiveDirectory.ADTaskUpdateNetworkLogonDates.ScheduleImmediately();
return RedirectToAction(MVC.Config.Logging.TaskStatus(taskStatus.SessionId));
}
@@ -126,7 +125,7 @@ namespace Disco.Web.Areas.API.Controllers
if (Image != null && Image.ContentLength > 0)
{
if (Image.ContentType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase))
if (Image.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
{
Database.DiscoConfiguration.OrganisationLogo = Image.InputStream;
@@ -227,7 +226,7 @@ namespace Disco.Web.Areas.API.Controllers
[DiscoAuthorize(Claims.Config.System.ConfigureActiveDirectory)]
public virtual ActionResult UpdateActiveDirectorySearchScope(List<string> Containers, bool redirect = false)
{
ActiveDirectory.UpdateSearchContainers(Database, Containers);
ActiveDirectory.Context.UpdateSearchContainers(Database, Containers);
Database.SaveChanges();
if (redirect)
@@ -237,17 +236,17 @@ namespace Disco.Web.Areas.API.Controllers
}
[DiscoAuthorize(Claims.Config.System.ConfigureActiveDirectory)]
public virtual ActionResult UpdateActiveDirectorySearchEntireForest(bool SearchEntireForest, bool redirect = false)
public virtual ActionResult UpdateActiveDirectorySearchAllForestServers(bool SearchAllForestServers, bool redirect = false)
{
try
{
var result = ActiveDirectory.UpdateSearchEntireForest(Database, SearchEntireForest);
var result = ActiveDirectory.Context.UpdateSearchAllForestServers(Database, SearchAllForestServers);
Database.SaveChanges();
if (!result)
{
var forestServers = ActiveDirectory.LoadForestServers();
var forestServers = ActiveDirectory.Context.ForestServers;
if (forestServers.Count > ActiveDirectory.MaxForestServerSearch)
throw new InvalidOperationException(string.Format("This forest contains more than the Max Forest Server Search restriction ({0})", ActiveDirectory.MaxForestServerSearch));
else
@@ -271,8 +270,8 @@ namespace Disco.Web.Areas.API.Controllers
[DiscoAuthorizeAny(Claims.Config.System.ConfigureActiveDirectory, Claims.Config.DeviceProfile.Configure)]
public virtual ActionResult DomainOrganisationalUnits()
{
var domainOUs = ActiveDirectory.Domains
.Select(d => new Models.System.DomainOrganisationalUnitsModel() { Domain = d, OrganisationalUnits = ActiveDirectory.RetrieveOrganisationalUnitStructure(d) })
var domainOUs = ActiveDirectory.RetrieveADOrganisationalUnitStructure()
.Select(d => new Models.System.DomainOrganisationalUnitsModel() { Domain = d.Item1, OrganisationalUnits = d.Item2})
.Select(ous => ous.ToFancyTreeNode()).ToList();
return new JsonResult()
@@ -283,6 +282,29 @@ namespace Disco.Web.Areas.API.Controllers
};
}
[DiscoAuthorizeAny(Claims.DiscoAdminAccount, Claims.Config.JobQueue.Configure)]
public virtual ActionResult SearchSubjects(string term)
{
var groupResults = ActiveDirectory.SearchADGroups(term).Cast<IADObject>();
var userResults = ActiveDirectory.SearchADUserAccounts(term, true).Cast<IADObject>();
var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName)
.Select(r => Models.Shared.SubjectDescriptorModel.FromActiveDirectoryObject(r)).ToList();
return Json(results, JsonRequestBehavior.AllowGet);
}
[DiscoAuthorizeAny(Claims.DiscoAdminAccount, Claims.Config.JobQueue.Configure)]
public virtual ActionResult Subject(string Id)
{
var subject = ActiveDirectory.RetrieveADObject(Id, Quick: true);
if (subject == null)
return Json(null, JsonRequestBehavior.AllowGet);
else
return Json(Models.Shared.SubjectDescriptorModel.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
}
#endregion
#region Proxy Settings
@@ -50,7 +50,7 @@ namespace Disco.Web.Areas.API.Controllers
var thumbPath = ua.RepositoryThumbnailFilename(Database);
if (System.IO.File.Exists(thumbPath))
{
if (thumbPath.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
if (thumbPath.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
return File(thumbPath, "image/png");
else
return File(thumbPath, "image/jpg");
@@ -65,7 +65,7 @@ namespace Disco.Web.Areas.API.Controllers
public virtual ActionResult AttachmentUpload(string id, string Domain, string Comments)
{
if (string.IsNullOrEmpty(Domain))
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
id = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + id;
else
id = Domain + @"\" + id;
@@ -78,7 +78,7 @@ namespace Disco.Web.Areas.API.Controllers
if (file.ContentLength > 0)
{
var contentType = file.ContentType;
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
contentType = BI.Interop.MimeTypes.ResolveMimeType(file.FileName);
var ua = new Disco.Models.Repository.UserAttachment()
@@ -127,7 +127,7 @@ namespace Disco.Web.Areas.API.Controllers
public virtual ActionResult Attachments(string id, string Domain)
{
if (string.IsNullOrEmpty(Domain))
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
id = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + id;
else
id = Domain + @"\" + id;
@@ -151,7 +151,7 @@ namespace Disco.Web.Areas.API.Controllers
var ua = Database.UserAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault();
if (ua != null)
{
if (ua.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
if (ua.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))
Authorization.RequireAny(Claims.User.Actions.RemoveAnyAttachments, Claims.User.Actions.RemoveOwnAttachments);
else
Authorization.Require(Claims.User.Actions.RemoveAnyAttachments);
@@ -174,7 +174,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new ArgumentNullException("AttachmentTypeId");
if (string.IsNullOrEmpty(Domain))
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
id = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + id;
else
id = Domain + @"\" + id;
@@ -1,25 +0,0 @@
using Disco.Models.Interop.ActiveDirectory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Disco.Web.Areas.API.Models.AuthorizationRole
{
public class SubjectItem
{
public string Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public static SubjectItem FromActiveDirectoryObject(IActiveDirectoryObject ADObject)
{
return new Models.AuthorizationRole.SubjectItem()
{
Id = ADObject.NetBiosId,
Name = ADObject.DisplayName,
Type = ADObject is ActiveDirectoryGroup ? "group" : "user"
};
}
}
}
@@ -1,25 +0,0 @@
using Disco.Models.Interop.ActiveDirectory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Disco.Web.Areas.API.Models.JobQueue
{
public class SubjectItem
{
public string Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public static SubjectItem FromActiveDirectoryObject(IActiveDirectoryObject ADObject)
{
return new Models.JobQueue.SubjectItem()
{
Id = ADObject.NetBiosId,
Name = ADObject.DisplayName,
Type = ADObject is ActiveDirectoryGroup ? "group" : "user"
};
}
}
}
@@ -0,0 +1,51 @@
using Disco.Services.Interop.ActiveDirectory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Disco.Web.Areas.API.Models.Shared
{
public class SubjectDescriptorModel
{
public string Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public bool IsGroup { get; set; }
public bool IsUserAccount { get; set; }
public bool IsMachineAccount { get; set; }
public static SubjectDescriptorModel FromActiveDirectoryObject(IADObject ADObject)
{
var item = new SubjectDescriptorModel()
{
Id = ADObject.Id,
Name = ADObject.DisplayName
};
if (ADObject is ADUserAccount)
{
item.IsUserAccount = true;
item.Type = "user";
}
else if (ADObject is ADGroup)
{
item.IsGroup = true;
item.Type = "group";
}
else if (ADObject is ADMachineAccount)
{
item.IsMachineAccount = true;
item.Type = "machine";
}
else
{
item.Type = "unknown";
}
return item;
}
}
}
@@ -1,16 +1,14 @@
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Web.Models.Shared;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Disco.Web.Areas.API.Models.System
{
public class DomainOrganisationalUnitsModel
{
public ActiveDirectoryDomain Domain { get; set; }
public List<ActiveDirectoryOrganisationalUnit> OrganisationalUnits { get; set; }
public ADDomain Domain { get; set; }
public List<ADOrganisationalUnit> OrganisationalUnits { get; set; }
public FancyTreeNode ToFancyTreeNode()
{
@@ -21,13 +19,13 @@ namespace Disco.Web.Areas.API.Models.System
key = Domain.DistinguishedName,
title = Domain.NetBiosName,
folder = true,
tooltip = Domain.DnsName,
tooltip = Domain.Name,
children = children,
unselectable = false,
expanded = true
};
}
private FancyTreeNode OrganisationalUnitToFancyTreeNode(ActiveDirectoryOrganisationalUnit OrganisationalUnit)
private FancyTreeNode OrganisationalUnitToFancyTreeNode(ADOrganisationalUnit OrganisationalUnit)
{
FancyTreeNode[] children = OrganisationalUnit.Children == null
? null
@@ -6,6 +6,7 @@ using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Plugins.Features.UIExtension;
using Disco.Services.Users;
using Disco.Services.Web;
using Disco.Web.Areas.API.Models.Shared;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -27,10 +28,10 @@ namespace Disco.Web.Areas.Config.Controllers
throw new ArgumentException("Invalid Authorization Role Id");
var token = RoleToken.FromAuthorizationRole(ar);
var subjects = token.SubjectIds == null ? new List<Models.AuthorizationRole.SubjectDescriptorModel>() :
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
var subjects = token.SubjectIds == null ? new List<SubjectDescriptorModel>() :
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveADObject(subjectId, Quick: true))
.Where(item => item != null)
.Select(item => Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
.Select(item => SubjectDescriptorModel.FromActiveDirectoryObject(item))
.OrderBy(item => item.Name).ToList();
var m = new Models.AuthorizationRole.ShowModel()
@@ -53,9 +54,9 @@ namespace Disco.Web.Areas.Config.Controllers
.Select(ar => RoleToken.FromAuthorizationRole(ar)).Cast<IRoleToken>().ToList();
var administratorSubjects = UserService.AdministratorSubjectIds
.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
.Select(subjectId => ActiveDirectory.RetrieveADObject(subjectId, Quick: true))
.Where(item => item != null)
.Select(item => Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
.Select(item => SubjectDescriptorModel.FromActiveDirectoryObject(item))
.OrderBy(item => item.Name).ToList();
var m = new Models.AuthorizationRole.IndexModel()
@@ -77,7 +77,7 @@ namespace Disco.Web.Areas.Config.Controllers
ComputerNameTemplate = DeviceProfile.DefaultComputerNameTemplate,
ProvisionADAccount = true,
DistributionType = DeviceProfile.DistributionTypes.OneToMany,
OrganisationalUnit = ActiveDirectory.PrimaryDomain.GetDefaultComputerContainer()
OrganisationalUnit = ActiveDirectory.Context.PrimaryDomain.DefaultComputerContainer
}
};
@@ -6,6 +6,7 @@ using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Jobs.JobQueues;
using Disco.Services.Plugins.Features.UIExtension;
using Disco.Services.Web;
using Disco.Web.Areas.API.Models.Shared;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -28,10 +29,10 @@ namespace Disco.Web.Areas.Config.Controllers
throw new ArgumentException("Invalid Job Queue Id");
var token = JobQueueToken.FromJobQueue(jq);
var subjects = token.SubjectIds == null ? new List<Models.JobQueue.ShowModel.SubjectDescriptor>() :
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
var subjects = token.SubjectIds == null ? new List<SubjectDescriptorModel>() :
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveADObject(subjectId, Quick: true))
.Where(item => item != null)
.Select(item => Models.JobQueue.ShowModel.SubjectDescriptor.FromActiveDirectoryObject(item))
.Select(item => SubjectDescriptorModel.FromActiveDirectoryObject(item))
.OrderBy(item => item.Name).ToList();
var totalJobCount = Database.JobQueueJobs.Where(jqj => jqj.JobQueueId == id.Value).Select(jqj => jqj.Job).Distinct().Count();
@@ -5,6 +5,7 @@ using System.Web;
using Disco.Data.Repository;
using Disco.Models.UI.Config.AuthorizationRole;
using Disco.Models.Services.Authorization;
using Disco.Web.Areas.API.Models.Shared;
namespace Disco.Web.Areas.Config.Models.AuthorizationRole
{
@@ -1,6 +1,6 @@
using Disco.Models.Services.Authorization;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.UI.Config.AuthorizationRole;
using Disco.Web.Areas.API.Models.Shared;
using Disco.Web.Models.Shared;
using System;
using System.Collections.Generic;
@@ -1,25 +0,0 @@
using Disco.Models.Interop.ActiveDirectory;
namespace Disco.Web.Areas.Config.Models.AuthorizationRole
{
public class SubjectDescriptorModel
{
public bool IsGroup { get; set; }
public string Name { get; set; }
public string Id { get; set; }
public static SubjectDescriptorModel FromActiveDirectoryObject(IActiveDirectoryObject ADObject)
{
var item = new SubjectDescriptorModel()
{
Id = ADObject.NetBiosId,
Name = ADObject.DisplayName
};
if (ADObject is ActiveDirectoryGroup)
item.IsGroup = true;
return item;
}
}
}
@@ -5,6 +5,7 @@ using System.Web;
using System.Web.Mvc;
using Disco.Services.Plugins;
using Disco.Models.UI.Config.DeviceProfile;
using Disco.Services.Interop.ActiveDirectory;
namespace Disco.Web.Areas.Config.Models.DeviceProfile
{
@@ -15,6 +16,23 @@ namespace Disco.Web.Areas.Config.Models.DeviceProfile
public Disco.Models.BI.Config.OrganisationAddress DefaultOrganisationAddress { get; set; }
public List<Disco.Models.BI.Config.OrganisationAddress> OrganisationAddresses { get; set; }
public string FriendlyOrganisationalUnitName
{
get
{
if (string.IsNullOrEmpty(this.DeviceProfile.OrganisationalUnit))
{
var domain = ActiveDirectory.Context.PrimaryDomain;
return domain.FriendlyDistinguishedNamePath(domain.DefaultComputerContainer);
}
else
{
var domain = ActiveDirectory.Context.GetDomainFromDistinguishedName(this.DeviceProfile.OrganisationalUnit);
return domain.FriendlyDistinguishedNamePath(this.DeviceProfile.OrganisationalUnit);
}
}
}
public List<PluginFeatureManifest> CertificateProviders { get; set; }
public int DeviceCount { get; set; }
@@ -1,10 +1,7 @@
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Services.Jobs.JobQueues;
using Disco.Models.Services.Jobs.JobQueues;
using Disco.Models.UI.Config.JobQueue;
using System;
using Disco.Web.Areas.API.Models.Shared;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Disco.Web.Areas.Config.Models.JobQueue
{
@@ -12,28 +9,7 @@ namespace Disco.Web.Areas.Config.Models.JobQueue
{
public IJobQueueToken Token { get; set; }
public List<SubjectDescriptor> Subjects { get; set; }
public class SubjectDescriptor
{
public bool IsGroup { get; set; }
public string Name { get; set; }
public string Id { get; set; }
public static SubjectDescriptor FromActiveDirectoryObject(IActiveDirectoryObject ADObject)
{
var item = new SubjectDescriptor()
{
Id = ADObject.NetBiosId,
Name = ADObject.DisplayName
};
if (ADObject is ActiveDirectoryGroup)
item.IsGroup = true;
return item;
}
}
public List<SubjectDescriptorModel> Subjects { get; set; }
public int OpenJobCount { get; set; }
public int TotalJobCount { get; set; }
@@ -41,6 +17,5 @@ namespace Disco.Web.Areas.Config.Models.JobQueue
public List<Disco.Models.Repository.JobType> JobTypes { get; set; }
public bool CanDelete { get; set; }
}
}
@@ -8,7 +8,6 @@ using System.Data.SqlClient;
using Disco.Data.Repository;
using Disco.Models.BI.Interop.Community;
using Disco.Services.Tasks;
using Disco.Models.Interop.ActiveDirectory;
using System.DirectoryServices.ActiveDirectory;
using Disco.Services.Interop.ActiveDirectory;
@@ -77,14 +76,14 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig
#region Active Directory
[Display(Name="Search Entire Forest")]
public bool ADSearchEntireForest { get; set; }
[Display(Name="Search All Forest Servers")]
public bool ADSearchAllForestServers { get; set; }
public ActiveDirectoryDomain ADPrimaryDomain { get; set; }
public List<ActiveDirectoryDomain> ADAdditionalDomains { get; set; }
public ActiveDirectorySite ADSite { get; set; }
public List<Tuple<DirectoryServer, bool>> ADSiteServers { get; set; }
public List<Tuple<string, ActiveDirectoryDomain, string>> ADSearchContainers { get; set; }
public List<ADDomain> ADDomains { get; set; }
public ADDomain ADPrimaryDomain { get; set; }
public ADSite ADSite { get; set; }
public List<ADDomainController> ADServers { get; set; }
public List<Tuple<string, ADDomain, string>> ADSearchContainers { get; set; }
public List<string> ADForestServers { get; set; }
#endregion
@@ -119,28 +118,28 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig
};
// AD
m.ADPrimaryDomain = ActiveDirectory.PrimaryDomain;
m.ADAdditionalDomains = ActiveDirectory.Domains.Where(d => d != m.ADPrimaryDomain).ToList();
m.ADSite = ActiveDirectory.Site;
m.ADSiteServers = m.ADSite.Servers.Cast<DirectoryServer>().Select(s => Tuple.Create(s, s.Reachable())).ToList();
m.ADDomains = ActiveDirectory.Context.Domains.ToList();
m.ADPrimaryDomain = ActiveDirectory.Context.PrimaryDomain;
m.ADSite = ActiveDirectory.Context.Site;
m.ADServers = ActiveDirectory.Context.Domains.SelectMany(d => d.DomainControllers).ToList();
var configSearchContainers = config.ActiveDirectory.SearchContainers;
m.ADSearchContainers = configSearchContainers == null ? null : configSearchContainers.SelectMany(d => d.Value, (k, c) =>
{
var domain = ActiveDirectory.GetDomainByDnsName(k.Key);
return Tuple.Create(c, domain, domain.GetFriendlyOrganisationalUnitName(c));
var domain = ActiveDirectory.Context.GetDomainByName(k.Key);
return Tuple.Create(c, domain, domain.FriendlyDistinguishedNamePath(c));
}).ToList();
var loadForestServersTask = ActiveDirectory.LoadForestServersAsync();
var loadForestServersTask = ADDiscoverForestServers.LoadForestServersAsync();
if (loadForestServersTask.Wait(TimeSpan.FromSeconds(1)))
{
m.ADForestServers = loadForestServersTask.Result;
var configValue = config.ActiveDirectory.SearchEntireForest ?? true;
m.ADSearchEntireForest = configValue && m.ADForestServers.Count <= ActiveDirectory.MaxForestServerSearch;
var configValue = config.ActiveDirectory.SearchAllForestServers ?? true;
m.ADSearchAllForestServers = configValue && m.ADForestServers.Count <= ActiveDirectory.MaxForestServerSearch;
}
else
{
m.ADForestServers = null;
m.ADSearchEntireForest = config.ActiveDirectory.SearchEntireForest ?? true;
m.ADSearchAllForestServers = config.ActiveDirectory.SearchAllForestServers ?? true;
}
return m;
@@ -90,7 +90,7 @@ else
textAdd.watermark('Search Subjects')
.autocomplete({
source: '@(Url.Action(MVC.API.AuthorizationRole.SearchSubjects()))',
source: '@(Url.Action(MVC.API.System.SearchSubjects()))',
minLength: 2,
focus: function (e, ui) {
textAdd.val(ui.item.Id);
@@ -148,32 +148,37 @@ else
var id = textAdd.val();
$.ajax({
url: '@Url.Action(MVC.API.AuthorizationRole.Subject())',
url: '@Url.Action(MVC.API.System.Subject())',
method: 'post',
data: { Id: id }
}).done(function (response) {
if (response) {
if (list.find('li[data-subjectid="' + response.Id.replace('\\', '\\\\') + '"]').length == 0) {
if (response.IsGroup || response.IsUserAccount) {
if (list.find('li[data-subjectid="' + response.Id.replace('\\', '\\\\') + '"]').length == 0) {
var liIcon = $('<i>').addClass('fa fa-lg');
if (response.Type === 'user')
liIcon.addClass('fa-user');
else
liIcon.addClass('fa-users');
var liIcon = $('<i>').addClass('fa fa-lg');
if (response.Type === 'user')
liIcon.addClass('fa-user');
else
liIcon.addClass('fa-users');
var li = $('<li>')
.append(liIcon)
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
.append($('<i>').addClass('fa fa-times-circle remove'))
.addClass(response.Type)
.attr('data-subjectid', response.Id)
.attr('data-subjectstatus', 'new');
var li = $('<li>')
.append(liIcon)
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
.append($('<i>').addClass('fa fa-times-circle remove'))
.addClass(response.Type)
.attr('data-subjectid', response.Id)
.attr('data-subjectstatus', 'new');
list.append(li);
list.append(li);
updateNoSubjects();
} else {
alert('That subject has already been added');
updateNoSubjects();
} else {
alert('That subject has already been added');
}
}
else {
alert(response.Name + ' ['+response.Id+'] is a ' + response.Type + '. Only users and groups can be added.');
}
} else {
alert('Unknown Id');
@@ -385,7 +385,7 @@ WriteLiteral(@"></form>
#line 93 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
Write(Url.Action(MVC.API.AuthorizationRole.SearchSubjects()));
Write(Url.Action(MVC.API.System.SearchSubjects()));
#line default
@@ -417,42 +417,47 @@ WriteLiteral("\',\r\n minLength: 2,\r\n
#line 151 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
Write(Url.Action(MVC.API.AuthorizationRole.Subject()));
Write(Url.Action(MVC.API.System.Subject()));
#line default
#line hidden
WriteLiteral("\',\r\n method: \'post\',\r\n data: { Id: id }\r\n " +
" }).done(function (response) {\r\n if (response) {\r\n " +
" if (list.find(\'li[data-subjectid=\"\' + response.Id.replace(\'\\\\\', \'\\\\\\\\\') + " +
"\'\"]\').length == 0) {\r\n\r\n var liIcon = $(\'<i>\').addClass(\'" +
"fa fa-lg\');\r\n if (response.Type === \'user\')\r\n " +
" liIcon.addClass(\'fa-user\');\r\n else\r\n " +
" liIcon.addClass(\'fa-users\');\r\n\r\n v" +
"ar li = $(\'<li>\')\r\n .append(liIcon)\r\n " +
" .append($(\'<span>\').text(response.Id == response.Name ? response.Id " +
": response.Name + \' [\' + response.Id + \']\'))\r\n .appen" +
"d($(\'<i>\').addClass(\'fa fa-times-circle remove\'))\r\n ." +
"addClass(response.Type)\r\n .attr(\'data-subjectid\', res" +
"ponse.Id)\r\n .attr(\'data-subjectstatus\', \'new\');\r\n\r\n " +
" list.append(li);\r\n\r\n updateNoSubjec" +
"ts();\r\n } else {\r\n alert(\'That subject" +
" has already been added\');\r\n }\r\n } else {\r\n " +
" alert(\'Unknown Id\');\r\n }\r\n }).fail(fu" +
"nction (jqXHR, textStatus, errorThrown) {\r\n alert(\'Error: \' + err" +
"orThrown);\r\n });\r\n return false;\r\n }\r\n\r\n " +
" function updateNoSubjects() {\r\n if (list.find(\'li:visible\').leng" +
"th > 0)\r\n noSubjects.hide();\r\n else\r\n n" +
"oSubjects.show();\r\n }\r\n\r\n function saveChanges() {\r\n va" +
"r form = $(\'#Config_AuthRoles_Subjects_Update_Dialog_Form\').empty();\r\n\r\n " +
" list.find(\'li[data-subjectstatus!=\"removed\"]\').each(function () {\r\n " +
" var subjectId = $(this).attr(\'data-subjectid\');\r\n\r\n form.a" +
"ppend($(\'<input>\').attr({\r\n \'name\': \'Subjects\',\r\n " +
" \'type\': \'hidden\'\r\n }).val(subjectId));\r\n\r\n })." +
"get();\r\n\r\n form.submit();\r\n\r\n dialog.dialog(\"disable\");\r\n " +
" dialog.dialog(\"option\", \"buttons\", null);\r\n }\r\n\r\n $(fun" +
"ction () {\r\n $(\'#Config_AuthRoles_UpdateAdministrators\').click(showDi" +
"alog);\r\n });\r\n\r\n })();\r\n</script>\r\n<!-- #endregion -->\r\n<div");
" if (response.IsGroup || response.IsUserAccount) {\r\n " +
" if (list.find(\'li[data-subjectid=\"\' + response.Id.replace(\'\\\\\', \'\\\\\\\\\') + \'\"]\')" +
".length == 0) {\r\n\r\n var liIcon = $(\'<i>\').addClass(\'f" +
"a fa-lg\');\r\n if (response.Type === \'user\')\r\n " +
" liIcon.addClass(\'fa-user\');\r\n " +
"else\r\n liIcon.addClass(\'fa-users\');\r\n\r\n " +
" var li = $(\'<li>\')\r\n .append(li" +
"Icon)\r\n .append($(\'<span>\').text(response.Id == r" +
"esponse.Name ? response.Id : response.Name + \' [\' + response.Id + \']\'))\r\n " +
" .append($(\'<i>\').addClass(\'fa fa-times-circle remove\'))" +
"\r\n .addClass(response.Type)\r\n " +
" .attr(\'data-subjectid\', response.Id)\r\n " +
" .attr(\'data-subjectstatus\', \'new\');\r\n\r\n list.append" +
"(li);\r\n\r\n updateNoSubjects();\r\n " +
" } else {\r\n alert(\'That subject has already been add" +
"ed\');\r\n }\r\n }\r\n els" +
"e {\r\n alert(response.Name + \' [\'+response.Id+\'] is a \' + " +
"response.Type + \'. Only users and groups can be added.\');\r\n }" +
"\r\n } else {\r\n alert(\'Unknown Id\');\r\n " +
" }\r\n }).fail(function (jqXHR, textStatus, errorThrown) {\r\n " +
" alert(\'Error: \' + errorThrown);\r\n });\r\n retu" +
"rn false;\r\n }\r\n\r\n function updateNoSubjects() {\r\n i" +
"f (list.find(\'li:visible\').length > 0)\r\n noSubjects.hide();\r\n " +
" else\r\n noSubjects.show();\r\n }\r\n\r\n function " +
"saveChanges() {\r\n var form = $(\'#Config_AuthRoles_Subjects_Update_Dia" +
"log_Form\').empty();\r\n\r\n list.find(\'li[data-subjectstatus!=\"removed\"]\'" +
").each(function () {\r\n var subjectId = $(this).attr(\'data-subject" +
"id\');\r\n\r\n form.append($(\'<input>\').attr({\r\n \'n" +
"ame\': \'Subjects\',\r\n \'type\': \'hidden\'\r\n }).val(" +
"subjectId));\r\n\r\n }).get();\r\n\r\n form.submit();\r\n\r\n " +
" dialog.dialog(\"disable\");\r\n dialog.dialog(\"option\", \"buttons\", nul" +
"l);\r\n }\r\n\r\n $(function () {\r\n $(\'#Config_AuthRoles_Upda" +
"teAdministrators\').click(showDialog);\r\n });\r\n\r\n })();\r\n</script>\r\n<!--" +
" #endregion -->\r\n<div");
WriteLiteral(" class=\"actionBar\"");
@@ -467,7 +472,7 @@ WriteLiteral(" class=\"button\"");
WriteLiteral(">Update Disco Administrators [");
#line 221 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
#line 226 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
Write(Model.AdministratorSubjects.Count);
@@ -478,7 +483,7 @@ WriteLiteral("]</a>\r\n");
WriteLiteral(" ");
#line 222 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
#line 227 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
Write(Html.ActionLinkButton("Create Authorization Role", MVC.Config.AuthorizationRole.Create()));
@@ -112,7 +112,7 @@
textAdd.watermark('Search Subjects')
.autocomplete({
source: '@(Url.Action(MVC.API.AuthorizationRole.SearchSubjects()))',
source: '@(Url.Action(MVC.API.System.SearchSubjects()))',
minLength: 2,
focus: function (e, ui) {
textAdd.val(ui.item.Id);
@@ -169,32 +169,36 @@
var id = textAdd.val();
$.ajax({
url: '@Url.Action(MVC.API.AuthorizationRole.Subject())',
url: '@Url.Action(MVC.API.System.Subject())',
method: 'post',
data: { Id: id }
}).done(function(response){
if (response){
if (list.find('li[data-subjectid="'+response.Id.replace('\\', '\\\\')+'"]').length == 0){
if (response.IsGroup || response.IsUserAccount) {
if (list.find('li[data-subjectid="'+response.Id.replace('\\', '\\\\')+'"]').length == 0){
var liIcon = $('<i>').addClass('fa fa-lg');
if (response.Type === 'user')
liIcon.addClass('fa-user');
else
liIcon.addClass('fa-users');
var liIcon = $('<i>').addClass('fa fa-lg');
if (response.Type === 'user')
liIcon.addClass('fa-user');
else
liIcon.addClass('fa-users');
var li = $('<li>')
.append(liIcon)
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
.append($('<i>').addClass('fa fa-times-circle remove'))
.addClass(response.Type)
.attr('data-subjectid', response.Id)
.attr('data-subjectstatus', 'new');
var li = $('<li>')
.append(liIcon)
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
.append($('<i>').addClass('fa fa-times-circle remove'))
.addClass(response.Type)
.attr('data-subjectid', response.Id)
.attr('data-subjectstatus', 'new');
list.append(li);
list.append(li);
updateNoSubjects();
updateNoSubjects();
}else{
alert('That subject has already been added');
}
}else{
alert('That subject has already been added');
alert(response.Name + ' ['+response.Id+'] is a ' + response.Type + '. Only users and groups can be added.');
}
}else{
alert('Unknown Id');
@@ -500,7 +500,7 @@ WriteLiteral("></form>\r\n </div>\r\n <scr
#line 115 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
Write(Url.Action(MVC.API.AuthorizationRole.SearchSubjects()));
Write(Url.Action(MVC.API.System.SearchSubjects()));
#line default
@@ -544,7 +544,7 @@ WriteLiteral("\',\r\n minLength: 2,\r
#line 172 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
Write(Url.Action(MVC.API.AuthorizationRole.Subject()));
Write(Url.Action(MVC.API.System.Subject()));
#line default
@@ -552,49 +552,54 @@ WriteLiteral("\',\r\n minLength: 2,\r
WriteLiteral("\',\r\n method: \'post\',\r\n " +
" data: { Id: id }\r\n }).done(function(r" +
"esponse){\r\n if (response){\r\n " +
" if (list.find(\'li[data-subjectid=\"\'+response.Id.replace(\'" +
"\\\\\', \'\\\\\\\\\')+\'\"]\').length == 0){\r\n \r\n" +
" var liIcon = $(\'<i>\').addClass(\'fa f" +
"a-lg\');\r\n if (response.Type === \'user" +
"\')\r\n liIcon.addClass(\'fa-user\');\r" +
"\n else\r\n " +
" liIcon.addClass(\'fa-users\');\r\n\r\n " +
" var li = $(\'<li>\')\r\n " +
" .append(liIcon)\r\n .append($(\'<" +
"span>\').text(response.Id == response.Name ? response.Id : response.Name + \' [\' " +
"+ response.Id + \']\'))\r\n .append($" +
"(\'<i>\').addClass(\'fa fa-times-circle remove\'))\r\n " +
" .addClass(response.Type)\r\n " +
" .attr(\'data-subjectid\', response.Id)\r\n " +
" .attr(\'data-subjectstatus\', \'new\');\r\n\r\n " +
" list.append(li);\r\n\r\n " +
" updateNoSubjects(); \r\n " +
" }else{\r\n aler" +
"t(\'That subject has already been added\');\r\n " +
" }\r\n }else{\r\n " +
" alert(\'Unknown Id\');\r\n }\r\n " +
" }).fail(function(jqXHR, textStatus, errorThrown){\r\n " +
" alert(\'Error: \' + errorThrown);\r\n " +
" });\r\n }\r\n\r\n " +
" function updateNoSubjects(){\r\n if (list.find" +
"(\'li:visible\').length > 0)\r\n noSubjects.hide(" +
");\r\n else\r\n no" +
"Subjects.show();\r\n }\r\n\r\n f" +
"unction saveChanges(){\r\n var form = $(\'#Config_Au" +
"thRoles_Subjects_Update_Dialog_Form\').empty();\r\n\r\n " +
" list.find(\'li[data-subjectstatus!=\"removed\"]\').each(function(){\r\n " +
" var subjectId = $(this).attr(\'data-subjectid\');\r\n " +
" \r\n form.append($(" +
"\'<input>\').attr({\r\n \'name\': \'Subjects\',\r\n" +
" \'type\': \'hidden\'\r\n " +
" }).val(subjectId));\r\n\r\n }).get();\r\n" +
"\r\n form.submit();\r\n\r\n " +
" dialog.dialog(\"disable\");\r\n dialog.dialog(\"op" +
"tion\", \"buttons\", null);\r\n }\r\n\r\n " +
" $(function(){\r\n $(\'#Config_AuthRoles_Subje" +
"cts_Update\').click(showDialog);\r\n });\r\n\r\n " +
" })();\r\n </script>\r\n </div>\r\n " +
" </td>\r\n </tr>\r\n <tr>\r\n <td");
" if (response.IsGroup || response.IsUserAccount) {\r\n " +
" if (list.find(\'li[data-subjectid=\"\'+respon" +
"se.Id.replace(\'\\\\\', \'\\\\\\\\\')+\'\"]\').length == 0){\r\n " +
" \r\n var liIcon = $(\'<" +
"i>\').addClass(\'fa fa-lg\');\r\n if (" +
"response.Type === \'user\')\r\n l" +
"iIcon.addClass(\'fa-user\');\r\n else" +
"\r\n liIcon.addClass(\'fa-users\'" +
");\r\n\r\n var li = $(\'<li>\')\r\n " +
" .append(liIcon)\r\n " +
" .append($(\'<span>\').text(response.Id == respo" +
"nse.Name ? response.Id : response.Name + \' [\' + response.Id + \']\'))\r\n " +
" .append($(\'<i>\').addClass(\'fa fa-times" +
"-circle remove\'))\r\n .addClass" +
"(response.Type)\r\n .attr(\'data" +
"-subjectid\', response.Id)\r\n ." +
"attr(\'data-subjectstatus\', \'new\');\r\n\r\n " +
" list.append(li);\r\n\r\n update" +
"NoSubjects(); \r\n " +
" }else{\r\n alert" +
"(\'That subject has already been added\');\r\n " +
" }\r\n }else{\r\n " +
" alert(response.Name + \' [\'+response.Id+\'] is a \' + response" +
".Type + \'. Only users and groups can be added.\');\r\n " +
" }\r\n }else{\r\n " +
" alert(\'Unknown Id\');\r\n }\r\n " +
" }).fail(function(jqXHR, textStatus, errorThrown){" +
"\r\n alert(\'Error: \' + errorThrown);\r\n " +
" });\r\n }\r\n\r\n " +
" function updateNoSubjects(){\r\n if (l" +
"ist.find(\'li:visible\').length > 0)\r\n noSubjec" +
"ts.hide();\r\n else\r\n " +
" noSubjects.show();\r\n }\r\n\r\n " +
" function saveChanges(){\r\n var form = $(\'#C" +
"onfig_AuthRoles_Subjects_Update_Dialog_Form\').empty();\r\n\r\n " +
" list.find(\'li[data-subjectstatus!=\"removed\"]\').each(function(){\r\n " +
" var subjectId = $(this).attr(\'data-subjectid\');\r\n" +
" \r\n form.a" +
"ppend($(\'<input>\').attr({\r\n \'name\': \'Subj" +
"ects\',\r\n \'type\': \'hidden\'\r\n " +
" }).val(subjectId));\r\n\r\n })." +
"get();\r\n\r\n form.submit();\r\n\r\n " +
" dialog.dialog(\"disable\");\r\n dialog.di" +
"alog(\"option\", \"buttons\", null);\r\n }\r\n\r\n " +
" $(function(){\r\n $(\'#Config_AuthRol" +
"es_Subjects_Update\').click(showDialog);\r\n });\r\n\r\n " +
" })();\r\n </script>\r\n </div>" +
"\r\n </td>\r\n </tr>\r\n <tr>\r\n <td");
WriteLiteral(" colspan=\"2\"");
@@ -613,7 +618,7 @@ WriteLiteral(" class=\"button small disabled\"");
WriteLiteral(">Save Changes</a>");
#line 247 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
#line 251 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
Write(AjaxHelpers.AjaxLoader());
@@ -623,7 +628,7 @@ WriteLiteral("\r\n </div>\r\n <script>\r\n
"(){\r\n var claimNodes = ");
#line 251 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
#line 255 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
Write(new HtmlString(Newtonsoft.Json.JsonConvert.SerializeObject(Model.ClaimNavigatorFancyTreeNodes)));
@@ -662,7 +667,7 @@ WriteLiteral(@";
url: '");
#line 281 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
#line 285 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
Write(Url.Action(MVC.API.AuthorizationRole.UpdateClaims(Model.Token.Role.Id)));
@@ -702,7 +707,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 307 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
#line 311 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
Write(Html.ActionLinkButton("Delete", MVC.API.AuthorizationRole.Delete(Model.Token.Role.Id, true), "Config_AuthRoles_Actions_Delete_Button"));
@@ -523,24 +523,15 @@
<td>@if (canConfig)
{
<div id="DeviceProfile_OrganisationalUnit" class="code" data-value="@Model.DeviceProfile.OrganisationalUnit">
@if (string.IsNullOrEmpty(Model.DeviceProfile.OrganisationalUnit))
{
<span>{Default Computers Container}</span>
}
else
{
var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit);
<span>
@Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit)
</span>
}
<span>
@Model.FriendlyOrganisationalUnitName
</span>
</div>
<a id="changeOrganisationalUnit" href="#" class="button small">Change</a>@AjaxHelpers.AjaxLoader()
<div id="dialogOrganisationalUnit" title="Organisational Unit" class="dialog">
<div id="dialogOrganisationalUnit_Loading">
@AjaxHelpers.AjaxLoader() Loading Organisational Units
</div>
@AjaxHelpers.AjaxLoader() Loading Organisational Units
</div>
<div id="treeOrganisationalUnit" class="organisationalUnitTree">
</div>
</div>
@@ -660,18 +651,9 @@
else
{
<div id="displayOrganisationalUnit" class="code">
@if (string.IsNullOrEmpty(Model.DeviceProfile.OrganisationalUnit))
{
<span>{Default Computers Container}</span>
}
else
{
var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit);
<span>
@Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit)
</span>
}
<span>
@Model.FriendlyOrganisationalUnitName
</span>
</div>
}
<div style="margin-top: 8px;">
@@ -1597,56 +1597,18 @@ WriteLiteral(" data-value=\"");
#line hidden
WriteLiteral("\"");
WriteLiteral(">\r\n");
WriteLiteral(">\r\n <span>\r\n");
WriteLiteral(" ");
#line 526 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line default
#line hidden
#line 526 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
if (string.IsNullOrEmpty(Model.DeviceProfile.OrganisationalUnit))
{
#line 527 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Model.FriendlyOrganisationalUnitName);
#line default
#line hidden
WriteLiteral(" <span>{Default Computers Container}</span>\r\n");
#line 529 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
else
{
var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit);
#line default
#line hidden
WriteLiteral(" <span>\r\n");
WriteLiteral(" ");
#line 535 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit));
#line default
#line hidden
WriteLiteral("\r\n </span>\r\n");
#line 537 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
#line default
#line hidden
WriteLiteral(" </div>\r\n");
WriteLiteral("\r\n </span>\r\n </div>\r\n");
WriteLiteral(" <a");
@@ -1659,20 +1621,20 @@ WriteLiteral(" class=\"button small\"");
WriteLiteral(">Change</a>");
#line 539 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 530 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line default
#line hidden
#line 539 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 530 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(AjaxHelpers.AjaxLoader());
#line default
#line hidden
#line 539 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 530 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
@@ -1692,17 +1654,17 @@ WriteLiteral(" id=\"dialogOrganisationalUnit_Loading\"");
WriteLiteral(">\r\n");
WriteLiteral(" ");
WriteLiteral(" ");
#line 542 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(AjaxHelpers.AjaxLoader());
#line 533 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(AjaxHelpers.AjaxLoader());
#line default
#line hidden
WriteLiteral(" Loading Organisational Units\r\n </div>\r\n " +
" <div");
WriteLiteral(" Loading Organisational Units\r\n </div>\r\n <d" +
"iv");
WriteLiteral(" id=\"treeOrganisationalUnit\"");
@@ -1717,7 +1679,7 @@ WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(">\r\n $(function () {\r\n var ouSetUrl = \'");
#line 549 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 540 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Url.Action(MVC.API.DeviceProfile.UpdateOrganisationalUnit(Model.DeviceProfile.Id, null, true)));
@@ -1759,7 +1721,7 @@ WriteLiteral("\';\r\n var ouValue = $(\'#DeviceProfile_Or
" $ouTree.css(\'height\', \'100%\');\r\n\r\n $.getJSON(\'");
#line 599 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 590 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Url.Action(MVC.API.System.DomainOrganisationalUnits()));
@@ -1806,7 +1768,7 @@ WriteLiteral("\', null, function (data) {\r\n
" </script>\r\n");
#line 659 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 650 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
else
{
@@ -1820,59 +1782,21 @@ WriteLiteral(" id=\"displayOrganisationalUnit\"");
WriteLiteral(" class=\"code\"");
WriteLiteral(">\r\n");
WriteLiteral(">\r\n <span>\r\n");
WriteLiteral(" ");
#line 663 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line default
#line hidden
#line 663 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
if (string.IsNullOrEmpty(Model.DeviceProfile.OrganisationalUnit))
{
#line 655 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Model.FriendlyOrganisationalUnitName);
#line default
#line hidden
WriteLiteral(" <span>{Default Computers Container}</span>\r\n");
WriteLiteral("\r\n </span>\r\n </div>\r\n");
#line 666 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
else
{
var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit);
#line default
#line hidden
WriteLiteral(" <span>\r\n");
WriteLiteral(" ");
#line 672 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit));
#line default
#line hidden
WriteLiteral("\r\n </span>\r\n");
#line 674 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
#line default
#line hidden
WriteLiteral(" </div>\r\n");
#line 676 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 658 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
@@ -1885,13 +1809,13 @@ WriteLiteral(" style=\"margin-top: 8px;\"");
WriteLiteral(">\r\n");
#line 678 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 660 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line default
#line hidden
#line 678 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 660 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
if (canConfig)
{
@@ -1907,7 +1831,7 @@ WriteLiteral(" type=\"checkbox\"");
WriteLiteral(" ");
#line 680 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 662 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Model.DeviceProfile.EnforceOrganisationalUnit ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty));
@@ -1928,7 +1852,7 @@ WriteLiteral(@">
$.getJSON('");
#line 687 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 669 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Url.Action(MVC.API.DeviceProfile.UpdateEnforceOrganisationalUnit(Model.DeviceProfile.Id)));
@@ -1948,7 +1872,7 @@ WriteLiteral(@"', data, function (response, result) {
");
#line 698 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 680 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
else
{
@@ -1965,7 +1889,7 @@ WriteLiteral(" type=\"checkbox\"");
WriteLiteral(" ");
#line 701 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 683 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Model.DeviceProfile.EnforceOrganisationalUnit ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty));
@@ -1974,7 +1898,7 @@ WriteLiteral(" ");
WriteLiteral(" disabled=\"disabled\" />\r\n");
#line 702 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 684 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
@@ -1990,7 +1914,7 @@ WriteLiteral(">\r\n Enforce Organisational Unit\r\n
WriteLiteral(" ");
#line 706 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 688 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(AjaxHelpers.AjaxLoader());
@@ -2000,7 +1924,7 @@ WriteLiteral("\r\n </div>\r\n </td>\r\n </tr>\r
"\n");
#line 712 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 694 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
if (canDelete)
{
@@ -2055,7 +1979,7 @@ WriteLiteral(@">
");
#line 748 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 730 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
@@ -2068,13 +1992,13 @@ WriteLiteral(" class=\"actionBar\"");
WriteLiteral(">\r\n");
#line 750 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 732 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line default
#line hidden
#line 750 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 732 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
if (canDelete)
{
@@ -2082,14 +2006,14 @@ WriteLiteral(">\r\n");
#line default
#line hidden
#line 752 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 734 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Html.ActionLinkButton("Delete", MVC.API.DeviceProfile.Delete(Model.DeviceProfile.Id, true), "buttonDelete"));
#line default
#line hidden
#line 752 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 734 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
@@ -2099,7 +2023,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 754 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 736 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
if (Authorization.Has(Claims.Device.Actions.Export))
{
@@ -2107,14 +2031,14 @@ WriteLiteral(" ");
#line default
#line hidden
#line 756 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 738 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Html.ActionLinkButton("Export Devices", MVC.API.DeviceProfile.ExportDevices(Model.DeviceProfile.Id)));
#line default
#line hidden
#line 756 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 738 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
@@ -2124,7 +2048,7 @@ WriteLiteral(" ");
WriteLiteral(" ");
#line 758 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 740 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
if (Authorization.Has(Claims.Device.Search))
{
@@ -2132,14 +2056,14 @@ WriteLiteral(" ");
#line default
#line hidden
#line 760 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 742 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
Write(Html.ActionLinkButton("View Devices", MVC.Search.Query(Model.DeviceProfile.Id.ToString(), "DeviceProfile")));
#line default
#line hidden
#line 760 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
#line 742 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
}
@@ -369,7 +369,7 @@
textAdd.watermark('Search Subjects')
.autocomplete({
source: '@(Url.Action(MVC.API.JobQueue.SearchSubjects()))',
source: '@(Url.Action(MVC.API.System.SearchSubjects()))',
minLength: 2,
focus: function (e, ui) {
textAdd.val(ui.item.Id);
@@ -428,32 +428,36 @@
var id = textAdd.val();
$.ajax({
url: '@Url.Action(MVC.API.JobQueue.Subject())',
url: '@Url.Action(MVC.API.System.Subject())',
method: 'post',
data: { Id: id }
}).done(function (response) {
if (response) {
if (list.find('li[data-subjectid="' + response.Id + '"]').filter('[data-status!="removed"]').length == 0) {
if (response.IsGroup || response.IsUserAccount) {
if (list.find('li[data-subjectid="' + response.Id + '"]').filter('[data-status!="removed"]').length == 0) {
var liIcon = $('<i>').addClass('fa fa-lg');
if (response.Type === 'user')
liIcon.addClass('fa-user');
else
liIcon.addClass('fa-users');
var liIcon = $('<i>').addClass('fa fa-lg');
if (response.Type === 'user')
liIcon.addClass('fa-user');
else
liIcon.addClass('fa-users');
var li = $('<li>')
.append(liIcon)
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
.append($('<i>').addClass('fa fa-times-circle remove'))
.addClass(response.Type)
.attr('data-subjectid', response.Id)
.attr('data-subjectstatus', 'new');
var li = $('<li>')
.append(liIcon)
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
.append($('<i>').addClass('fa fa-times-circle remove'))
.addClass(response.Type)
.attr('data-subjectid', response.Id)
.attr('data-subjectstatus', 'new');
list.append(li);
list.append(li);
updateNoSubjects();
updateNoSubjects();
} else {
alert('That subject has already been added');
}
} else {
alert('That subject has already been added');
alert(response.Name + ' [' + response.Id + '] is a ' + response.Type + '. Only users and groups can be added.');
}
} else {
alert('Unknown Id');
@@ -1321,7 +1321,7 @@ WriteLiteral("></form>\r\n </div>\r\n
#line 372 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
Write(Url.Action(MVC.API.JobQueue.SearchSubjects()));
Write(Url.Action(MVC.API.System.SearchSubjects()));
#line default
@@ -1368,7 +1368,7 @@ WriteLiteral("\',\r\n minLength:
#line 431 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
Write(Url.Action(MVC.API.JobQueue.Subject()));
Write(Url.Action(MVC.API.System.Subject()));
#line default
@@ -1376,53 +1376,58 @@ WriteLiteral("\',\r\n minLength:
WriteLiteral("\',\r\n method: \'post\',\r\n " +
" data: { Id: id }\r\n }).don" +
"e(function (response) {\r\n if (response) {" +
"\r\n if (list.find(\'li[data-subjectid=\"" +
"\' + response.Id + \'\"]\').filter(\'[data-status!=\"removed\"]\').length == 0) {\r\n\r\n " +
" var liIcon = $(\'<i>\').addClass(\'fa " +
"fa-lg\');\r\n if (response.Type === " +
"\'user\')\r\n liIcon.addClass(\'fa" +
"-user\');\r\n else\r\n " +
" liIcon.addClass(\'fa-users\');\r\n\r\n " +
" var li = $(\'<li>\')\r\n " +
" .append(liIcon)\r\n " +
" .append($(\'<span>\').text(response.Id == response.Name ? respons" +
"e.Id : response.Name + \' [\' + response.Id + \']\'))\r\n " +
" .append($(\'<i>\').addClass(\'fa fa-times-circle remove\'))\r\n" +
" .addClass(response.Type)\r\n " +
" .attr(\'data-subjectid\', respon" +
"se.Id)\r\n .attr(\'data-subjects" +
"tatus\', \'new\');\r\n\r\n list.append(l" +
"i);\r\n\r\n updateNoSubjects();\r\n " +
" } else {\r\n " +
" alert(\'That subject has already been added\');\r\n " +
" }\r\n } else {" +
"\r\n alert(\'Unknown Id\');\r\n " +
" }\r\n }).fail(funct" +
"ion (jqXHR, textStatus, errorThrown) {\r\n " +
"alert(\'Error: \' + errorThrown);\r\n });\r\n " +
" }\r\n\r\n function upda" +
"teNoSubjects() {\r\n if (list.find(\'li:visible\'" +
").length > 0)\r\n noSubjects.hide();\r\n " +
" else\r\n noS" +
"ubjects.show();\r\n }\r\n\r\n " +
" function saveChanges() {\r\n var form = $" +
"(\'#Config_JobQueues_Subjects_Update_Dialog_Form\').empty();\r\n\r\n " +
" list.find(\'li[data-subjectstatus!=\"removed\"]\').each(function (" +
") {\r\n var subjectId = $(this).attr(\'data-" +
"subjectid\');\r\n\r\n form.append($(\'<input>\')" +
".attr({\r\n \'name\': \'Subjects\',\r\n " +
" \'type\': \'hidden\'\r\n " +
" }).val(subjectId));\r\n\r\n }).ge" +
"t();\r\n\r\n form.submit();\r\n\r\n " +
" dialog.dialog(\"disable\");\r\n " +
" dialog.dialog(\"option\", \"buttons\", null);\r\n }\r\n\r" +
"\n $(function () {\r\n " +
" $(\'#Config_JobQueues_Subjects_Update\').click(showDialog);\r\n " +
" });\r\n\r\n })();\r\n " +
" </script>\r\n </div>\r\n");
"\r\n if (response.IsGroup || response.I" +
"sUserAccount) {\r\n if (list.find(\'" +
"li[data-subjectid=\"\' + response.Id + \'\"]\').filter(\'[data-status!=\"removed\"]\').le" +
"ngth == 0) {\r\n\r\n var liIcon =" +
" $(\'<i>\').addClass(\'fa fa-lg\');\r\n " +
" if (response.Type === \'user\')\r\n " +
" liIcon.addClass(\'fa-user\');\r\n " +
" else\r\n liIco" +
"n.addClass(\'fa-users\');\r\n\r\n v" +
"ar li = $(\'<li>\')\r\n .appe" +
"nd(liIcon)\r\n .append($(\'<" +
"span>\').text(response.Id == response.Name ? response.Id : response.Name + \' [\' +" +
" response.Id + \']\'))\r\n .a" +
"ppend($(\'<i>\').addClass(\'fa fa-times-circle remove\'))\r\n " +
" .addClass(response.Type)\r\n " +
" .attr(\'data-subjectid\', response.Id)\r\n " +
" .attr(\'data-subjectstatus\', \'new\'" +
");\r\n\r\n list.append(li);\r\n\r\n " +
" updateNoSubjects();\r\n " +
" } else {\r\n " +
" alert(\'That subject has already been added\');\r\n " +
" }\r\n " +
" } else {\r\n alert(response.Name" +
" + \' [\' + response.Id + \'] is a \' + response.Type + \'. Only users and groups can" +
" be added.\');\r\n }\r\n " +
" } else {\r\n aler" +
"t(\'Unknown Id\');\r\n }\r\n " +
" }).fail(function (jqXHR, textStatus, errorThrown) {\r\n " +
" alert(\'Error: \' + errorThrown);\r\n " +
" });\r\n }\r\n\r\n " +
" function updateNoSubjects() {\r\n " +
" if (list.find(\'li:visible\').length > 0)\r\n " +
" noSubjects.hide();\r\n else\r\n " +
" noSubjects.show();\r\n }" +
"\r\n\r\n function saveChanges() {\r\n " +
" var form = $(\'#Config_JobQueues_Subjects_Update_Dialog_Form\')." +
"empty();\r\n\r\n list.find(\'li[data-subjectstatus" +
"!=\"removed\"]\').each(function () {\r\n var s" +
"ubjectId = $(this).attr(\'data-subjectid\');\r\n\r\n " +
" form.append($(\'<input>\').attr({\r\n " +
" \'name\': \'Subjects\',\r\n \'type\': \'hid" +
"den\'\r\n }).val(subjectId));\r\n\r\n " +
" }).get();\r\n\r\n form.s" +
"ubmit();\r\n\r\n dialog.dialog(\"disable\");\r\n " +
" dialog.dialog(\"option\", \"buttons\", null);\r\n " +
" }\r\n\r\n $(function () {\r\n" +
" $(\'#Config_JobQueues_Subjects_Update\').click" +
"(showDialog);\r\n });\r\n\r\n " +
" })();\r\n </script>\r\n </div>\r\n");
#line 499 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 503 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
}
@@ -1432,13 +1437,13 @@ WriteLiteral(" </td>\r\n </tr>\r\n <tr>\r\n
" Jobs:</th>\r\n <td>\r\n <div>\r\n");
#line 506 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 510 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line default
#line hidden
#line 506 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 510 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
if (Model.Token.JobQueue.JobSubTypes.Count > 0)
{
@@ -1448,13 +1453,13 @@ WriteLiteral(" </td>\r\n </tr>\r\n <tr>\r\n
WriteLiteral(" <ul>\r\n");
#line 509 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 513 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line default
#line hidden
#line 509 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 513 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
foreach (var jobType in Model.Token.JobQueue.JobSubTypes.GroupBy(jst => jst.JobType).OrderBy(jtg => jtg.Key.Description))
{
@@ -1466,7 +1471,7 @@ WriteLiteral(" <li>\r\n");
WriteLiteral(" ");
#line 512 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 516 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
Write(jobType.Key.Description);
@@ -1475,13 +1480,13 @@ WriteLiteral(" ");
WriteLiteral("\r\n <ul>\r\n");
#line 514 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 518 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line default
#line hidden
#line 514 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 518 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
if (jobType.Count() == Model.JobTypes.FirstOrDefault(jt => jt.Id == jobType.Key.Id).JobSubTypes.Count)
{
@@ -1495,7 +1500,7 @@ WriteLiteral(" class=\"smallMessage\"");
WriteLiteral(">[All Sub Types]</span></li>\r\n");
#line 517 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 521 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
}
else
{
@@ -1508,7 +1513,7 @@ WriteLiteral(">[All Sub Types]</span></li>\r\n");
WriteLiteral(" <li>");
#line 522 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 526 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
Write(jobSubType.Description);
@@ -1517,7 +1522,7 @@ WriteLiteral(" <li>");
WriteLiteral("</li>\r\n");
#line 523 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 527 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
}
}
@@ -1528,7 +1533,7 @@ WriteLiteral(" </ul>\r\n
"\n");
#line 527 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 531 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
}
@@ -1537,7 +1542,7 @@ WriteLiteral(" </ul>\r\n
WriteLiteral(" </ul>\r\n");
#line 529 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 533 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
}
else
{
@@ -1552,7 +1557,7 @@ WriteLiteral("&lt;None&gt;");
WriteLiteral("\r\n");
#line 533 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 537 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
}
@@ -1561,13 +1566,13 @@ WriteLiteral("\r\n");
WriteLiteral(" </div>\r\n");
#line 535 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 539 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line default
#line hidden
#line 535 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 539 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
if (canConfig)
{
@@ -1595,13 +1600,13 @@ WriteLiteral(" title=\"Job Queue Automatic Types\"");
WriteLiteral(">\r\n");
#line 539 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 543 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line default
#line hidden
#line 539 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 543 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
using (Html.BeginForm(MVC.API.JobQueue.UpdateJobSubTypes(Model.Token.JobQueue.Id, null, true)))
{
var selectedTypes = Model.Token.JobQueue.JobSubTypes.Select(jst => jst.JobType).Distinct().ToList();
@@ -1613,15 +1618,15 @@ WriteLiteral(">\r\n");
#line hidden
WriteLiteral(" <div");
WriteAttribute("id", Tuple.Create(" id=\"", 28527), Tuple.Create("\"", 28549)
, Tuple.Create(Tuple.Create("", 28532), Tuple.Create("trJobType", 28532), true)
WriteAttribute("id", Tuple.Create(" id=\"", 28953), Tuple.Create("\"", 28975)
, Tuple.Create(Tuple.Create("", 28958), Tuple.Create("trJobType", 28958), true)
#line 544 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
, Tuple.Create(Tuple.Create("", 28541), Tuple.Create<System.Object, System.Int32>(jt.Id
#line 548 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
, Tuple.Create(Tuple.Create("", 28967), Tuple.Create<System.Object, System.Int32>(jt.Id
#line default
#line hidden
, 28541), false)
, 28967), false)
);
WriteLiteral(" class=\"jobTypes\"");
@@ -1629,35 +1634,35 @@ WriteLiteral(" class=\"jobTypes\"");
WriteLiteral(">\r\n <h4>\r\n <inp" +
"ut");
WriteAttribute("id", Tuple.Create(" id=\"", 28650), Tuple.Create("\"", 28669)
, Tuple.Create(Tuple.Create("", 28655), Tuple.Create("Types_", 28655), true)
WriteAttribute("id", Tuple.Create(" id=\"", 29076), Tuple.Create("\"", 29095)
, Tuple.Create(Tuple.Create("", 29081), Tuple.Create("Types_", 29081), true)
#line 546 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
, Tuple.Create(Tuple.Create("", 28661), Tuple.Create<System.Object, System.Int32>(jt.Id
#line 550 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
, Tuple.Create(Tuple.Create("", 29087), Tuple.Create<System.Object, System.Int32>(jt.Id
#line default
#line hidden
, 28661), false)
, 29087), false)
);
WriteLiteral(" class=\"jobType\"");
WriteLiteral(" type=\"checkbox\"");
WriteAttribute("value", Tuple.Create(" value=\"", 28702), Tuple.Create("\"", 28718)
WriteAttribute("value", Tuple.Create(" value=\"", 29128), Tuple.Create("\"", 29144)
#line 546 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
, Tuple.Create(Tuple.Create("", 28710), Tuple.Create<System.Object, System.Int32>(jt.Id
#line 550 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
, Tuple.Create(Tuple.Create("", 29136), Tuple.Create<System.Object, System.Int32>(jt.Id
#line default
#line hidden
, 28710), false)
, 29136), false)
);
WriteLiteral(" ");
#line 546 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 550 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
Write(selectedTypes.Contains(jt) ? "checked=\"checked\"" : null);
@@ -1665,21 +1670,21 @@ WriteLiteral(" ");
#line hidden
WriteLiteral(" /><label");
WriteAttribute("for", Tuple.Create(" for=\"", 28789), Tuple.Create("\"", 28809)
, Tuple.Create(Tuple.Create("", 28795), Tuple.Create("Types_", 28795), true)
WriteAttribute("for", Tuple.Create(" for=\"", 29215), Tuple.Create("\"", 29235)
, Tuple.Create(Tuple.Create("", 29221), Tuple.Create("Types_", 29221), true)
#line 546 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
, Tuple.Create(Tuple.Create("", 28801), Tuple.Create<System.Object, System.Int32>(jt.Id
#line 550 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
, Tuple.Create(Tuple.Create("", 29227), Tuple.Create<System.Object, System.Int32>(jt.Id
#line default
#line hidden
, 28801), false)
, 29227), false)
);
WriteLiteral(">");
#line 546 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 550 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
Write(jt.Description);
@@ -1687,15 +1692,15 @@ WriteLiteral(">");
#line hidden
WriteLiteral("</label></h4>\r\n <div");
WriteAttribute("id", Tuple.Create(" id=\"", 28877), Tuple.Create("\"", 28899)
, Tuple.Create(Tuple.Create("", 28882), Tuple.Create("SubTypes_", 28882), true)
WriteAttribute("id", Tuple.Create(" id=\"", 29303), Tuple.Create("\"", 29325)
, Tuple.Create(Tuple.Create("", 29308), Tuple.Create("SubTypes_", 29308), true)
#line 547 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
, Tuple.Create(Tuple.Create("", 28891), Tuple.Create<System.Object, System.Int32>(jt.Id
#line 551 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
, Tuple.Create(Tuple.Create("", 29317), Tuple.Create<System.Object, System.Int32>(jt.Id
#line default
#line hidden
, 28891), false)
, 29317), false)
);
WriteLiteral(" class=\"jobSubTypes\"");
@@ -1705,7 +1710,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 548 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 552 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
Write(CommonHelpers.CheckboxBulkSelect(string.Format("CheckboxBulkSelect_{0}", jt.Id), "div"));
@@ -1716,7 +1721,7 @@ WriteLiteral("\r\n");
WriteLiteral(" ");
#line 549 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 553 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
Write(CommonHelpers.CheckBoxList("JobSubTypes", jt.JobSubTypes.OrderBy(jst => jst.Description).ToSelectListItems(Model.Token.JobQueue.JobSubTypes), 2));
@@ -1726,7 +1731,7 @@ WriteLiteral("\r\n </div>\r\n
"");
#line 552 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 556 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
}
}
@@ -1774,7 +1779,7 @@ WriteLiteral(" <script>\r\n (function
" })();\r\n </script>\r\n");
#line 617 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 621 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
}
@@ -1795,7 +1800,7 @@ WriteLiteral("></i>&nbsp;When jobs of these types are created, they will automat
" </table>\r\n</div>\r\n");
#line 625 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 629 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
if (canDelete || canShowJobs)
{
@@ -1811,7 +1816,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 628 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 632 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
Write(Html.ActionLinkButton("Delete", MVC.API.JobQueue.Delete(Model.Token.JobQueue.Id, true), "Config_JobQueues_Actions_Delete_Button"));
@@ -1866,7 +1871,7 @@ WriteLiteral(@">
WriteLiteral(" ");
#line 665 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 669 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
Write(Html.ActionLinkButton(string.Format("Show {0} job{1}", Model.OpenJobCount, (Model.OpenJobCount == 1 ? null : "s")), MVC.Job.Queue(Model.Token.JobQueue.Id), "Config_JobQueues_Actions_ShowJobs_Button"));
@@ -1875,7 +1880,7 @@ WriteLiteral(" ");
WriteLiteral("\r\n </div>\r\n");
#line 667 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
#line 671 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
}
#line default
@@ -148,22 +148,23 @@
<th style="width: 135px">Primary Domain:
</th>
<td>
<code><strong>@Model.ADPrimaryDomain.DnsName</strong> <span>[@Model.ADPrimaryDomain.NetBiosName]</span></code>
<code><strong>@Model.ADPrimaryDomain.Name</strong> <span>[@Model.ADPrimaryDomain.NetBiosName]</span></code>
</td>
</tr>
<tr>
<th style="width: 135px">Additional Domains:
</th>
<td>
@if (Model.ADAdditionalDomains.Count > 0)
@if (Model.ADDomains.Count > 1)
{
var adDomainFirst = Model.ADAdditionalDomains.First();
<code>@adDomainFirst.DnsName <span>[@adDomainFirst.NetBiosName]</span></code>
foreach (var adDomain in Model.ADAdditionalDomains.Skip(1))
var adAdditionalDomains = Model.ADDomains.Where(d => d != Model.ADPrimaryDomain).OrderBy(d => d.Name).ToList();
var adDomainFirst = adAdditionalDomains.First();
<code>@adDomainFirst.Name <span>[@adDomainFirst.NetBiosName]</span></code>
foreach (var adDomain in adAdditionalDomains.Skip(1))
{
<hr />
<div>
<code>@adDomain.DnsName <span>[@adDomain.NetBiosName]</span></code>
<code>@adDomain.Name <span>[@adDomain.NetBiosName]</span></code>
</div>
}
}
@@ -178,18 +179,42 @@
</th>
<td>
<code><strong>@Model.ADSite.Name</strong></code>
<hr />
</td>
</tr>
<tr>
<th style="width: 135px">Servers:
</th>
<td>
<div>
@if (Model.ADSiteServers.Count > 0)
@if (Model.ADServers.Count > 0)
{
<span>Servers:</span>
<ul class="none">
@foreach (var siteServer in Model.ADSiteServers)
@foreach (var server in Model.ADServers)
{
var server = siteServer.Item1;
var reachable = siteServer.Item2;
var serverDescription = string.Format("{0} [{1}]", server.Name.EndsWith(server.Domain.Name, StringComparison.OrdinalIgnoreCase) ? server.Name.Substring(0, server.Name.Length - server.Domain.Name.Length - 1) : server.Name, server.Domain.NetBiosName);
var reachable = server.IsAvailable;
<li>
<i class="fa @(reachable ? "fa-check success" : "fa-exclamation warning") fa-fw fa-lg" title="@(reachable ? "Reachable" : "Unavailable")"></i>&nbsp;<code>@(server.Name)</code>
@if (server.IsAvailable)
{
<i class="fa fa-check success fa-fw fa-lg" title="Available"></i>
}
else
{
<i class="fa fa-exclamation warning fa-fw fa-lg" title="Unavailable, will retry at @(server.AvailableWhen.Value.ToLongTimeString())"></i>
}
<code>@(serverDescription)</code>
@if (server.IsSiteServer)
{
<i class="fa fa-building-o information fa-fw" title="Site Server"></i>
}
else
{
<i class="fa fa-globe warning fa-fw" title="Not a Site Server"></i>
}
@if (server.IsWritable)
{
<i class="fa fa-pencil information fa-fw" title="Writable Domain Controller"></i>
}
</li>
}
</ul>
@@ -210,11 +235,12 @@
@if (Model.ADForestServers == null)
{
<div>
@Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchEntireForest)
@Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchAllForestServers)
</div>
<div style="padding: 0.7em 0.7em;" class="ui-state-highlight ui-corner-all">
<i class="fa fa-info-circle information"></i>&nbsp;Forest servers are currently being retrieved.
<br />Try refreshing this page in a moment.
<br />
Try refreshing this page in a moment.
</div>
}
else
@@ -225,20 +251,20 @@
<div>
@if (!canSearchEntireForest)
{
@Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchEntireForest)
@Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchAllForestServers)
<div style="padding: 0.7em 0.7em;" class="ui-state-highlight ui-corner-all">
<i class="fa fa-exclamation-circle warning"></i>&nbsp;Disco will not search entire forests which consist of more than @(Disco.Services.Interop.ActiveDirectory.ActiveDirectory.MaxForestServerSearch) servers. Only servers within this site will be searched.
</div>
}
else
{
@Html.CheckBoxFor(m => m.ADSearchEntireForest) @Html.LabelFor(m => m.ADSearchEntireForest) @AjaxHelpers.AjaxLoader()
@Html.CheckBoxFor(m => m.ADSearchAllForestServers) @Html.LabelFor(m => m.ADSearchAllForestServers) @AjaxHelpers.AjaxLoader()
<div class="smallMessage">
If this setting is enabled, Disco will search all servers within the forest rather than only servers within this site.
If this setting is enabled, Disco will query all servers within the forest rather than only servers within this site.
</div>
<script>
$(function () {
document.DiscoFunctions.PropertyChangeHelper($('#ADSearchEntireForest'), null, '@(Url.Action(MVC.API.System.UpdateActiveDirectorySearchEntireForest()))', 'SearchEntireForest');
document.DiscoFunctions.PropertyChangeHelper($('#ADSearchAllForestServers'), null, '@(Url.Action(MVC.API.System.UpdateActiveDirectorySearchAllForestServers()))', 'SearchAllForestServers');
});
</script>
}
@@ -247,7 +273,7 @@
else
{
<div>
@Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchEntireForest)
@Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchAllForestServers)
<div class="smallMessage">
If this setting is enabled, Disco will search all servers within the forest rather than only servers within this site.
</div>
@@ -255,11 +281,25 @@
}
<div>
<hr />
<span>Servers:</span>
<ul id="Config_System_AD_ForestServers">
@foreach (var server in Model.ADForestServers.OrderBy(s => s))
<span>All Servers:</span>
<ul id="Config_System_AD_ForestServers" class="none">
@{
var domainIndex = Model.ADDomains.ToDictionary(d => d.Name, StringComparer.OrdinalIgnoreCase);
foreach (var server in Model.ADForestServers.OrderBy(s => s))
{
var isSiteServer = Model.ADServers.Any(s => s.IsSiteServer && s.Name.Equals(server, StringComparison.OrdinalIgnoreCase));
var serverDescription = server;
if (server.Contains('.'))
{
Disco.Services.Interop.ActiveDirectory.ADDomain serverDomain;
if (domainIndex.TryGetValue(server.Substring(server.IndexOf('.') + 1), out serverDomain))
{
<li><code>@server</code> @(Model.ADSiteServers.Count(ss => ss.Item1.Name.Equals(server, StringComparison.InvariantCultureIgnoreCase)) > 0 ? "[Site Server]" : null)</li>
serverDescription = string.Format("{0} [{1}]", server.Substring(0, server.IndexOf('.')), serverDomain.NetBiosName);
}
}
<li><code>@serverDescription</code>@if (isSiteServer)
{ <i class="fa fa-building-o information fa-fw" title="Site Server"></i> }</li>
}
}
</ul>
<script>
@@ -502,7 +502,7 @@ WriteLiteral(">Primary Domain:\r\n </th>\r\n <td>\r\n
#line 151 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Model.ADPrimaryDomain.DnsName);
Write(Model.ADPrimaryDomain.Name);
#line default
@@ -511,7 +511,7 @@ WriteLiteral("</strong> <span>[");
#line 151 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Model.ADPrimaryDomain.NetBiosName);
Write(Model.ADPrimaryDomain.NetBiosName);
#line default
@@ -530,9 +530,10 @@ WriteLiteral(">Additional Domains:\r\n </th>\r\n <td>\r\n"
#line hidden
#line 158 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (Model.ADAdditionalDomains.Count > 0)
if (Model.ADDomains.Count > 1)
{
var adDomainFirst = Model.ADAdditionalDomains.First();
var adAdditionalDomains = Model.ADDomains.Where(d => d != Model.ADPrimaryDomain).OrderBy(d => d.Name).ToList();
var adDomainFirst = adAdditionalDomains.First();
#line default
@@ -540,8 +541,8 @@ WriteLiteral(">Additional Domains:\r\n </th>\r\n <td>\r\n"
WriteLiteral(" <code>");
#line 161 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(adDomainFirst.DnsName);
#line 162 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(adDomainFirst.Name);
#line default
@@ -549,8 +550,8 @@ WriteLiteral(" <code>");
WriteLiteral(" <span>[");
#line 161 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(adDomainFirst.NetBiosName);
#line 162 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(adDomainFirst.NetBiosName);
#line default
@@ -558,8 +559,8 @@ WriteLiteral(" <span>[");
WriteLiteral("]</span></code>\r\n");
#line 162 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
foreach (var adDomain in Model.ADAdditionalDomains.Skip(1))
#line 163 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
foreach (var adDomain in adAdditionalDomains.Skip(1))
{
@@ -570,8 +571,8 @@ WriteLiteral(" <hr />\r\n");
WriteLiteral(" <div>\r\n <code>");
#line 166 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(adDomain.DnsName);
#line 167 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(adDomain.Name);
#line default
@@ -579,8 +580,8 @@ WriteLiteral(" <div>\r\n <code>");
WriteLiteral(" <span>[");
#line 166 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(adDomain.NetBiosName);
#line 167 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(adDomain.NetBiosName);
#line default
@@ -588,7 +589,7 @@ WriteLiteral(" <span>[");
WriteLiteral("]</span></code>\r\n </div>\r\n");
#line 168 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 169 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
}
else
@@ -604,7 +605,7 @@ WriteLiteral(" class=\"smallMessage\"");
WriteLiteral(">&lt;None&gt;</span>\r\n");
#line 173 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 174 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
@@ -617,30 +618,33 @@ WriteLiteral(" style=\"width: 135px\"");
WriteLiteral(">Site:\r\n </th>\r\n <td>\r\n <code><strong>");
#line 180 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 181 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Model.ADSite.Name);
#line default
#line hidden
WriteLiteral("</strong></code>\r\n <hr />\r\n <div>\r\n");
WriteLiteral("</strong></code>\r\n </td>\r\n </tr>\r\n <tr>\r\n <th" +
"");
WriteLiteral(" style=\"width: 135px\"");
WriteLiteral(">Servers:\r\n </th>\r\n <td>\r\n <div>\r\n");
#line 183 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 189 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 183 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (Model.ADSiteServers.Count > 0)
#line 189 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (Model.ADServers.Count > 0)
{
#line default
#line hidden
WriteLiteral(" <span>Servers:</span>\r\n");
WriteLiteral(" <ul");
WriteLiteral(" class=\"none\"");
@@ -648,59 +652,167 @@ WriteLiteral(" class=\"none\"");
WriteLiteral(">\r\n");
#line 187 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 187 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
foreach (var siteServer in Model.ADSiteServers)
#line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
foreach (var server in Model.ADServers)
{
var server = siteServer.Item1;
var reachable = siteServer.Item2;
var serverDescription = string.Format("{0} [{1}]", server.Name.EndsWith(server.Domain.Name, StringComparison.OrdinalIgnoreCase) ? server.Name.Substring(0, server.Name.Length - server.Domain.Name.Length - 1) : server.Name, server.Domain.NetBiosName);
var reachable = server.IsAvailable;
#line default
#line hidden
WriteLiteral(" <li>\r\n <i");
WriteLiteral(" <li>\r\n");
WriteAttribute("class", Tuple.Create(" class=\"", 7471), Tuple.Create("\"", 7554)
, Tuple.Create(Tuple.Create("", 7479), Tuple.Create("fa", 7479), true)
#line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
, Tuple.Create(Tuple.Create(" ", 7481), Tuple.Create<System.Object, System.Int32>(reachable ? "fa-check success" : "fa-exclamation warning"
#line 197 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
, 7482), false)
, Tuple.Create(Tuple.Create(" ", 7542), Tuple.Create("fa-fw", 7543), true)
, Tuple.Create(Tuple.Create(" ", 7548), Tuple.Create("fa-lg", 7549), true)
#line 197 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (server.IsAvailable)
{
#line default
#line hidden
WriteLiteral(" <i");
WriteLiteral(" class=\"fa fa-check success fa-fw fa-lg\"");
WriteLiteral(" title=\"Available\"");
WriteLiteral("></i>\r\n");
#line 200 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
else
{
#line default
#line hidden
WriteLiteral(" <i");
WriteLiteral(" class=\"fa fa-exclamation warning fa-fw fa-lg\"");
WriteAttribute("title", Tuple.Create(" title=\"", 8221), Tuple.Create("\"", 8304)
, Tuple.Create(Tuple.Create("", 8229), Tuple.Create("Unavailable,", 8229), true)
, Tuple.Create(Tuple.Create(" ", 8241), Tuple.Create("will", 8242), true)
, Tuple.Create(Tuple.Create(" ", 8246), Tuple.Create("retry", 8247), true)
, Tuple.Create(Tuple.Create(" ", 8252), Tuple.Create("at", 8253), true)
#line 203 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
, Tuple.Create(Tuple.Create(" ", 8255), Tuple.Create<System.Object, System.Int32>(server.AvailableWhen.Value.ToLongTimeString()
#line default
#line hidden
, 8256), false)
);
WriteAttribute("title", Tuple.Create(" title=\"", 7555), Tuple.Create("\"", 7605)
#line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
, Tuple.Create(Tuple.Create("", 7563), Tuple.Create<System.Object, System.Int32>(reachable ? "Reachable" : "Unavailable"
#line default
#line hidden
, 7563), false)
);
WriteLiteral("></i>&nbsp;<code>");
WriteLiteral("></i>\r\n");
#line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(server.Name);
#line 204 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
#line default
#line hidden
WriteLiteral("</code>\r\n </li>\r\n");
WriteLiteral(" <code>");
#line 194 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 205 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(serverDescription);
#line default
#line hidden
WriteLiteral("</code>\r\n");
#line 206 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 206 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (server.IsSiteServer)
{
#line default
#line hidden
WriteLiteral(" <i");
WriteLiteral(" class=\"fa fa-building-o information fa-fw\"");
WriteLiteral(" title=\"Site Server\"");
WriteLiteral("></i>\r\n");
#line 209 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
else
{
#line default
#line hidden
WriteLiteral(" <i");
WriteLiteral(" class=\"fa fa-globe warning fa-fw\"");
WriteLiteral(" title=\"Not a Site Server\"");
WriteLiteral("></i>\r\n");
#line 213 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
#line default
#line hidden
WriteLiteral(" ");
#line 214 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (server.IsWritable)
{
#line default
#line hidden
WriteLiteral(" <i");
WriteLiteral(" class=\"fa fa-pencil information fa-fw\"");
WriteLiteral(" title=\"Writable Domain Controller\"");
WriteLiteral("></i>\r\n");
#line 217 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
#line default
#line hidden
WriteLiteral(" </li>\r\n");
#line 219 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
@@ -709,7 +821,7 @@ WriteLiteral("</code>\r\n </li>\r\n");
WriteLiteral(" </ul>\r\n");
#line 196 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 221 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
else
{
@@ -728,7 +840,7 @@ WriteLiteral(" class=\"fa fa-exclamation-circle fa-lg\"");
WriteLiteral("></i>&nbsp;<span>None Found</span>\r\n </div>\r\n");
#line 202 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 227 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
@@ -742,13 +854,13 @@ WriteLiteral(" style=\"width: 135px\"");
WriteLiteral(">Forest:\r\n </th>\r\n <td>\r\n");
#line 210 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 210 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (Model.ADForestServers == null)
{
@@ -760,8 +872,8 @@ WriteLiteral(" <div>\r\n");
WriteLiteral(" ");
#line 213 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }));
#line 238 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }));
#line default
@@ -769,8 +881,8 @@ WriteLiteral(" ");
WriteLiteral(" ");
#line 213 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.LabelFor(m => m.ADSearchEntireForest));
#line 238 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.LabelFor(m => m.ADSearchAllForestServers));
#line default
@@ -788,10 +900,11 @@ WriteLiteral(">\r\n <i");
WriteLiteral(" class=\"fa fa-info-circle information\"");
WriteLiteral("></i>&nbsp;Forest servers are currently being retrieved.\r\n " +
" <br />Try refreshing this page in a moment.\r\n </div>\r\n");
" <br />\r\n Try refreshing this page in a moment.\r\n " +
" </div>\r\n");
#line 219 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 245 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
else
{
@@ -805,13 +918,13 @@ WriteLiteral("></i>&nbsp;Forest servers are currently being retrieved.\r\n
WriteLiteral(" <div>\r\n");
#line 226 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 252 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 226 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 252 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (!canSearchEntireForest)
{
@@ -819,28 +932,28 @@ WriteLiteral(" <div>\r\n");
#line default
#line hidden
#line 228 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }));
#line 254 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }));
#line default
#line hidden
#line 228 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 254 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 228 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.LabelFor(m => m.ADSearchEntireForest));
#line 254 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.LabelFor(m => m.ADSearchAllForestServers));
#line default
#line hidden
#line 228 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 254 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
@@ -858,7 +971,7 @@ WriteLiteral(" class=\"fa fa-exclamation-circle warning\"");
WriteLiteral("></i>&nbsp;Disco will not search entire forests which consist of more than ");
#line 230 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 256 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Disco.Services.Interop.ActiveDirectory.ActiveDirectory.MaxForestServerSearch);
@@ -868,7 +981,7 @@ WriteLiteral(" servers. Only servers within this site will be searched.\r\n
" </div>\r\n");
#line 232 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 258 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
else
{
@@ -877,41 +990,41 @@ WriteLiteral(" servers. Only servers within this site will be searched.\r\n
#line default
#line hidden
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.CheckBoxFor(m => m.ADSearchEntireForest));
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.CheckBoxFor(m => m.ADSearchAllForestServers));
#line default
#line hidden
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.LabelFor(m => m.ADSearchEntireForest));
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.LabelFor(m => m.ADSearchAllForestServers));
#line default
#line hidden
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(AjaxHelpers.AjaxLoader());
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(AjaxHelpers.AjaxLoader());
#line default
#line hidden
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
@@ -920,26 +1033,26 @@ WriteLiteral(" <div");
WriteLiteral(" class=\"smallMessage\"");
WriteLiteral(">\r\n If this setting is enabled, Disco will search " +
"all servers within the forest rather than only servers within this site.\r\n " +
" </div>\r\n");
WriteLiteral(">\r\n If this setting is enabled, Disco will query a" +
"ll servers within the forest rather than only servers within this site.\r\n " +
" </div>\r\n");
WriteLiteral(" <script>\r\n $(function " +
"() {\r\n document.DiscoFunctions.PropertyChange" +
"Helper($(\'#ADSearchEntireForest\'), null, \'");
"Helper($(\'#ADSearchAllForestServers\'), null, \'");
#line 241 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Url.Action(MVC.API.System.UpdateActiveDirectorySearchEntireForest()));
#line 267 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Url.Action(MVC.API.System.UpdateActiveDirectorySearchAllForestServers()));
#line default
#line hidden
WriteLiteral("\', \'SearchEntireForest\');\r\n });\r\n " +
" </script>\r\n");
WriteLiteral("\', \'SearchAllForestServers\');\r\n });\r\n " +
" </script>\r\n");
#line 244 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 270 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
@@ -948,7 +1061,7 @@ WriteLiteral("\', \'SearchEntireForest\');\r\n })
WriteLiteral(" </div>\r\n");
#line 246 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 272 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
else
{
@@ -961,8 +1074,8 @@ WriteLiteral(" <div>\r\n");
WriteLiteral(" ");
#line 250 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }));
#line 276 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }));
#line default
@@ -970,8 +1083,8 @@ WriteLiteral(" ");
WriteLiteral(" ");
#line 250 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.LabelFor(m => m.ADSearchEntireForest));
#line 276 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.LabelFor(m => m.ADSearchAllForestServers));
#line default
@@ -985,29 +1098,43 @@ WriteLiteral(">\r\n If this setting is enabled, Disco
" </div>\r\n </div>\r\n");
#line 255 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 281 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
#line default
#line hidden
WriteLiteral(" <div>\r\n <hr />\r\n " +
" <span>Servers:</span>\r\n <ul");
" <span>All Servers:</span>\r\n <ul");
WriteLiteral(" id=\"Config_System_AD_ForestServers\"");
WriteLiteral(" class=\"none\"");
WriteLiteral(">\r\n");
#line 260 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 286 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 260 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
foreach (var server in Model.ADForestServers.OrderBy(s => s))
#line 286 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
var domainIndex = Model.ADDomains.ToDictionary(d => d.Name, StringComparer.OrdinalIgnoreCase);
foreach (var server in Model.ADForestServers.OrderBy(s => s))
{
var isSiteServer = Model.ADServers.Any(s => s.IsSiteServer && s.Name.Equals(server, StringComparison.OrdinalIgnoreCase));
var serverDescription = server;
if (server.Contains('.'))
{
Disco.Services.Interop.ActiveDirectory.ADDomain serverDomain;
if (domainIndex.TryGetValue(server.Substring(server.IndexOf('.') + 1), out serverDomain))
{
serverDescription = string.Format("{0} [{1}]", server.Substring(0, server.IndexOf('.')), serverDomain.NetBiosName);
}
}
#line default
@@ -1015,31 +1142,46 @@ WriteLiteral(">\r\n");
WriteLiteral(" <li><code>");
#line 262 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(server);
#line 300 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(serverDescription);
#line default
#line hidden
WriteLiteral("</code> ");
WriteLiteral("</code>");
#line 262 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Model.ADSiteServers.Count(ss => ss.Item1.Name.Equals(server, StringComparison.InvariantCultureIgnoreCase)) > 0 ? "[Site Server]" : null);
#line 300 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (isSiteServer)
{
#line default
#line hidden
WriteLiteral(" <i");
WriteLiteral(" class=\"fa fa-building-o information fa-fw\"");
WriteLiteral(" title=\"Site Server\"");
WriteLiteral("></i> ");
#line 301 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
#line default
#line hidden
WriteLiteral("</li>\r\n");
#line 263 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
#line 302 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
#line default
#line hidden
WriteLiteral(@" </ul>
WriteLiteral(@"
</ul>
<script>
$(function () {
var toManyServers = 5;
@@ -1066,7 +1208,7 @@ WriteLiteral(@" </ul>
");
#line 288 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 328 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
@@ -1079,13 +1221,13 @@ WriteLiteral(" style=\"width: 135px\"");
WriteLiteral(">Search Scope:\r\n </th>\r\n <td>\r\n");
#line 295 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 335 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 295 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 335 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (Model.ADSearchContainers != null && Model.ADSearchContainers.Count > 0)
{
@@ -1102,13 +1244,13 @@ WriteLiteral(" id=\"Config_System_AD_SearchScope_DistinguishedNames\"");
WriteLiteral(">\r\n");
#line 299 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 339 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 299 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 339 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
foreach (var adContainer in Model.ADSearchContainers)
{
@@ -1120,7 +1262,7 @@ WriteLiteral(" <li");
WriteLiteral(" data-distinguishedname=\"");
#line 301 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 341 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(adContainer.Item1);
@@ -1131,7 +1273,7 @@ WriteLiteral("\"");
WriteLiteral("><code>");
#line 301 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 341 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(adContainer.Item3);
@@ -1140,7 +1282,7 @@ WriteLiteral("><code>");
WriteLiteral("</code></li>\r\n");
#line 302 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 342 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
@@ -1149,7 +1291,7 @@ WriteLiteral("</code></li>\r\n");
WriteLiteral(" </ul>\r\n");
#line 304 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 344 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
else
{
@@ -1167,7 +1309,7 @@ WriteLiteral(">When searching, the entire domain will be queried. This is suitab
"gle-domain deployments.</div>\r\n");
#line 309 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 349 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
@@ -1176,7 +1318,7 @@ WriteLiteral(">When searching, the entire domain will be queried. This is suitab
WriteLiteral(" ");
#line 310 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 350 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (canConfigAD)
{
@@ -1211,7 +1353,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 318 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 358 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(AjaxHelpers.AjaxLoader());
@@ -1227,13 +1369,13 @@ WriteLiteral(" class=\"organisationalUnitTree\"");
WriteLiteral(">\r\n </div>\r\n");
#line 322 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 362 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line default
#line hidden
#line 322 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 362 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
using (Html.BeginForm(MVC.API.System.UpdateActiveDirectorySearchScope(null, redirect: true)))
{
}
@@ -1280,7 +1422,7 @@ WriteLiteral(" <script>\r\n $(function
"\');\r\n\r\n $.getJSON(\'");
#line 376 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 416 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Url.Action(MVC.API.System.DomainOrganisationalUnits()));
@@ -1326,7 +1468,7 @@ WriteLiteral("\', null, function (data) {\r\n
"\r\n </script>\r\n");
#line 433 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 473 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
@@ -1335,7 +1477,7 @@ WriteLiteral("\', null, function (data) {\r\n
WriteLiteral(" </td>\r\n </tr>\r\n </table>\r\n</div>\r\n");
#line 438 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 478 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
if (canConfigProxy)
{
using (Html.BeginForm(MVC.API.System.UpdateProxySettings()))
@@ -1360,7 +1502,7 @@ WriteLiteral(">Address:\r\n </th>\r\n <td>\r\n");
WriteLiteral(" ");
#line 449 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 489 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.EditorFor(m => m.ProxyAddress));
@@ -1371,7 +1513,7 @@ WriteLiteral("<br />\r\n");
WriteLiteral(" ");
#line 450 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 490 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.ValidationMessageFor(m => m.ProxyAddress));
@@ -1387,7 +1529,7 @@ WriteLiteral(">Port:\r\n </th>\r\n <td>\r\n");
WriteLiteral(" ");
#line 457 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 497 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.EditorFor(m => m.ProxyPort));
@@ -1398,7 +1540,7 @@ WriteLiteral("<br />\r\n");
WriteLiteral(" ");
#line 458 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 498 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.ValidationMessageFor(m => m.ProxyPort));
@@ -1414,7 +1556,7 @@ WriteLiteral(">Username:\r\n </th>\r\n <td>\r\n");
WriteLiteral(" ");
#line 465 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 505 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.EditorFor(m => m.ProxyUsername));
@@ -1425,7 +1567,7 @@ WriteLiteral("<br />\r\n");
WriteLiteral(" ");
#line 466 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 506 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.ValidationMessageFor(m => m.ProxyUsername));
@@ -1441,7 +1583,7 @@ WriteLiteral(">Password:\r\n </th>\r\n <td>\r\n");
WriteLiteral(" ");
#line 473 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 513 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.EditorFor(m => m.ProxyPassword));
@@ -1452,7 +1594,7 @@ WriteLiteral("<br />\r\n");
WriteLiteral(" ");
#line 474 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 514 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.ValidationMessageFor(m => m.ProxyPassword));
@@ -1474,7 +1616,7 @@ WriteLiteral(" value=\"Save Proxy Settings\"");
WriteLiteral(" />\r\n </td>\r\n </tr>\r\n </table>\r\n </div>\r\n");
#line 486 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 526 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
}
else
@@ -1499,7 +1641,7 @@ WriteLiteral(">Address:\r\n </th>\r\n <td>\r\n");
WriteLiteral(" ");
#line 497 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 537 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.DisplayFor(m => m.ProxyAddress));
@@ -1515,7 +1657,7 @@ WriteLiteral(">Port:\r\n </th>\r\n <td>\r\n");
WriteLiteral(" ");
#line 504 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 544 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.DisplayFor(m => m.ProxyPort));
@@ -1531,7 +1673,7 @@ WriteLiteral(">Username:\r\n </th>\r\n <td>\r\n");
WriteLiteral(" ");
#line 511 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 551 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.DisplayFor(m => m.ProxyUsername));
@@ -1546,7 +1688,7 @@ WriteLiteral(">Password:\r\n </th>\r\n <td>*******
"</td>\r\n </tr>\r\n </table>\r\n </div>\r\n");
#line 522 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 562 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
}
@@ -1561,7 +1703,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 524 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
#line 564 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
Write(Html.ActionLinkButton("Update Device Last Network Logons", MVC.API.System.UpdateLastNetworkLogonDates()));
@@ -22,7 +22,7 @@ namespace Disco.Web.ClientSource.Style.Images.AttachmentTypes
}
// Generic 'image' icon
if (MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase))
if (MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
return Links.ClientSource.Style.Images.AttachmentTypes.image_png;
// All other Attachments
@@ -12,8 +12,8 @@ using System.Management;
using System.Web;
using Disco.Services.Users;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Authorization;
using Disco.Web.Areas.API.Models.Shared;
namespace Disco.Web.Controllers
{
@@ -255,9 +255,9 @@ namespace Disco.Web.Controllers
public virtual ActionResult Administrators()
{
var administratorSubjects = UserService.AdministratorSubjectIds
.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
.Select(subjectId => ActiveDirectory.RetrieveADObject(subjectId, Quick: true))
.Where(item => item != null)
.Select(item => Disco.Web.Areas.Config.Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
.Select(item => SubjectDescriptorModel.FromActiveDirectoryObject(item))
.OrderBy(item => item.Name).ToList();
var m = new AdministratorsModel()
@@ -269,11 +269,11 @@ namespace Disco.Web.Controllers
}
public virtual ActionResult AdministratorsSearch(string term)
{
var groupResults = ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
var userResults = ActiveDirectory.SearchUserAccounts(term).Cast<IActiveDirectoryObject>();
var groupResults = ActiveDirectory.SearchADGroups(term).Cast<IADObject>();
var userResults = ActiveDirectory.SearchADUserAccounts(term, Quick: true).Cast<IADObject>();
var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName)
.Select(r => Disco.Web.Areas.API.Models.AuthorizationRole.SubjectItem.FromActiveDirectoryObject(r)).ToList();
.Select(r => SubjectDescriptorModel.FromActiveDirectoryObject(r)).ToList();
return Json(results, JsonRequestBehavior.AllowGet);
}
@@ -282,14 +282,14 @@ namespace Disco.Web.Controllers
if (string.IsNullOrWhiteSpace(Id))
return Json(null, JsonRequestBehavior.AllowGet);
else if (!Id.Contains(@"\"))
Id = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, Id);
Id = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, Id);
var subject = ActiveDirectory.RetrieveObject(Id, Quick: true);
var subject = ActiveDirectory.RetrieveADObject(Id, Quick: true);
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
if (subject == null || !(subject is ADUserAccount || subject is ADGroup))
return Json(null, JsonRequestBehavior.AllowGet);
else
return Json(Disco.Web.Areas.API.Models.AuthorizationRole.SubjectItem.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
return Json(SubjectDescriptorModel.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
}
[HttpPost]
public virtual ActionResult Administrators(string[] Subjects)
@@ -305,14 +305,14 @@ namespace Disco.Web.Controllers
var subjects = Subjects
.Where(s => !string.IsNullOrWhiteSpace(s))
.Select(s => s.Trim())
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveADObject(s, Quick: true)))
.ToList();
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
if (invalidSubjects.Count > 0)
throw new ArgumentException(string.Format("Subjects not found: {0}", string.Join(", ", invalidSubjects)), "Subjects");
proposedSubjects = subjects.Select(s => s.Item2.NetBiosId).OrderBy(s => s).ToArray();
proposedSubjects = subjects.Select(s => s.Item2.Id).OrderBy(s => s).ToArray();
var currentSubjects = UserService.AdministratorSubjectIds;
removedSubjects = currentSubjects.Except(proposedSubjects).ToArray();
addedSubjects = proposedSubjects.Except(currentSubjects).ToArray();
+1 -1
View File
@@ -36,7 +36,7 @@ namespace Disco.Web.Controllers
throw new ArgumentNullException("id", "The User Id must be provided");
if (string.IsNullOrEmpty(Domain))
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
id = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + id;
else
id = Domain + @"\" + id;
+4 -4
View File
@@ -193,9 +193,8 @@
<Compile Include="Areas\API\Controllers\JobQueueJobController.cs" />
<Compile Include="Areas\API\Controllers\PluginController.cs" />
<Compile Include="Areas\API\Controllers\SearchController.cs" />
<Compile Include="Areas\API\Models\AuthorizationRole\SubjectItem.cs" />
<Compile Include="Areas\API\Models\JobQueue\SubjectItem.cs" />
<Compile Include="Areas\API\Models\Job\DeviceHeldLocationModel.cs" />
<Compile Include="Areas\API\Models\Shared\SubjectDescriptorModel.cs" />
<Compile Include="Areas\API\Models\System\DomainOrganisationalUnitsModel.cs" />
<Compile Include="Areas\Config\Controllers\AuthorizationRoleController.cs" />
<Compile Include="Areas\Config\Controllers\JobPreferencesController.cs" />
@@ -203,7 +202,6 @@
<Compile Include="Areas\Config\Models\AuthorizationRole\CreateModel.cs" />
<Compile Include="Areas\Config\Models\AuthorizationRole\IndexModel.cs" />
<Compile Include="Areas\Config\Models\AuthorizationRole\ShowModel.cs" />
<Compile Include="Areas\Config\Models\AuthorizationRole\SubjectDescriptorModel.cs" />
<Compile Include="Areas\Config\Models\Config\IndexModel.cs" />
<Compile Include="Areas\Config\Models\DeviceBatch\CreateModel.cs" />
<Compile Include="Areas\Config\Models\DeviceBatch\TimelineModel.cs" />
@@ -1998,6 +1996,8 @@
<None Include="_bin_deployableAssemblies\x86\Microsoft.VC90.CRT\Microsoft.VC90.CRT.manifest" />
</ItemGroup>
<ItemGroup>
<Folder Include="Areas\API\Models\AuthorizationRole\" />
<Folder Include="Areas\API\Models\JobQueue\" />
<Folder Include="Areas\API\Models\Search\" />
<Folder Include="Areas\API\Models\WirelessCertificate\" />
<Folder Include="Areas\Services\Models\" />
@@ -2053,7 +2053,7 @@
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
<UserProperties BuildVersion_StartDate="2011/7/1" BuildVersion_BuildAction="Both" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildAction="Both" BuildVersion_StartDate="2011/7/1" />
</VisualStudio>
</ProjectExtensions>
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
+1 -1
View File
@@ -18,7 +18,7 @@ namespace Disco.Web.Controllers
throw new ArgumentException("The User Id is not in the correct format ({Domain}\\{Id})", "id");
string userDomain;
if (splitId.Item1.Equals(ActiveDirectory.PrimaryDomain.NetBiosName, StringComparison.InvariantCultureIgnoreCase))
if (splitId.Item1.Equals(ActiveDirectory.Context.PrimaryDomain.NetBiosName, StringComparison.OrdinalIgnoreCase))
userDomain = null; // Url doesn't contain Domain if it is the default.
else
userDomain = splitId.Item1;
@@ -1,4 +1,5 @@
using Disco.Web.Areas.Config.Models.AuthorizationRole;
using Disco.Web.Areas.API.Models.Shared;
using Disco.Web.Areas.Config.Models.AuthorizationRole;
using System.Collections.Generic;
namespace Disco.Web.Models.InitialConfig
@@ -55,9 +55,9 @@ namespace Disco.Web.Models.InitialConfig
{
DataSource = this.Server,
InitialCatalog = this.DatabaseName,
IntegratedSecurity = (this.AuthMethod.Equals("SSPI", StringComparison.InvariantCultureIgnoreCase)),
UserID = (this.AuthMethod.Equals("SQL", StringComparison.InvariantCultureIgnoreCase)) ? this.Auth_SQL_Username : string.Empty,
Password = (this.AuthMethod.Equals("SQL", StringComparison.InvariantCultureIgnoreCase)) ? this.Auth_SQL_Password : string.Empty,
IntegratedSecurity = (this.AuthMethod.Equals("SSPI", StringComparison.OrdinalIgnoreCase)),
UserID = (this.AuthMethod.Equals("SQL", StringComparison.OrdinalIgnoreCase)) ? this.Auth_SQL_Username : string.Empty,
Password = (this.AuthMethod.Equals("SQL", StringComparison.OrdinalIgnoreCase)) ? this.Auth_SQL_Password : string.Empty,
ApplicationName = "Disco WebApp",
MultipleActiveResultSets = true,
Pooling = true
@@ -97,7 +97,7 @@ namespace Disco.Web.Models.InitialConfig
{
var instance = validationContext.ObjectInstance as DatabaseModel;
if (instance != null && instance.AuthMethod != null && instance.AuthMethod.Equals("SQL", StringComparison.InvariantCultureIgnoreCase))
if (instance != null && instance.AuthMethod != null && instance.AuthMethod.Equals("SQL", StringComparison.OrdinalIgnoreCase))
{
var stringValue = value as string;
if (string.IsNullOrWhiteSpace(stringValue))
+65 -117
View File
@@ -2386,18 +2386,6 @@ namespace Disco.Web.Areas.API.Controllers
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateAdministratorSubjects);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult SearchSubjects()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult Subject()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public AuthorizationRoleController Actions { get { return MVC.API.AuthorizationRole; } }
@@ -2420,8 +2408,6 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string UpdateSubjects = "UpdateSubjects";
public readonly string Delete = "Delete";
public readonly string UpdateAdministratorSubjects = "UpdateAdministratorSubjects";
public readonly string SearchSubjects = "SearchSubjects";
public readonly string Subject = "Subject";
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
@@ -2433,8 +2419,6 @@ namespace Disco.Web.Areas.API.Controllers
public const string UpdateSubjects = "UpdateSubjects";
public const string Delete = "Delete";
public const string UpdateAdministratorSubjects = "UpdateAdministratorSubjects";
public const string SearchSubjects = "SearchSubjects";
public const string Subject = "Subject";
}
@@ -2497,22 +2481,6 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string Subjects = "Subjects";
public readonly string redirect = "redirect";
}
static readonly ActionParamsClass_SearchSubjects s_params_SearchSubjects = new ActionParamsClass_SearchSubjects();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_SearchSubjects SearchSubjectsParams { get { return s_params_SearchSubjects; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_SearchSubjects
{
public readonly string term = "term";
}
static readonly ActionParamsClass_Subject s_params_Subject = new ActionParamsClass_Subject();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_Subject SubjectParams { get { return s_params_Subject; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_Subject
{
public readonly string Id = "Id";
}
static readonly ViewsClass s_views = new ViewsClass();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ViewsClass Views { get { return s_views; } }
@@ -2603,26 +2571,6 @@ namespace Disco.Web.Areas.API.Controllers
return callInfo;
}
partial void SearchSubjectsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string term);
public override System.Web.Mvc.ActionResult SearchSubjects(string term)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "term", term);
SearchSubjectsOverride(callInfo, term);
return callInfo;
}
partial void SubjectOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id);
public override System.Web.Mvc.ActionResult Subject(string Id)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
SubjectOverride(callInfo, Id);
return callInfo;
}
}
}
@@ -8079,18 +8027,6 @@ namespace Disco.Web.Areas.API.Controllers
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Delete);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult SearchSubjects()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult Subject()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public JobQueueController Actions { get { return MVC.API.JobQueue; } }
@@ -8118,8 +8054,6 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string UpdateSubjects = "UpdateSubjects";
public readonly string UpdateJobSubTypes = "UpdateJobSubTypes";
public readonly string Delete = "Delete";
public readonly string SearchSubjects = "SearchSubjects";
public readonly string Subject = "Subject";
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
@@ -8136,8 +8070,6 @@ namespace Disco.Web.Areas.API.Controllers
public const string UpdateSubjects = "UpdateSubjects";
public const string UpdateJobSubTypes = "UpdateJobSubTypes";
public const string Delete = "Delete";
public const string SearchSubjects = "SearchSubjects";
public const string Subject = "Subject";
}
@@ -8252,22 +8184,6 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string id = "id";
public readonly string redirect = "redirect";
}
static readonly ActionParamsClass_SearchSubjects s_params_SearchSubjects = new ActionParamsClass_SearchSubjects();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_SearchSubjects SearchSubjectsParams { get { return s_params_SearchSubjects; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_SearchSubjects
{
public readonly string term = "term";
}
static readonly ActionParamsClass_Subject s_params_Subject = new ActionParamsClass_Subject();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_Subject SubjectParams { get { return s_params_Subject; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_Subject
{
public readonly string Id = "Id";
}
static readonly ViewsClass s_views = new ViewsClass();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ViewsClass Views { get { return s_views; } }
@@ -8420,26 +8336,6 @@ namespace Disco.Web.Areas.API.Controllers
return callInfo;
}
partial void SearchSubjectsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string term);
public override System.Web.Mvc.ActionResult SearchSubjects(string term)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "term", term);
SearchSubjectsOverride(callInfo, term);
return callInfo;
}
partial void SubjectOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id);
public override System.Web.Mvc.ActionResult Subject(string Id)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
SubjectOverride(callInfo, Id);
return callInfo;
}
}
}
@@ -9293,9 +9189,21 @@ namespace Disco.Web.Areas.API.Controllers
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult UpdateActiveDirectorySearchEntireForest()
public virtual System.Web.Mvc.ActionResult UpdateActiveDirectorySearchAllForestServers()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchEntireForest);
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchAllForestServers);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult SearchSubjects()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult Subject()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
@@ -9328,8 +9236,10 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string DeleteOrganisationAddress = "DeleteOrganisationAddress";
public readonly string UpdateMultiSiteMode = "UpdateMultiSiteMode";
public readonly string UpdateActiveDirectorySearchScope = "UpdateActiveDirectorySearchScope";
public readonly string UpdateActiveDirectorySearchEntireForest = "UpdateActiveDirectorySearchEntireForest";
public readonly string UpdateActiveDirectorySearchAllForestServers = "UpdateActiveDirectorySearchAllForestServers";
public readonly string DomainOrganisationalUnits = "DomainOrganisationalUnits";
public readonly string SearchSubjects = "SearchSubjects";
public readonly string Subject = "Subject";
public readonly string UpdateProxySettings = "UpdateProxySettings";
}
@@ -9345,8 +9255,10 @@ namespace Disco.Web.Areas.API.Controllers
public const string DeleteOrganisationAddress = "DeleteOrganisationAddress";
public const string UpdateMultiSiteMode = "UpdateMultiSiteMode";
public const string UpdateActiveDirectorySearchScope = "UpdateActiveDirectorySearchScope";
public const string UpdateActiveDirectorySearchEntireForest = "UpdateActiveDirectorySearchEntireForest";
public const string UpdateActiveDirectorySearchAllForestServers = "UpdateActiveDirectorySearchAllForestServers";
public const string DomainOrganisationalUnits = "DomainOrganisationalUnits";
public const string SearchSubjects = "SearchSubjects";
public const string Subject = "Subject";
public const string UpdateProxySettings = "UpdateProxySettings";
}
@@ -9409,15 +9321,31 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string Containers = "Containers";
public readonly string redirect = "redirect";
}
static readonly ActionParamsClass_UpdateActiveDirectorySearchEntireForest s_params_UpdateActiveDirectorySearchEntireForest = new ActionParamsClass_UpdateActiveDirectorySearchEntireForest();
static readonly ActionParamsClass_UpdateActiveDirectorySearchAllForestServers s_params_UpdateActiveDirectorySearchAllForestServers = new ActionParamsClass_UpdateActiveDirectorySearchAllForestServers();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_UpdateActiveDirectorySearchEntireForest UpdateActiveDirectorySearchEntireForestParams { get { return s_params_UpdateActiveDirectorySearchEntireForest; } }
public ActionParamsClass_UpdateActiveDirectorySearchAllForestServers UpdateActiveDirectorySearchAllForestServersParams { get { return s_params_UpdateActiveDirectorySearchAllForestServers; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_UpdateActiveDirectorySearchEntireForest
public class ActionParamsClass_UpdateActiveDirectorySearchAllForestServers
{
public readonly string SearchEntireForest = "SearchEntireForest";
public readonly string SearchAllForestServers = "SearchAllForestServers";
public readonly string redirect = "redirect";
}
static readonly ActionParamsClass_SearchSubjects s_params_SearchSubjects = new ActionParamsClass_SearchSubjects();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_SearchSubjects SearchSubjectsParams { get { return s_params_SearchSubjects; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_SearchSubjects
{
public readonly string term = "term";
}
static readonly ActionParamsClass_Subject s_params_Subject = new ActionParamsClass_Subject();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_Subject SubjectParams { get { return s_params_Subject; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_Subject
{
public readonly string Id = "Id";
}
static readonly ActionParamsClass_UpdateProxySettings s_params_UpdateProxySettings = new ActionParamsClass_UpdateProxySettings();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_UpdateProxySettings UpdateProxySettingsParams { get { return s_params_UpdateProxySettings; } }
@@ -9555,14 +9483,14 @@ namespace Disco.Web.Areas.API.Controllers
return callInfo;
}
partial void UpdateActiveDirectorySearchEntireForestOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, bool SearchEntireForest, bool redirect);
partial void UpdateActiveDirectorySearchAllForestServersOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, bool SearchAllForestServers, bool redirect);
public override System.Web.Mvc.ActionResult UpdateActiveDirectorySearchEntireForest(bool SearchEntireForest, bool redirect)
public override System.Web.Mvc.ActionResult UpdateActiveDirectorySearchAllForestServers(bool SearchAllForestServers, bool redirect)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchEntireForest);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "SearchEntireForest", SearchEntireForest);
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchAllForestServers);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "SearchAllForestServers", SearchAllForestServers);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "redirect", redirect);
UpdateActiveDirectorySearchEntireForestOverride(callInfo, SearchEntireForest, redirect);
UpdateActiveDirectorySearchAllForestServersOverride(callInfo, SearchAllForestServers, redirect);
return callInfo;
}
@@ -9575,6 +9503,26 @@ namespace Disco.Web.Areas.API.Controllers
return callInfo;
}
partial void SearchSubjectsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string term);
public override System.Web.Mvc.ActionResult SearchSubjects(string term)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "term", term);
SearchSubjectsOverride(callInfo, term);
return callInfo;
}
partial void SubjectOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id);
public override System.Web.Mvc.ActionResult Subject(string Id)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
SubjectOverride(callInfo, Id);
return callInfo;
}
partial void UpdateProxySettingsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string ProxyAddress, int? ProxyPort, string ProxyUsername, string ProxyPassword, bool redirect);
public override System.Web.Mvc.ActionResult UpdateProxySettings(string ProxyAddress, int? ProxyPort, string ProxyUsername, string ProxyPassword, bool redirect)