398 lines
19 KiB
C#
398 lines
19 KiB
C#
using Disco.Models.Interop.ActiveDirectory;
|
|
using Disco.BI.DeviceBI;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.DirectoryServices;
|
|
using System.Linq;
|
|
using System.IO;
|
|
|
|
namespace Disco.BI.Interop.ActiveDirectory
|
|
{
|
|
public static class ActiveDirectory
|
|
{
|
|
public static ActiveDirectoryMachineAccount GetMachineAccount(string ComputerName, System.Guid? UUIDNetbootGUID = null, System.Guid? MacAddressNetbootGUID = null, params string[] AdditionalProperties)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(ComputerName))
|
|
throw new System.ArgumentException("Invalid Computer Name - Empty", "ComputerName");
|
|
if (ComputerName.Contains("\\"))
|
|
ComputerName = ComputerName.Substring(checked(ComputerName.IndexOf("\\") + 1));
|
|
if (ComputerName.Length > 24)
|
|
throw new System.ArgumentException("Invalid Computer Name - Length > 24", "ComputerName");
|
|
string sAMAccountName = ComputerName;
|
|
if (!sAMAccountName.EndsWith("$"))
|
|
sAMAccountName = string.Format("{0}$", sAMAccountName);
|
|
|
|
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
|
{
|
|
var loadProperties = new List<string> { "name", "distinguishedName", "sAMAccountName", "objectSid", "dNSHostName", "netbootGUID", "isCriticalSystemObject" };
|
|
loadProperties.AddRange(AdditionalProperties);
|
|
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(sAMAccountName={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), loadProperties.ToArray(), SearchScope.Subtree))
|
|
{
|
|
SearchResult dResult = dSearcher.FindOne();
|
|
if (dResult != null)
|
|
{
|
|
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
|
}
|
|
}
|
|
|
|
if (UUIDNetbootGUID.HasValue)
|
|
{
|
|
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(netbootGUID={0}))", ActiveDirectoryHelpers.FormatGuidForLdapQuery(UUIDNetbootGUID.Value)), loadProperties.ToArray(), SearchScope.Subtree))
|
|
{
|
|
SearchResult dResult = dSearcher.FindOne();
|
|
if (dResult != null)
|
|
{
|
|
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
|
}
|
|
}
|
|
}
|
|
if (MacAddressNetbootGUID.HasValue)
|
|
{
|
|
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(netbootGUID={0}))", ActiveDirectoryHelpers.FormatGuidForLdapQuery(MacAddressNetbootGUID.Value)), loadProperties.ToArray(), SearchScope.Subtree))
|
|
{
|
|
SearchResult dResult = dSearcher.FindOne();
|
|
if (dResult != null)
|
|
{
|
|
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
}
|
|
private static ActiveDirectoryMachineAccount DirectorySearchResultToMachineAccount(SearchResult result, params string[] AdditionalProperties)
|
|
{
|
|
string name = result.Properties["name"][0].ToString();
|
|
string sAMAccountName = result.Properties["sAMAccountName"][0].ToString();
|
|
string distinguishedName = result.Properties["distinguishedName"][0].ToString();
|
|
string objectSid = ActiveDirectoryHelpers.ConvertBytesToSIDString((byte[])result.Properties["objectSid"][0]);
|
|
|
|
var dNSNameProperty = result.Properties["dNSHostName"];
|
|
string dNSName = null;
|
|
if (dNSNameProperty.Count > 0)
|
|
dNSName = dNSNameProperty[0].ToString();
|
|
else
|
|
dNSName = string.Format("{0}.{1}", sAMAccountName.TrimEnd('$'), ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
|
|
|
bool isCriticalSystemObject = (bool)result.Properties["isCriticalSystemObject"][0];
|
|
|
|
System.Guid netbootGUIDResult = default(System.Guid);
|
|
ResultPropertyValueCollection netbootGUIDProp = result.Properties["netbootGUID"];
|
|
if (netbootGUIDProp.Count > 0)
|
|
{
|
|
netbootGUIDResult = new System.Guid((byte[])netbootGUIDProp[0]);
|
|
}
|
|
|
|
// Additional Properties
|
|
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
|
foreach (string propertyName in AdditionalProperties)
|
|
{
|
|
var property = 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,
|
|
ObjectSid = objectSid,
|
|
NetbootGUID = netbootGUIDResult,
|
|
Path = result.Path,
|
|
Domain = ActiveDirectoryHelpers.DefaultDomainNetBiosName,
|
|
DnsName = dNSName,
|
|
IsCriticalSystemObject = isCriticalSystemObject,
|
|
LoadedProperties = additionalProperties
|
|
};
|
|
}
|
|
private static ActiveDirectoryUserAccount SearchResultToActiveDirectoryUserAccount(SearchResult result, params string[] AdditionalProperties)
|
|
{
|
|
string name = result.Properties["name"][0].ToString();
|
|
string username = result.Properties["sAMAccountName"][0].ToString();
|
|
string distinguishedName = result.Properties["distinguishedName"][0].ToString();
|
|
string objectSid = ActiveDirectoryHelpers.ConvertBytesToSIDString((byte[])result.Properties["objectSid"][0]);
|
|
|
|
ResultPropertyValueCollection displayNameProp = result.Properties["displayName"];
|
|
string displayName = username;
|
|
if (displayNameProp.Count > 0)
|
|
displayName = displayNameProp[0].ToString();
|
|
string surname = null;
|
|
ResultPropertyValueCollection surnameProp = result.Properties["sn"];
|
|
if (surnameProp.Count > 0)
|
|
surname = surnameProp[0].ToString();
|
|
string givenName = null;
|
|
ResultPropertyValueCollection givenNameProp = result.Properties["givenName"];
|
|
if (givenNameProp.Count > 0)
|
|
givenName = givenNameProp[0].ToString();
|
|
string email = null;
|
|
ResultPropertyValueCollection emailProp = result.Properties["mail"];
|
|
if (emailProp.Count > 0)
|
|
email = emailProp[0].ToString();
|
|
string phone = null;
|
|
ResultPropertyValueCollection phoneProp = result.Properties["telephoneNumber"];
|
|
if (phoneProp.Count > 0)
|
|
phone = phoneProp[0].ToString();
|
|
|
|
IEnumerable<string> groupCNs = result.Properties["memberOf"].Cast<string>();
|
|
List<string> groups = ActiveDirectoryCachedGroups.GetGroups(groupCNs).Select(g => g.ToLower()).ToList();
|
|
|
|
//foreach (string groupCN in result.Properties["memberOf"])
|
|
//{
|
|
// Removed 2012-11-30 G# - Moved to Recursive Cache
|
|
//var groupCNlower = groupCN.ToLower();
|
|
//if (groupCNlower.StartsWith("cn="))
|
|
// groups.Add(groupCNlower.Substring(3, groupCNlower.IndexOf(",") - 3));
|
|
// End Removed 2012-11-30 G#
|
|
//}
|
|
|
|
string type = null;
|
|
if (groups.Contains("domain admins") || groups.Contains("disco admins"))
|
|
{
|
|
type = "Admin";
|
|
}
|
|
else
|
|
{
|
|
if (groups.Contains("staff"))
|
|
{
|
|
type = "Staff";
|
|
}
|
|
else
|
|
{
|
|
if (groups.Contains("students"))
|
|
{
|
|
type = "Student";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Additional Properties
|
|
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
|
foreach (string propertyName in AdditionalProperties)
|
|
{
|
|
var property = 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 = ActiveDirectoryHelpers.DefaultDomainNetBiosName,
|
|
Name = name,
|
|
Surname = surname,
|
|
GivenName = givenName,
|
|
Email = email,
|
|
Phone = phone,
|
|
DistinguishedName = distinguishedName,
|
|
sAMAccountName = username,
|
|
DisplayName = displayName,
|
|
ObjectSid = objectSid,
|
|
Type = type,
|
|
Path = result.Path,
|
|
LoadedProperties = additionalProperties
|
|
};
|
|
}
|
|
public static ActiveDirectoryUserAccount GetUserAccount(string Username, params string[] AdditionalProperties)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(Username))
|
|
throw new System.ArgumentException("Invalid User Account", "Username");
|
|
string sAMAccountName = Username;
|
|
if (sAMAccountName.Contains("\\"))
|
|
sAMAccountName = sAMAccountName.Substring(checked(sAMAccountName.IndexOf("\\") + 1));
|
|
|
|
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
|
{
|
|
var loadProperties = new List<string> {
|
|
"name",
|
|
"distinguishedName",
|
|
"sAMAccountName",
|
|
"objectSid",
|
|
"displayName",
|
|
"sn",
|
|
"givenName",
|
|
"memberOf",
|
|
"mail",
|
|
"telephoneNumber"
|
|
};
|
|
loadProperties.AddRange(AdditionalProperties);
|
|
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=user)(sAMAccountName={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), loadProperties.ToArray(), SearchScope.Subtree))
|
|
{
|
|
SearchResult dResult = dSearcher.FindOne();
|
|
if (dResult != null)
|
|
return ActiveDirectory.SearchResultToActiveDirectoryUserAccount(dResult, AdditionalProperties);
|
|
else
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
public static string OfflineDomainJoinProvision(ref ActiveDirectoryMachineAccount ExistingAccount, string ComputerName, string OrganisationalUnit = null, string EnrolSessionId = null)
|
|
{
|
|
if (ExistingAccount != null && ExistingAccount.IsCriticalSystemObject)
|
|
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", ExistingAccount.DistinguishedName));
|
|
|
|
string DJoinResult = null;
|
|
if (string.IsNullOrWhiteSpace(ComputerName) || ComputerName.Length > 24)
|
|
throw new System.ArgumentException("Invalid Computer Name; > 0 and <= 24", "ComputerName");
|
|
|
|
// Added 2012-10-25 G#
|
|
// Ensure Specified OU Exists
|
|
if (!string.IsNullOrEmpty(OrganisationalUnit))
|
|
{
|
|
var ouPath = string.Format("{0}{1},{2}", ActiveDirectoryHelpers.DefaultLdapPath, OrganisationalUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
|
try
|
|
{
|
|
using (DirectoryEntry ou = new DirectoryEntry(ouPath))
|
|
{
|
|
if (ou == null)
|
|
{
|
|
throw new Exception("OU's Directory Entry couldn't be found");
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new ArgumentException(string.Format("An error occurred while trying to locate the specified OU: {0}", ouPath), "OrganisationalUnit", ex);
|
|
}
|
|
}
|
|
// End Added 2012-10-25 G#
|
|
|
|
// Delete Existing
|
|
if (ExistingAccount != null)
|
|
ExistingAccount.DeleteAccount();
|
|
|
|
string tempFileName = System.IO.Path.GetTempFileName();
|
|
string argumentOU = (!string.IsNullOrWhiteSpace(OrganisationalUnit)) ? string.Format(" /MACHINEOU \"{0},{1}\"", OrganisationalUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName) : string.Empty;
|
|
string arguments = string.Format("/PROVISION /DOMAIN \"{0}\" /DCNAME \"{1}\" /MACHINE \"{2}\"{3} /REUSE /SAVEFILE \"{4}\"",
|
|
ActiveDirectoryHelpers.DefaultDomainName,
|
|
ActiveDirectoryHelpers.DefaultDomainPDCName,
|
|
ComputerName,
|
|
argumentOU,
|
|
tempFileName
|
|
);
|
|
ProcessStartInfo commandStarter = new ProcessStartInfo("DJOIN.EXE", arguments)
|
|
{
|
|
CreateNoWindow = true,
|
|
ErrorDialog = false,
|
|
LoadUserProfile = false,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
UseShellExecute = false
|
|
};
|
|
if (EnrolSessionId != null)
|
|
{
|
|
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, string.Format("{0} {1}{2}", "DJOIN.EXE", arguments, System.Environment.NewLine));
|
|
}
|
|
|
|
string stdOutput;
|
|
string stdError;
|
|
using (Process commandProc = Process.Start(commandStarter))
|
|
{
|
|
commandProc.WaitForExit(20000);
|
|
stdOutput = commandProc.StandardOutput.ReadToEnd();
|
|
stdError = commandProc.StandardError.ReadToEnd();
|
|
}
|
|
if (EnrolSessionId != null)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(stdOutput))
|
|
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, stdOutput + System.Environment.NewLine);
|
|
if (!string.IsNullOrWhiteSpace(stdError))
|
|
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, stdError + System.Environment.NewLine);
|
|
}
|
|
|
|
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));
|
|
ExistingAccount = ActiveDirectory.GetMachineAccount(ComputerName);
|
|
return DJoinResult;
|
|
}
|
|
|
|
public static List<ActiveDirectoryUserAccount> SearchUsers(string term)
|
|
{
|
|
List<ActiveDirectoryUserAccount> users = new List<ActiveDirectoryUserAccount>();
|
|
string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName;
|
|
string defaultNetBiosDomainName = ActiveDirectoryHelpers.DefaultDomainNetBiosName;
|
|
term = ActiveDirectoryHelpers.EscapeLdapQuery(term);
|
|
using (DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", defaultQualifiedDomainName)))
|
|
{
|
|
using (DirectorySearcher searcher = new DirectorySearcher(entry, string.Format("(&(objectClass=User)(objectCategory=Person)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))", term), new string[]
|
|
{
|
|
"name",
|
|
"distinguishedName",
|
|
"sAMAccountName",
|
|
"objectSid",
|
|
"displayName",
|
|
"sn",
|
|
"givenName",
|
|
"memberOf",
|
|
"mail",
|
|
"telephoneNumber"
|
|
}, SearchScope.Subtree))
|
|
{
|
|
searcher.SizeLimit = 30;
|
|
SearchResultCollection results = searcher.FindAll();
|
|
foreach (SearchResult result in results)
|
|
{
|
|
users.Add(ActiveDirectory.SearchResultToActiveDirectoryUserAccount(result));
|
|
}
|
|
}
|
|
}
|
|
return users;
|
|
}
|
|
public static List<ActiveDirectoryOrganisationalUnit> GetOrganisationalUnitStructure()
|
|
{
|
|
ActiveDirectoryOrganisationalUnit DomainOUs = new ActiveDirectoryOrganisationalUnit
|
|
{
|
|
Children = new System.Collections.Generic.List<ActiveDirectoryOrganisationalUnit>()
|
|
};
|
|
string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName;
|
|
|
|
using (DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", defaultQualifiedDomainName)))
|
|
{
|
|
ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref DomainOUs, entry);
|
|
}
|
|
return DomainOUs.Children;
|
|
}
|
|
private static void GetOrganisationalUnitStructure_Recursive(ref ActiveDirectoryOrganisationalUnit ParentOU, DirectoryEntry Container)
|
|
{
|
|
using (DirectorySearcher searcher = new DirectorySearcher(Container, "(objectCategory=organizationalUnit)", new string[]
|
|
{
|
|
"name",
|
|
"distinguishedName"
|
|
}, SearchScope.OneLevel))
|
|
{
|
|
using (SearchResultCollection results = searcher.FindAll())
|
|
{
|
|
foreach (SearchResult result in results)
|
|
{
|
|
string i = result.Properties["name"][0].ToString();
|
|
string dn = result.Properties["distinguishedName"][0].ToString();
|
|
ActiveDirectoryOrganisationalUnit ChildOU = new ActiveDirectoryOrganisationalUnit
|
|
{
|
|
Name = i,
|
|
Path = dn.Substring(0, dn.IndexOf(",DC=")),
|
|
Children = new List<ActiveDirectoryOrganisationalUnit>()
|
|
};
|
|
ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref ChildOU, result.GetDirectoryEntry());
|
|
if (ChildOU.Children.Count == 0)
|
|
ChildOU.Children = null;
|
|
ParentOU.Children.Add(ChildOU);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|