diff --git a/ConfigMgrWebService.Release.zip b/ConfigMgrWebService.Release.zip new file mode 100644 index 0000000..75e481b Binary files /dev/null and b/ConfigMgrWebService.Release.zip differ diff --git a/ConfigMgrWebService/ADComputer.cs b/ConfigMgrWebService/ADComputer.cs index 6639004..4cabe14 100644 --- a/ConfigMgrWebService/ADComputer.cs +++ b/ConfigMgrWebService/ADComputer.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Web; +using System.DirectoryServices; namespace ConfigMgrWebService { @@ -11,5 +10,33 @@ public class ADComputer public string CanonicalName { get; set; } public string DnsHostName { get; set; } public string DistinguishedName { get; set; } + + public ADComputer() { } + + /// + /// The 2nd constructor for . Using the specified , + /// this will populate the class's properties. + /// + /// The to use when populating this class's properties. + public ADComputer(DirectoryEntry dirEntry) + { + using (dirEntry) + { + this.DistinguishedName = dirEntry.Properties[ConfigMgrWebService.DISTINGUISHED_NAME].Value as string; + this.CanonicalName = dirEntry.Properties[ConfigMgrWebService.COMMON_NAME].Value as string; + this.DnsHostName = dirEntry.Properties[ConfigMgrWebService.DNS_HOST_NAME].Value as string; + this.SamAccountName = dirEntry.Properties[ConfigMgrWebService.SAM_ACCOUNT_NAME].Value as string; + } + } + + private ADComputer(ADComputerFromDC withDC) + { + this.CanonicalName = withDC.CanonicalName; + this.SamAccountName = withDC.SamAccountName; + this.DistinguishedName = withDC.DistinguishedName; + this.DnsHostName = withDC.DnsHostName; + } + + public static explicit operator ADComputer(ADComputerFromDC compFromDC) => new ADComputer(compFromDC); } } \ No newline at end of file diff --git a/ConfigMgrWebService/ADComputerFromDC.cs b/ConfigMgrWebService/ADComputerFromDC.cs new file mode 100644 index 0000000..aae3e5a --- /dev/null +++ b/ConfigMgrWebService/ADComputerFromDC.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.DirectoryServices; + +namespace ConfigMgrWebService +{ + public class ADComputerFromDC + { + public string SamAccountName { get; set; } + public string CanonicalName { get; set; } + public string DnsHostName { get; set; } + public string DistinguishedName { get; set; } + public string RespondingDC { get; set; } + + public ADComputerFromDC() { } + + /// + /// The 2nd constructor for . Using the specified , + /// this will populate the class's properties. It also specfies the DomainController that responding with the + /// . + /// + /// The to use when populating this class's properties. + /// The responding domain controller of the . + public ADComputerFromDC(DirectoryEntry dirEntry, string dc) + { + this.RespondingDC = dc; + using (dirEntry) + { + this.DistinguishedName = dirEntry.Properties[ConfigMgrWebService.DISTINGUISHED_NAME].Value as string; + this.CanonicalName = dirEntry.Properties[ConfigMgrWebService.COMMON_NAME].Value as string; + this.DnsHostName = dirEntry.Properties[ConfigMgrWebService.DNS_HOST_NAME].Value as string; + this.SamAccountName = dirEntry.Properties[ConfigMgrWebService.SAM_ACCOUNT_NAME].Value as string; + } + } + } +} \ No newline at end of file diff --git a/ConfigMgrWebService/ADDomain.cs b/ConfigMgrWebService/ADDomain.cs index 5842075..a342b4d 100644 --- a/ConfigMgrWebService/ADDomain.cs +++ b/ConfigMgrWebService/ADDomain.cs @@ -1,13 +1,105 @@ using System; using System.Collections.Generic; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; using System.Linq; using System.Web; namespace ConfigMgrWebService { - public class ADDomain + public class ADDomain : IDisposable { + private Domain _domain; + private string _typeName => this.GetType().FullName; + private bool _isDisp; + public string DomainName { get; set; } public string DefaultNamingContext { get; set; } + public string Path { get; set; } + + public ADDomain() { } + + private ADDomain(Domain domain) + { + this.DomainName = domain.Name; + using (DirectoryEntry de = domain.GetDirectoryEntry()) + { + this.DefaultNamingContext = de.Properties[ConfigMgrWebService.DISTINGUISHED_NAME].Value as string; + this.Path = de.Path; + } + _domain = domain; + } + + public DomainControllerCollection GetAllDomainControllers() + { + this.CheckIfDisposed(); + return _domain.FindAllDomainControllers(); + } + + public DomainController FindDomainController() + { + this.CheckIfDisposed(); + return _domain.FindDomainController(); + } + + public bool IsDC(string computerName) + { + bool result = false; + DomainControllerCollection dcCol = this.GetAllDomainControllers(); + if (dcCol.Count <= 0) + return result; + + foreach (DomainController dc in dcCol) + { + using (dc) + { + using (DirectoryEntry dcEntry = dc.GetDirectoryEntry()) + { + if (computerName.Equals( + dcEntry.Properties[ConfigMgrWebService.NAME].Value as string, + StringComparison.CurrentCultureIgnoreCase)) + { + result = true; + break; + } + } + } + } + return result; + } + + #region IDISPOSABLE METHODS + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_isDisp) + return; + + if (disposing) + _domain.Dispose(); + + _isDisp = true; + } + + private void CheckIfDisposed() + { + if (_isDisp) + throw new ObjectDisposedException(_typeName); + } + + #endregion + + public static implicit operator ADDomain(Domain domain) => new ADDomain(domain); + + public static implicit operator Domain(ADDomain adDomain) + { + adDomain.CheckIfDisposed(); + return adDomain._domain; + } } } \ No newline at end of file diff --git a/ConfigMgrWebService/ADGroup.cs b/ConfigMgrWebService/ADGroup.cs index 524a9c2..5b5f5c9 100644 --- a/ConfigMgrWebService/ADGroup.cs +++ b/ConfigMgrWebService/ADGroup.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.DirectoryServices; using System.Linq; using System.Web; @@ -7,7 +8,27 @@ namespace ConfigMgrWebService { public class ADGroup { - public string samAccountName { get; set; } + public string SamAccountName { get; set; } public string DistinguishedName { get; set; } + public string RespondingDC { get; } + + public ADGroup() { } + + /// + /// The 2nd constructor for . Using the specified , + /// this will populate the class's properties. It also specfies the DomainController that responding with the + /// . + /// + /// The to use when populating this class's properties. + /// The responding domain controller of the . + public ADGroup(DirectoryEntry dirEntry, string dc) + { + this.RespondingDC = dc; + using (dirEntry) + { + this.SamAccountName = dirEntry.Properties["sAMAccountName"].Value as string; + this.DistinguishedName = dirEntry.Properties["distinguishedName"].Value as string; + } + } } } \ No newline at end of file diff --git a/ConfigMgrWebService/ADOperations/AddADComputerToGroupByDC.cs b/ConfigMgrWebService/ADOperations/AddADComputerToGroupByDC.cs new file mode 100644 index 0000000..7b4eee5 --- /dev/null +++ b/ConfigMgrWebService/ADOperations/AddADComputerToGroupByDC.cs @@ -0,0 +1,58 @@ +using System; +using System.Diagnostics; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; +using System.Linq; +using System.Reflection; +using System.Web; +using System.Web.Services; + +namespace ConfigMgrWebService +{ + public partial class ConfigMgrWebService + { + [WebMethod(Description = "")] + public bool AddADComputerToGroupByDC(string secret, string groupName, string computerName, string domainController) + { + var method = MethodBase.GetCurrentMethod(); + MethodBegin(method); + + //' Variable for return value + bool returnValue = false; + + //' Validate secret key + if (secret == secretKey) + { + //' Log that secret key was accepted + WriteEventLog("Secret key was accepted", EventLogEntryType.Information); + + //' Get AD object distinguished name for computer and group + string computerDistinguishedName = (GetADObject(computerName, ADObjectClass.Computer, ADObjectType.distinguishedName, domainController)).Remove(0, 7); + string groupDistinguishedName = GetADObject(groupName, ADObjectClass.Group, ADObjectType.distinguishedName, domainController); + + if (!string.IsNullOrEmpty(computerDistinguishedName) && !string.IsNullOrEmpty(groupDistinguishedName)) + { + try + { + //' Add computer to group and commit + var groupEntry = new DirectoryEntry(groupDistinguishedName); + groupEntry.Properties["member"].Add(computerDistinguishedName); + groupEntry.CommitChanges(); + + //' Dispose object + groupEntry.Dispose(); + + returnValue = true; + } + catch (Exception ex) + { + WriteEventLog(string.Format("An error occured when attempting to add a computer object in Active Directory to a group. Error message: {0}", ex.Message), EventLogEntryType.Error); + } + } + } + + MethodEnd(method); + return returnValue; + } + } +} \ No newline at end of file diff --git a/ConfigMgrWebService/ADOperations/AddADUserToGroupByDC.cs b/ConfigMgrWebService/ADOperations/AddADUserToGroupByDC.cs new file mode 100644 index 0000000..2feceaf --- /dev/null +++ b/ConfigMgrWebService/ADOperations/AddADUserToGroupByDC.cs @@ -0,0 +1,55 @@ +using System; +using System.Diagnostics; +using System.DirectoryServices; +using System.Reflection; +using System.Web.Services; + +namespace ConfigMgrWebService +{ + public partial class ConfigMgrWebService + { + [WebMethod(Description = "Add a user in Active Directory to a specific group on the specified domain controller")] + public bool AddADUserToGroupByDC(string secret, string groupName, string userName, string domainController) + { + MethodBase method = MethodBase.GetCurrentMethod(); + MethodBegin(method); + + //' Variable for return value + bool returnValue = false; + + //' Validate secret key + if (secret == secretKey) + { + //' Log that secret key was accepted + WriteEventLog("Secret key was accepted", EventLogEntryType.Information); + + //' Get AD object distinguished name for computer and group + string userDistinguishedName = (GetADObject(userName, ADObjectClass.User, ADObjectType.distinguishedName)).Remove(0, 7); + string groupDistinguishedName = GetADObject(groupName, ADObjectClass.Group, ADObjectType.distinguishedName); + + if (!String.IsNullOrEmpty(userDistinguishedName) && !String.IsNullOrEmpty(groupDistinguishedName)) + { + try + { + //' Add user to group and commit + DirectoryEntry groupEntry = new DirectoryEntry(groupDistinguishedName); + groupEntry.Properties["member"].Add(userDistinguishedName); + groupEntry.CommitChanges(); + + //' Dispose object + groupEntry.Dispose(); + + returnValue = true; + } + catch (Exception ex) + { + WriteEventLog(String.Format("An error occured when attempting to add an user object in Active Directory to a group. Error message: {0}", ex.Message), EventLogEntryType.Error); + } + } + } + + MethodEnd(method); + return returnValue; + } + } +} \ No newline at end of file diff --git a/ConfigMgrWebService/ADOperations/GetADComputerByDC.cs b/ConfigMgrWebService/ADOperations/GetADComputerByDC.cs new file mode 100644 index 0000000..9b25c8f --- /dev/null +++ b/ConfigMgrWebService/ADOperations/GetADComputerByDC.cs @@ -0,0 +1,78 @@ +using System; +using System.Diagnostics; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; +using System.Reflection; +using System.Web.Services; + +namespace ConfigMgrWebService +{ + public partial class ConfigMgrWebService + { + [WebMethod(Description = "Check if a computer object exists in Active Directory on the specified domain controller")] + public ADComputerFromDC GetADComputerByDC(string secret, string computerName, string dc) + { + var method = MethodBase.GetCurrentMethod(); + MethodBegin(method); + + //' Instatiate return value variable + ADComputerFromDC returnValue = null; + + //' Validate secret key + if (secret == secretKey) + { + //' Log that secret key was accepted + WriteEventLog("Secret key was accepted", EventLogEntryType.Information); + + //' Set empty value for search result + SearchResult searchResult = null; + DirectoryEntry directoryObject = null; + + //' Get default naming context of current domain + var domain = Domain.GetComputerDomain(); + string respondingDC = GetRespondingDomainController(domain, dc); + + //' Construct directory entry for directory searcher + + string sFilter = string.Format("(&(objectClass=computer)((sAMAccountName={0}$)))", computerName); + var directorySearcher = new DirectorySearcher(domain.GetDirectoryEntry(), sFilter, COMPUTER_PROPERTIES); + + //' Invoke directory searcher + try + { + searchResult = directorySearcher.FindOne(); + if (searchResult != null) + { + //' Get computer object from search result + directoryObject = searchResult.GetDirectoryEntry(); + + if (directoryObject != null) + { + returnValue = new ADComputerFromDC(directoryObject, respondingDC); + + // Dispose directory object + directoryObject.Dispose(); + } + } + } + catch (Exception ex) + { + WriteEventLog( + string.Format( + "An error occured when attempting to locate Active Directory object. Error message: {0}", + ex.Message + ), + EventLogEntryType.Error + ); + } + + //' Dispose objects + directorySearcher.Dispose(); + domain.Dispose(); + } + + MethodEnd(method); + return returnValue; + } + } +} \ No newline at end of file diff --git a/ConfigMgrWebService/ADOperations/GetADGroupMembersByDC.cs b/ConfigMgrWebService/ADOperations/GetADGroupMembersByDC.cs new file mode 100644 index 0000000..3dc4170 --- /dev/null +++ b/ConfigMgrWebService/ADOperations/GetADGroupMembersByDC.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.DirectoryServices; +using System.Reflection; +using System.Web.Services; + +namespace ConfigMgrWebService +{ + public partial class ConfigMgrWebService + { + [WebMethod(Description = "Get all members of an Active Directory group on the specified domain controller.")] + public List GetADGroupMembersByDC(string secret, string groupName, string domainController) + { + var method = MethodBase.GetCurrentMethod(); + MethodBegin(method); + + //' Set return value variable + var returnValue = new List(); + + //' Validate secret key + if (secret == secretKey) + { + //' Log that secret key was accepted + WriteEventLog("Secret key was accepted", EventLogEntryType.Information); + + //' Get AD group object + string groupDistinguishedName = GetADObject(groupName, ADObjectClass.Group, ADObjectType.distinguishedName, domainController); + + if (!string.IsNullOrEmpty(groupDistinguishedName)) + { + try + { + var groupEntry = new DirectoryEntry(groupDistinguishedName); + returnValue = GetADGroupMemberList(groupEntry); + } + catch (Exception ex) + { + WriteEventLog(string.Format("An error occured when retrieving Active Directory group members. Error message: {0}", ex.Message), EventLogEntryType.Error); + } + } + } + + MethodEnd(method); + return returnValue; + } + } +} \ No newline at end of file diff --git a/ConfigMgrWebService/ADOperations/GetADGroupsByUserByDC.cs b/ConfigMgrWebService/ADOperations/GetADGroupsByUserByDC.cs new file mode 100644 index 0000000..a8d54d4 --- /dev/null +++ b/ConfigMgrWebService/ADOperations/GetADGroupsByUserByDC.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; +using System.Reflection; +using System.Web.Services; + +namespace ConfigMgrWebService +{ + public partial class ConfigMgrWebService + { + [WebMethod(Description = "Get Active Directory groups for a specific user on the specified domain controller.")] + public List GetADGroupsByUserByDC(string secret, string userName, string domainController) + { + var method = MethodBase.GetCurrentMethod(); + MethodBegin(method); + + //' Set return value variable + var returnValue = new List(); + + //' Validate secret key + if (secret == secretKey) + { + //' Log that secret key was accepted + WriteEventLog("Secret key was accepted", EventLogEntryType.Information); + + try + { + //' Get AD user object + string userDistinguishedName = GetADObject(userName, ADObjectClass.User, ADObjectType.distinguishedName, domainController); + + //' Get AD groups for user distinguished name + var groupMemberships = new ArrayList(); + ArrayList groups = GetADAttributeValues("memberOf", userDistinguishedName, groupMemberships, true); + + foreach (string group in groups) + { + string attributeValue = GetADAttributeValue(group, "samAccountName"); + returnValue.Add(new ADGroup() { DistinguishedName = group, SamAccountName = attributeValue }); + } + } + catch (Exception ex) + { + WriteEventLog($"An error occurred while retrieving Active Directory group memberships for user. Error message: { ex.Message }", EventLogEntryType.Error); + } + } + + MethodEnd(method); + return returnValue; + } + } +} \ No newline at end of file diff --git a/ConfigMgrWebService/ADOperations/GetADObject.cs b/ConfigMgrWebService/ADOperations/GetADObject.cs new file mode 100644 index 0000000..457944b --- /dev/null +++ b/ConfigMgrWebService/ADOperations/GetADObject.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; + +namespace ConfigMgrWebService +{ + public partial class ConfigMgrWebService + { + private string GetADObject(string name, ADObjectClass objectClass, ADObjectType objectType, string domainController = null) + { + //' Set empty value for return object and search result + string returnValue = string.Empty; + SearchResult searchResult = null; + + string ldapFormat = string.IsNullOrEmpty(domainController) + ? "LDAP://{0}" + : "LDAP://{0}/{1}"; + + //' Get default naming context of current domain + string defaultNamingContext = GetADDefaultNamingContext(); + + string currentDomain = string.IsNullOrEmpty(domainController) + ? string.Format(ldapFormat, defaultNamingContext) + : string.Format(ldapFormat, domainController, defaultNamingContext); + + //' Construct directory entry for directory searcher + var domain = new DirectoryEntry(currentDomain); + var directorySearcher = new DirectorySearcher(domain); + directorySearcher.PropertiesToLoad.Add("distinguishedName"); + + switch (objectClass) + { + case ADObjectClass.DomainController: + directorySearcher.Filter = string.Format("(&(objectClass=computer)((dNSHostName={0})))", name); + break; + case ADObjectClass.Computer: + directorySearcher.Filter = string.Format("(&(objectClass=computer)((sAMAccountName={0}$)))", name); + break; + case ADObjectClass.Group: + directorySearcher.Filter = string.Format("(&(objectClass=group)((sAMAccountName={0})))", name); + break; + case ADObjectClass.User: + directorySearcher.Filter = string.Format("(&(objectClass=user)((sAMAccountName={0})))", name); + break; + } + + //' Invoke directory searcher + try + { + searchResult = directorySearcher.FindOne(); + } + catch (Exception ex) + { + WriteEventLog(string.Format("An error occured when attempting to locate Active Directory object. Error message: {0}", ex.Message), EventLogEntryType.Error); + return returnValue; + } + + //' Return selected object type value + if (searchResult != null) + { + DirectoryEntry directoryObject = searchResult.GetDirectoryEntry(); + + if (objectType.Equals(ADObjectType.objectGuid)) + { + returnValue = directoryObject.Guid.ToString(); + } + + if (objectType.Equals(ADObjectType.distinguishedName)) + { + returnValue = string.Format(ldapFormat, directoryObject.Properties["distinguishedName"].Value); + } + } + + //' Dispose objects + directorySearcher.Dispose(); + domain.Dispose(); + + return returnValue; + } + } +} \ No newline at end of file diff --git a/ConfigMgrWebService/ADOperations/RemoveADComputerByDC.cs b/ConfigMgrWebService/ADOperations/RemoveADComputerByDC.cs new file mode 100644 index 0000000..56c0153 --- /dev/null +++ b/ConfigMgrWebService/ADOperations/RemoveADComputerByDC.cs @@ -0,0 +1,79 @@ +using System; +using System.Diagnostics; +using System.DirectoryServices; +using System.DirectoryServices.AccountManagement; +using System.DirectoryServices.ActiveDirectory; +using System.Reflection; +using System.Web.Services; + +namespace ConfigMgrWebService +{ + public partial class ConfigMgrWebService + { + [WebMethod(Description = "Remove a computer object from Active Directory on the specified domain controller (Prohibits removal of domain controllers)")] + public bool RemoveADComputerByDC(string secret, string samAccountName, string dc) + { + var method = MethodBase.GetCurrentMethod(); + MethodBegin(method); + + //' Instatiate return value variable + bool returnValue = false; + ComputerPrincipal compPrin = null; + DirectoryEntry dirEntry = null; + string respondingDC = null; + + //' Validate secret key + if (secret == secretKey) + { + //' Log that secret key was accepted + WriteEventLog("Secret key was accepted", EventLogEntryType.Information); + + using (ADDomain domain = Domain.GetComputerDomain()) + { + if (!domain.IsDC(samAccountName)) + { + WriteEventLog(string.Format("{0} is not a domain controller. Continuing with removal.", samAccountName), EventLogEntryType.Information); + compPrin = FindComputerObject(samAccountName, dc, out respondingDC); + if (compPrin == null) + { + WriteEventLog(string.Format("{0} was not found in active directory!", samAccountName), EventLogEntryType.Error); + } + else + { + dirEntry = (DirectoryEntry)compPrin.GetUnderlyingObject(); + try + { + dirEntry.DeleteTree(); + dirEntry.CommitChanges(); + returnValue = true; + WriteEventLog(string.Format("{0} was successfully deleted from Active Directory on {1}.", samAccountName, respondingDC), EventLogEntryType.Information); + } + catch (DirectoryServicesCOMException comEx) + { + WriteEventLog(string.Format("{0}:{1}{1}{2}", comEx.Message, Environment.NewLine, comEx.ExtendedErrorMessage), EventLogEntryType.Error); + } + catch (AppDomainUnloadedException unloadEx) + { + WriteEventLog(string.Format("{0}{1}{1}{2}", unloadEx.Message, Environment.NewLine, unloadEx.StackTrace), EventLogEntryType.Error); + } + catch (Exception e) + { + WriteEventLog(e.Message, EventLogEntryType.Error); + } + } + } + else + { + WriteEventLog(string.Format("{0} matches the name of an existing domain controller! We are not allowed to remove domain controllers. Stopping the execution.", samAccountName), EventLogEntryType.Error); + } + } + } + + dirEntry.Dispose(); + compPrin.Dispose(); + + MethodEnd(method); + return returnValue; + } + } +} \ No newline at end of file diff --git a/ConfigMgrWebService/ADOperations/RemoveADComputerFromGroupByDC.cs b/ConfigMgrWebService/ADOperations/RemoveADComputerFromGroupByDC.cs new file mode 100644 index 0000000..f7e3973 --- /dev/null +++ b/ConfigMgrWebService/ADOperations/RemoveADComputerFromGroupByDC.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.DirectoryServices; +using System.Reflection; +using System.Web.Services; + +namespace ConfigMgrWebService +{ + public partial class ConfigMgrWebService + { + [WebMethod(Description = "Remove a computer in Active Directory from a specific group on the specified domain controller.")] + public bool RemoveADComputerFromGroupByDC(string secret, string groupName, string computerName, string domainController) + { + var method = MethodBase.GetCurrentMethod(); + MethodBegin(method); + + //' Set return value variable + bool returnValue = false; + + //' Validate secret key + if (secret == secretKey) + { + //' Log that secret key was accepted + WriteEventLog("Secret key was accepted", EventLogEntryType.Information); + + //' Get AD object distinguished name for computer and group + string computerDistinguishedName = (GetADObject(computerName, ADObjectClass.Computer, ADObjectType.distinguishedName, domainController)).Remove(0, 7); + string groupDistinguishedName = GetADObject(groupName, ADObjectClass.Group, ADObjectType.distinguishedName, domainController); + + if (!string.IsNullOrEmpty(computerDistinguishedName) && !string.IsNullOrEmpty(groupDistinguishedName)) + { + try + { + //' Check if computer is member of group + var groupEntry = new DirectoryEntry(groupDistinguishedName); + List groupMembers = GetADGroupMemberList(groupEntry); + bool memberOf = groupMembers.Contains(computerDistinguishedName); + if (memberOf == true) + { + //' Remove computer from group and commit + groupEntry.Properties["member"].Remove(computerDistinguishedName); + groupEntry.CommitChanges(); + + returnValue = true; + } + + //' Dispose object + groupEntry.Dispose(); + } + catch (Exception ex) + { + WriteEventLog(string.Format("An error occured when attempting to remove a computer object in Active Directory from a group. Error message: {0}", ex.Message), EventLogEntryType.Error); + } + } + } + + MethodEnd(method); + return returnValue; + } + } +} \ No newline at end of file diff --git a/ConfigMgrWebService/ADOperations/SetADComputerManagedByByDC.cs b/ConfigMgrWebService/ADOperations/SetADComputerManagedByByDC.cs new file mode 100644 index 0000000..6054937 --- /dev/null +++ b/ConfigMgrWebService/ADOperations/SetADComputerManagedByByDC.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; +using System.Reflection; +using System.Web; +using System.Web.Services; + +namespace ConfigMgrWebService +{ + public partial class ConfigMgrWebService + { + [WebMethod(Description = "Set ManagedBy attribute for a specific computer with specified user name on the specified domain controller.")] + public bool SetADComputerManagedByByDC(string secret, string computerName, string userName, string domainController) + { + var method = MethodBase.GetCurrentMethod(); + MethodBegin(method); + + //' Variable for return value + bool returnValue = false; + + //' Validate secret key + if (secret == secretKey) + { + //' Log that secret key was accepted + WriteEventLog("Secret key was accepted", EventLogEntryType.Information); + + //' Get AD computer and user object distinguished names + string computerDistinguishedName = GetADObject(computerName, ADObjectClass.Computer, ADObjectType.distinguishedName, domainController); + string userDistinguishedName = (GetADObject(userName, ADObjectClass.User, ADObjectType.distinguishedName, domainController)).Remove(0, 7); + + if (!string.IsNullOrEmpty(computerDistinguishedName) && !string.IsNullOrEmpty(userDistinguishedName)) + { + try + { + //' Add user to ManagedBy attribute and commit + var computerEntry = new DirectoryEntry(computerDistinguishedName); + computerEntry.Properties["ManagedBy"].Clear(); + computerEntry.Properties["ManagedBy"].Add(userDistinguishedName); + computerEntry.CommitChanges(); + + //' Dispose object + computerEntry.Dispose(); + + returnValue = true; + } + catch (Exception ex) + { + WriteEventLog(string.Format("An error occured when attempting to add a user as ManagedBy for a computer object in Active Directory. Error message: {0}", ex.Message), EventLogEntryType.Error); + } + } + } + + MethodEnd(method); + return returnValue; + } + } +} \ No newline at end of file diff --git a/ConfigMgrWebService/ADOperations/SetADOrganizationalUnitForComputerByDC.cs b/ConfigMgrWebService/ADOperations/SetADOrganizationalUnitForComputerByDC.cs new file mode 100644 index 0000000..0130589 --- /dev/null +++ b/ConfigMgrWebService/ADOperations/SetADOrganizationalUnitForComputerByDC.cs @@ -0,0 +1,64 @@ +using System; +using System.Diagnostics; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; +using System.Reflection; +using System.Web; +using System.Web.Services; + +namespace ConfigMgrWebService +{ + public partial class ConfigMgrWebService + { + [WebMethod(Description = "Move a computer in Active Directory to a specific organizational unit via the specified domain controller.")] + public bool SetADOrganizationalUnitForComputerByDC(string secret, string organizationalUnitLocation, string computerName, string domainController) + { + var method = MethodBase.GetCurrentMethod(); + MethodBegin(method); + + //' Variable for return value + bool returnValue = false; + + //' Validate secret key + if (secret == secretKey) + { + //' Log that secret key was accepted + WriteEventLog("Secret key was accepted", EventLogEntryType.Information); + + //' Determine if ldap prefix needs to be appended + if (organizationalUnitLocation.StartsWith("LDAP://") == false && string.IsNullOrEmpty(domainController)) + { + organizationalUnitLocation = string.Format("LDAP://{0}", organizationalUnitLocation); + } + else if (!string.IsNullOrEmpty(domainController)) + { + string fullLDAP = "LDAP://{0}/{1}"; + organizationalUnitLocation = string.Format(fullLDAP, domainController, organizationalUnitLocation); + } + + //' Get AD object distinguished name + string currentDistinguishedName = GetADObject(computerName, ADObjectClass.Computer, ADObjectType.distinguishedName, domainController); + + if (!string.IsNullOrEmpty(currentDistinguishedName)) + { + try + { + //' Move current object to new location + var currentObject = new DirectoryEntry(currentDistinguishedName); + var newLocation = new DirectoryEntry(organizationalUnitLocation); + currentObject.MoveTo(newLocation, currentObject.Name); + + returnValue = true; + } + catch (Exception ex) + { + WriteEventLog(string.Format("An error occured when attempting to move Active Directory object. Error message: {0}", ex.Message), EventLogEntryType.Error); + } + } + } + + MethodEnd(method); + return returnValue; + } + } +} \ No newline at end of file diff --git a/ConfigMgrWebService/ADOrganizationalUnit.cs b/ConfigMgrWebService/ADOrganizationalUnit.cs index 821d190..612e0f4 100644 --- a/ConfigMgrWebService/ADOrganizationalUnit.cs +++ b/ConfigMgrWebService/ADOrganizationalUnit.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.DirectoryServices; using System.Linq; using System.Web; @@ -7,8 +8,61 @@ namespace ConfigMgrWebService { public class ADOrganizationalUnit { + + private string Path { get; set; } + public string Name { set; get; } public string DistinguishedName { set; get; } public bool HasChildren { set; get; } + + public ADOrganizationalUnit() { } + + /// + /// The 2nd constructor for . Using the specified , + /// this will populate the class's properties. + /// + /// The to use when populating this class's properties. + public ADOrganizationalUnit(DirectoryEntry dirEntry) + { + using (dirEntry) + { + if (dirEntry.SchemaClassName != ConfigMgrWebService.ORG_UNIT) + throw new ArgumentException("The provided DirectoryEntry is not a valid Organizational Unit!"); + + this.HasChildren = false; + this.Name = dirEntry.Properties[ConfigMgrWebService.NAME].Value as string; + this.DistinguishedName = dirEntry.Properties[ConfigMgrWebService.DISTINGUISHED_NAME].Value as string; + foreach (DirectoryEntry child in dirEntry.Children) + { + if (child.SchemaClassName == ConfigMgrWebService.ORG_UNIT) + { + this.HasChildren = true; + break; + } + } + this.Path = dirEntry.Path; + } + } + + public IEnumerable GetChildrenOUs() + { + if (this.HasChildren) + { + var list = new List(); + using (DirectoryEntry de = this.GetDirectoryEntry()) + { + foreach (DirectoryEntry entry in de.Children) + { + if (entry.SchemaClassName == ConfigMgrWebService.ORG_UNIT) + list.Add(new ADOrganizationalUnit(entry)); + } + } + return list; + } + else + return null; + } + + private DirectoryEntry GetDirectoryEntry() => new DirectoryEntry(this.Path); } } \ No newline at end of file diff --git a/ConfigMgrWebService/ConfigMgrWebService.asmx.cs b/ConfigMgrWebService/ConfigMgrWebService.asmx.cs index 644cce9..61a8cdc 100644 --- a/ConfigMgrWebService/ConfigMgrWebService.asmx.cs +++ b/ConfigMgrWebService/ConfigMgrWebService.asmx.cs @@ -1,26 +1,28 @@ -using System; +using Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine; +using Microsoft.ConfigurationManagement.ManagementProvider; +using SqlExtensions; +using System; using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.DirectoryServices; using System.Collections; -using System.Diagnostics; -using System.Web.Services; -using System.Management; -using System.Web.Configuration; +using System.ComponentModel; using System.Data.SqlClient; -using Microsoft.ConfigurationManagement.ManagementProvider; -using Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine; -using System.Text; using System.Data; -using System.Reflection; -using System.DirectoryServices.ActiveDirectory; +using System.Diagnostics; using System.DirectoryServices.AccountManagement; +using System.DirectoryServices.ActiveDirectory; +using System.DirectoryServices; +using System.Globalization; +using System.Linq; +using System.Management; using System.Net; -using System.Security; +using System.Reflection; using System.Runtime.InteropServices; -using System.Globalization; -using SqlExtensions; +using System.Security; +using System.Text; +using System.Text.RegularExpressions; +using System.Web.Configuration; +using System.Web.Services; +using System.Web; namespace SqlExtensions { @@ -41,9 +43,9 @@ namespace ConfigMgrWebService { [WebService(Name = "ConfigMgr WebService", Description = "Web service for ConfigMgr Current Branch developed by Nickolaj Andersen (1.7.0)", Namespace = "http://www.scconfigmgr.com")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] - [System.ComponentModel.ToolboxItem(false)] + [ToolboxItem(false)] - public class ConfigMgrWebService : System.Web.Services.WebService + public partial class ConfigMgrWebService : WebService { //' Read required application settings from web.config private string secretKey = WebConfigurationManager.AppSettings["SecretKey"]; @@ -2726,309 +2728,30 @@ public CMTaskSequence GetCMTaskSequence(string secret, string packageID) } [WebMethod(Description = "Move a computer in Active Directory to a specific organizational unit")] - public bool SetADOrganizationalUnitForComputer(string secret, string organizationalUnitLocation, string computerName) - { - MethodBase method = MethodBase.GetCurrentMethod(); - MethodBegin(method); - - //' Variable for return value - bool returnValue = false; - - //' Validate secret key - if (secret == secretKey) - { - //' Log that secret key was accepted - WriteEventLog("Secret key was accepted", EventLogEntryType.Information); - - //' Determine if ldap prefix needs to be appended - if (organizationalUnitLocation.StartsWith("LDAP://") == false) - { - organizationalUnitLocation = String.Format("LDAP://{0}", organizationalUnitLocation); - } - - //' Get AD object distinguished name - string currentDistinguishedName = GetADObject(computerName, ADObjectClass.Computer, ADObjectType.distinguishedName); - - if (!String.IsNullOrEmpty(currentDistinguishedName)) - { - try - { - //' Move current object to new location - DirectoryEntry currentObject = new DirectoryEntry(currentDistinguishedName); - DirectoryEntry newLocation = new DirectoryEntry(organizationalUnitLocation); - currentObject.MoveTo(newLocation, currentObject.Name); - - returnValue = true; - } - catch (Exception ex) - { - WriteEventLog(String.Format("An error occured when attempting to move Active Directory object. Error message: {0}", ex.Message), EventLogEntryType.Error); - } - } - } - - MethodEnd(method); - return returnValue; - } + public bool SetADOrganizationalUnitForComputer(string secret, string organizationalUnitLocation, string computerName) => + this.SetADOrganizationalUnitForComputerByDC(secret, organizationalUnitLocation, computerName, null); [WebMethod(Description = "Set ManagedBy attribute for a specific computer with specified user name")] - public bool SetADComputerManagedBy(string secret, string computerName, string userName) - { - MethodBase method = MethodBase.GetCurrentMethod(); - MethodBegin(method); - - //' Variable for return value - bool returnValue = false; - - //' Validate secret key - if (secret == secretKey) - { - //' Log that secret key was accepted - WriteEventLog("Secret key was accepted", EventLogEntryType.Information); - - //' Get AD computer and user object distinguished names - string computerDistinguishedName = GetADObject(computerName, ADObjectClass.Computer, ADObjectType.distinguishedName); - string userDistinguishedName = (GetADObject(userName, ADObjectClass.User, ADObjectType.distinguishedName)).Remove(0, 7); - - if (!String.IsNullOrEmpty(computerDistinguishedName) && !String.IsNullOrEmpty(userDistinguishedName)) - { - try - { - //' Add user to ManagedBy attribute and commit - DirectoryEntry computerEntry = new DirectoryEntry(computerDistinguishedName); - computerEntry.Properties["ManagedBy"].Clear(); - computerEntry.Properties["ManagedBy"].Add(userDistinguishedName); - computerEntry.CommitChanges(); - - //' Dispose object - computerEntry.Dispose(); - - returnValue = true; - } - catch (Exception ex) - { - WriteEventLog(String.Format("An error occured when attempting to add a user as ManagedBy for a computer object in Active Directory. Error message: {0}", ex.Message), EventLogEntryType.Error); - } - } - } - - MethodEnd(method); - return returnValue; - } + public bool SetADComputerManagedBy(string secret, string computerName, string userName) => + this.SetADComputerManagedBy(secret, computerName, null); [WebMethod(Description = "Add a computer in Active Directory to a specific group")] - public bool AddADComputerToGroup(string secret, string groupName, string computerName) - { - MethodBase method = MethodBase.GetCurrentMethod(); - MethodBegin(method); - - //' Variable for return value - bool returnValue = false; - - //' Validate secret key - if (secret == secretKey) - { - //' Log that secret key was accepted - WriteEventLog("Secret key was accepted", EventLogEntryType.Information); - - //' Get AD object distinguished name for computer and group - string computerDistinguishedName = (GetADObject(computerName, ADObjectClass.Computer, ADObjectType.distinguishedName)).Remove(0, 7); - string groupDistinguishedName = GetADObject(groupName, ADObjectClass.Group, ADObjectType.distinguishedName); - - if (!String.IsNullOrEmpty(computerDistinguishedName) && !String.IsNullOrEmpty(groupDistinguishedName)) - { - try - { - //' Add computer to group and commit - DirectoryEntry groupEntry = new DirectoryEntry(groupDistinguishedName); - groupEntry.Properties["member"].Add(computerDistinguishedName); - groupEntry.CommitChanges(); - - //' Dispose object - groupEntry.Dispose(); - - returnValue = true; - } - catch (Exception ex) - { - WriteEventLog(String.Format("An error occured when attempting to add a computer object in Active Directory to a group. Error message: {0}", ex.Message), EventLogEntryType.Error); - } - } - } - - MethodEnd(method); - return returnValue; - } + public bool AddADComputerToGroup(string secret, string groupName, string computerName) => + this.AddADComputerToGroupByDC(secret, groupName, computerName, null); [WebMethod(Description = "Add a user in Active Directory to a specific group")] - public bool AddADUserToGroup(string secret, string groupName, string userName) - { - MethodBase method = MethodBase.GetCurrentMethod(); - MethodBegin(method); - - //' Variable for return value - bool returnValue = false; - - //' Validate secret key - if (secret == secretKey) - { - //' Log that secret key was accepted - WriteEventLog("Secret key was accepted", EventLogEntryType.Information); - - //' Get AD object distinguished name for computer and group - string userDistinguishedName = (GetADObject(userName, ADObjectClass.User, ADObjectType.distinguishedName)).Remove(0, 7); - string groupDistinguishedName = GetADObject(groupName, ADObjectClass.Group, ADObjectType.distinguishedName); - - if (!String.IsNullOrEmpty(userDistinguishedName) && !String.IsNullOrEmpty(groupDistinguishedName)) - { - try - { - //' Add user to group and commit - DirectoryEntry groupEntry = new DirectoryEntry(groupDistinguishedName); - groupEntry.Properties["member"].Add(userDistinguishedName); - groupEntry.CommitChanges(); - - //' Dispose object - groupEntry.Dispose(); - - returnValue = true; - } - catch (Exception ex) - { - WriteEventLog(String.Format("An error occured when attempting to add an user object in Active Directory to a group. Error message: {0}", ex.Message), EventLogEntryType.Error); - } - } - } - - MethodEnd(method); - return returnValue; - } + public bool AddADUserToGroup(string secret, string groupName, string userName) => + this.AddADUserToGroupByDC(secret, groupName, userName, null); [WebMethod(Description = "Remove a computer in Active Directory from a specific group")] - public bool RemoveADComputerFromGroup(string secret, string groupName, string computerName) - { - MethodBase method = MethodBase.GetCurrentMethod(); - MethodBegin(method); - - //' Set return value variable - bool returnValue = false; - - //' Validate secret key - if (secret == secretKey) - { - //' Log that secret key was accepted - WriteEventLog("Secret key was accepted", EventLogEntryType.Information); - - //' Get AD object distinguished name for computer and group - string computerDistinguishedName = (GetADObject(computerName, ADObjectClass.Computer, ADObjectType.distinguishedName)).Remove(0,7); - string groupDistinguishedName = GetADObject(groupName, ADObjectClass.Group, ADObjectType.distinguishedName); - - if (!String.IsNullOrEmpty(computerDistinguishedName) && !String.IsNullOrEmpty(groupDistinguishedName)) - { - try - { - //' Check if computer is member of group - DirectoryEntry groupEntry = new DirectoryEntry(groupDistinguishedName); - List groupMembers = GetADGroupMemberList(groupEntry); - bool memberOf = groupMembers.Contains(computerDistinguishedName); - if (memberOf == true) - { - //' Remove computer from group and commit - groupEntry.Properties["member"].Remove(computerDistinguishedName); - groupEntry.CommitChanges(); - - returnValue = true; - } - - //' Dispose object - groupEntry.Dispose(); - } - catch (Exception ex) - { - WriteEventLog(String.Format("An error occured when attempting to remove a computer object in Active Directory from a group. Error message: {0}", ex.Message), EventLogEntryType.Error); - } - } - } - - MethodEnd(method); - return returnValue; - } + public bool RemoveADComputerFromGroup(string secret, string groupName, string computerName) => + this.RemoveADComputerFromGroupByDC(secret, groupName, computerName, null); [WebMethod(Description = "Get all members of an Active Directory group")] - public List GetADGroupMembers(string secret, string groupName) - { - MethodBase method = MethodBase.GetCurrentMethod(); - MethodBegin(method); - - //' Set return value variable - List returnValue = new List(); - - //' Validate secret key - if (secret == secretKey) - { - //' Log that secret key was accepted - WriteEventLog("Secret key was accepted", EventLogEntryType.Information); - - //' Get AD group object - string groupDistinguishedName = GetADObject(groupName, ADObjectClass.Group, ADObjectType.distinguishedName); - - if (!String.IsNullOrEmpty(groupDistinguishedName)) - { - try - { - DirectoryEntry groupEntry = new DirectoryEntry(groupDistinguishedName); - returnValue = GetADGroupMemberList(groupEntry); - } - catch (Exception ex) - { - WriteEventLog(String.Format("An error occured when retrieving Active Directory group members. Error message: {0}", ex.Message), EventLogEntryType.Error); - } - } - } - - MethodEnd(method); - return returnValue; - } + public List GetADGroupMembers(string secret, string groupName) => this.GetADGroupMembersByDC(secret, groupName, null); [WebMethod(Description = "Get Active Directory groups for a specific user")] - public List GetADGroupsByUser(string secret, string userName) - { - MethodBase method = MethodBase.GetCurrentMethod(); - MethodBegin(method); - - //' Set return value variable - List returnValue = new List(); - - //' Validate secret key - if (secret == secretKey) - { - //' Log that secret key was accepted - WriteEventLog("Secret key was accepted", EventLogEntryType.Information); - - try - { - //' Get AD user object - string userDistinguishedName = GetADObject(userName, ADObjectClass.User, ADObjectType.distinguishedName); - - //' Get AD groups for user distinguished name - ArrayList groupMemberships = new ArrayList(); - ArrayList groups = GetADAttributeValues("memberOf", userDistinguishedName, groupMemberships, true); - - foreach (string group in groups) - { - string attributeValue = GetADAttributeValue(group, "samAccountName"); - returnValue.Add(new ADGroup() { DistinguishedName = group, samAccountName = attributeValue }); - } - } - catch (Exception ex) - { - WriteEventLog($"An error occurred while retrieving Active Directory group memberships for user. Error message: { ex.Message }", EventLogEntryType.Error); - } - } - - MethodEnd(method); - return returnValue; - } + public List GetADGroupsByUser(string secret, string userName) => this.GetADGroupsByUserByDC(secret, userName, null); [WebMethod(Description = "Set the description field for a computer in Active Directory")] public bool SetADComputerDescription(string secret, string computerName, string description) @@ -3244,82 +2967,19 @@ public bool GetADGroupMemberByComputer(string secret, string computerName, strin } [WebMethod(Description = "Check if a computer object exists in Active Directory")] - public ADComputer GetADComputer(string secret, string computerName) - { - MethodBase method = MethodBase.GetCurrentMethod(); - MethodBegin(method); - - //' Instatiate return value variable - ADComputer returnValue = new ADComputer(); - - //' Validate secret key - if (secret == secretKey) - { - //' Log that secret key was accepted - WriteEventLog("Secret key was accepted", EventLogEntryType.Information); - - //' Set empty value for search result - SearchResult searchResult = null; - DirectoryEntry directoryObject = null; - - //' Get default naming context of current domain - string defaultNamingContext = GetADDefaultNamingContext(); - string currentDomain = String.Format("GC://{0}", defaultNamingContext); - - //' Construct directory entry for directory searcher - DirectoryEntry domain = new DirectoryEntry(currentDomain); - DirectorySearcher directorySearcher = new DirectorySearcher(domain) - { - Filter = String.Format("(&(objectClass=computer)((sAMAccountName={0}$)))", computerName) - }; - directorySearcher.PropertiesToLoad.Add("distinguishedName"); - directorySearcher.PropertiesToLoad.Add("sAMAccountName"); - directorySearcher.PropertiesToLoad.Add("cn"); - directorySearcher.PropertiesToLoad.Add("dNSHostName"); - - //' Invoke directory searcher - try - { - searchResult = directorySearcher.FindOne(); - if (searchResult != null) - { - //' Get computer object from search result - directoryObject = searchResult.GetDirectoryEntry(); - - if (directoryObject != null) - { - returnValue.SamAccountName = (string)directoryObject.Properties["sAMAccountName"].Value; - returnValue.CanonicalName = (string)directoryObject.Properties["cn"].Value; - returnValue.DistinguishedName = (string)directoryObject.Properties["distinguishedName"].Value; - returnValue.DnsHostName = (string)directoryObject.Properties["dNSHostName"].Value; - - // Dispose directory object - directoryObject.Dispose(); - } - } - } - catch (Exception ex) - { - WriteEventLog(String.Format("An error occured when attempting to locate Active Directory object. Error message: {0}", ex.Message), EventLogEntryType.Error); - } - - //' Dispose objects - directorySearcher.Dispose(); - domain.Dispose(); - } - - MethodEnd(method); - return returnValue; - } + public ADComputer GetADComputer(string secret, string computerName) => (ADComputer)this.GetADComputerByDC(secret, computerName, null); [WebMethod(Description = "Remove a computer object from Active Directory (Prohibits removal of domain controllers)")] - public bool RemoveADComputer(string secret, string samAccountName) + public bool RemoveADComputer(string secret, string samAccountName) => RemoveADComputerByDC(secret, samAccountName, null); + + [WebMethod(Description = "Get the domain details for current domain")] + public ADDomain GetADDomain(string secret) { MethodBase method = MethodBase.GetCurrentMethod(); MethodBegin(method); //' Instatiate return value variable - bool returnValue = false; + ADDomain domain = null; //' Validate secret key if (secret == secretKey) @@ -3327,100 +2987,29 @@ public bool RemoveADComputer(string secret, string samAccountName) //' Log that secret key was accepted WriteEventLog("Secret key was accepted", EventLogEntryType.Information); - //' Construct list for all domain controllers - List domainControllers = new List(); - - //' Configure domain context - Domain currentDomain = Domain.GetCurrentDomain(); - PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, currentDomain.Name, null, ContextOptions.Negotiate); - WriteEventLog(String.Format("Using current domain for domain controller lookup: {0}", currentDomain.Name), EventLogEntryType.Information); - - //' Get a list of all domain controllers in the current domain try { - foreach (DomainController domainController in currentDomain.DomainControllers) - { - //' Add domain controller distinguished name to list - DirectoryEntry domainControllerEntry = domainController.GetDirectoryEntry(); - string domainControllerName = (string)domainControllerEntry.Properties["name"].Value; - - //' Debug - WriteEventLog(String.Format("Detected domain controller name: {0}", domainControllerName), EventLogEntryType.Information); - - ComputerPrincipal dcPrincipal = ComputerPrincipal.FindByIdentity(principalContext, IdentityType.Name, domainControllerName); - domainControllers.Add(dcPrincipal.DistinguishedName); - - //' Dispose objects - domainControllerEntry.Dispose(); - dcPrincipal.Dispose(); - } + DirectoryContext ctx = new DirectoryContext(DirectoryContextType.Domain); + domain = Domain.GetDomain(ctx); } catch (Exception ex) { - WriteEventLog(String.Format("Unable to detect domain controllers in current domain. Error message: {0}", ex.Message), EventLogEntryType.Error); - returnValue = false; - } - - if (domainControllers.Count >= 1) - { - //' Get computer principal eligible for removal - ComputerPrincipal computerPrincipal = ComputerPrincipal.FindByIdentity(principalContext, samAccountName); - - if (computerPrincipal != null) - { - if (domainControllers.Contains(computerPrincipal.DistinguishedName) == false) - { - try - { - //' Delete computer object including any leaf objects - DirectoryEntry subEntry = (DirectoryEntry)computerPrincipal.GetUnderlyingObject(); - - if (subEntry != null) - { - subEntry.DeleteTree(); - subEntry.CommitChanges(); - - WriteEventLog(String.Format("Successfully removed computer object named '{0}'", computerPrincipal.Name), EventLogEntryType.Information); - } - - //' Dispose object - subEntry.Dispose(); - - returnValue = true; - } - catch (Exception ex) - { - WriteEventLog(String.Format("Unable to remove computer object '{0}'. Error message: {1}", samAccountName, ex.Message), EventLogEntryType.Error); - returnValue = false; - } - } - - //' Dispose object - computerPrincipal.Dispose(); - } - else - { - WriteEventLog(String.Format("Unable to find a computer object named '{0}'", computerPrincipal.Name), EventLogEntryType.Information); - } + WriteEventLog($"An error occurred while querying for Active Directory domain details. Error message: { ex.Message } ", EventLogEntryType.Error); } - - //' Dispose objects - currentDomain.Dispose(); - principalContext.Dispose(); } MethodEnd(method); - return returnValue; + return domain; } - [WebMethod(Description = "Get the domain details for current domain")] - public ADDomain GetADDomain(string secret) + [WebMethod(Description = "Get the domain details for the specified domain")] + public ADDomain GetADDomainByName(string secret, string domainName) { MethodBase method = MethodBase.GetCurrentMethod(); MethodBegin(method); //' Instatiate return value variable - ADDomain domain = new ADDomain(); + ADDomain domain = null; //' Validate secret key if (secret == secretKey) @@ -3430,8 +3019,8 @@ public ADDomain GetADDomain(string secret) try { - domain.DefaultNamingContext = GetADDefaultNamingContext(); - domain.DomainName = GetADDomainName(); + DirectoryContext ctx = new DirectoryContext(DirectoryContextType.Domain, domainName); + domain = Domain.GetDomain(ctx); } catch (Exception ex) { @@ -3467,42 +3056,13 @@ public List GetADOrganizationalUnits(string secret, string } //' Get the base OU directory entry and start a one level search - using (DirectorySearcher directorySearcher = new DirectorySearcher(new DirectoryEntry(distinguishedName))) + using (DirectorySearcher directorySearcher = new DirectorySearcher(new DirectoryEntry(distinguishedName), + "(objectCategory=organizationalUnit)", ORG_UNIT_PROPERTIES, SearchScope.Subtree)) { - //' Define filter options for searcher - directorySearcher.Filter = "(objectCategory=organizationalUnit)"; - directorySearcher.SearchScope = SearchScope.OneLevel; - directorySearcher.PropertiesToLoad.Add("name"); - directorySearcher.PropertiesToLoad.Add("path"); - //' Enumerate top level containers foreach (SearchResult container in directorySearcher.FindAll()) { - //' Search for children - SearchResult childResult = null; - using (DirectorySearcher childDirectorySearcher = new DirectorySearcher(new DirectoryEntry(container.Path))) - { - //' Define filter options for searcher - childDirectorySearcher.Filter = "(objectCategory=organizationalUnit)"; - childDirectorySearcher.SearchScope = SearchScope.OneLevel; - childDirectorySearcher.PropertiesToLoad.Add("name"); - childResult = childDirectorySearcher.FindOne(); - } - - //' Determine if child exist - bool childPresence = false; - if (childResult != null) - { - childPresence = true; - } - - //' Construct a new object to hold container information - ADOrganizationalUnit orgUnit = new ADOrganizationalUnit() - { - HasChildren = childPresence, - Name = container.Properties["name"][0].ToString(), - DistinguishedName = container.Path - }; + ADOrganizationalUnit orgUnit = new ADOrganizationalUnit(container.GetDirectoryEntry()); containers.Add(orgUnit); } } @@ -5662,70 +5222,7 @@ private string GetADDomainName() return Domain.GetComputerDomain().Name; } - private string GetADObject(string name, ADObjectClass objectClass, ADObjectType objectType) - { - //' Set empty value for return object and search result - string returnValue = string.Empty; - SearchResult searchResult = null; - - //' Get default naming context of current domain - string defaultNamingContext = GetADDefaultNamingContext(); - string currentDomain = String.Format("LDAP://{0}", defaultNamingContext); - - //' Construct directory entry for directory searcher - DirectoryEntry domain = new DirectoryEntry(currentDomain); - DirectorySearcher directorySearcher = new DirectorySearcher(domain); - directorySearcher.PropertiesToLoad.Add("distinguishedName"); - - switch (objectClass) - { - case ADObjectClass.DomainController: - directorySearcher.Filter = String.Format("(&(objectClass=computer)((dNSHostName={0})))", name); - break; - case ADObjectClass.Computer: - directorySearcher.Filter = String.Format("(&(objectClass=computer)((sAMAccountName={0}$)))", name); - break; - case ADObjectClass.Group: - directorySearcher.Filter = String.Format("(&(objectClass=group)((sAMAccountName={0})))", name); - break; - case ADObjectClass.User: - directorySearcher.Filter = String.Format("(&(objectClass=user)((sAMAccountName={0})))", name); - break; - } - - //' Invoke directory searcher - try - { - searchResult = directorySearcher.FindOne(); - } - catch (Exception ex) - { - WriteEventLog(String.Format("An error occured when attempting to locate Active Directory object. Error message: {0}", ex.Message), EventLogEntryType.Error); - return returnValue; - } - - //' Return selected object type value - if (searchResult != null) - { - DirectoryEntry directoryObject = searchResult.GetDirectoryEntry(); - - if (objectType.Equals(ADObjectType.objectGuid)) - { - returnValue = directoryObject.Guid.ToString(); - } - - if (objectType.Equals(ADObjectType.distinguishedName)) - { - returnValue = String.Format("LDAP://{0}", directoryObject.Properties["distinguishedName"].Value); - } - } - - //' Dispose objects - directorySearcher.Dispose(); - domain.Dispose(); - - return returnValue; - } + /// /// Code adjusted from: https://itq.nl/get-more-than-1500-members-from-an-active-directory-group/ @@ -5791,13 +5288,18 @@ private List GetADGroupMemberList(DirectoryEntry groupEntry) /// /// Check if user if member of a group including nested group - https://stackoverflow.com/questions/5312744/how-to-determine-all-the-groups-a-user-belongs-to-including-nested-groups-in-a/31725157#31725157 /// - private bool GetADGroupNestedMemberOf(Principal principal, GroupPrincipal group) + private bool GetADGroupNestedMemberOf(Principal principal, GroupPrincipal group, string domainController = null) { //' LDAP query for memberOf including nested string filter = String.Format("(&(sAMAccountName={0})(memberOf:1.2.840.113556.1.4.1941:={1}))", principal.SamAccountName, group.DistinguishedName); WriteEventLog(String.Format("Using LDAP filter for user validation: {0}", filter), EventLogEntryType.Information); DirectorySearcher searcher = new DirectorySearcher(filter); + string ldapString = string.IsNullOrEmpty(domainController) + ? string.Format("LDAP://{0}", this.GetADDefaultNamingContext()) + : string.Format("LDAP://{0}/{1}", domainController, this.GetADDefaultNamingContext()); + + searcher.SearchRoot = new DirectoryEntry(ldapString); SearchResult result = searcher.FindOne(); return result != null; @@ -5879,6 +5381,72 @@ public static Dictionary GetADSubnets(string forestName) return subnetList; } + private ComputerPrincipal FindComputerObject(string name, string dc, out string respondingDC) + { + ComputerPrincipal returnValue = null; + string realDC = null; + using (Domain domain = Domain.GetComputerDomain()) + { + realDC = GetRespondingDomainController(domain, dc); + PrincipalContext prinCtx = new PrincipalContext(ContextType.Domain, realDC, null, ContextOptions.Negotiate); + WriteEventLog(string.Format("Using the following domain controller for the computer lookup: {0}", realDC), EventLogEntryType.Information); + + returnValue = ComputerPrincipal.FindByIdentity(prinCtx, name); + } + respondingDC = realDC; + return returnValue; + } + + private Domain GetDomainFromDN(string ouPath) + { + string[] dcStrings = ouPath.Split( + new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries).Where( + x => x.StartsWith("DC=", StringComparison.CurrentCultureIgnoreCase)).ToArray(); + + string[] cutOut = new string[dcStrings.Length]; + for (int i = 0; i < dcStrings.Length; i++) + { + cutOut[i] = Regex.Match(dcStrings[i], @"^[D|d][C|c]\=(\S{1,})").Groups[1].Value; + } + string fqdn = string.Join(".", cutOut); + return GetDomainFromString(fqdn); + } + + private Domain GetDomainFromString(string domainName) + { + DirectoryContext ctx = string.IsNullOrEmpty(domainName) + ? new DirectoryContext(DirectoryContextType.Domain) + : new DirectoryContext(DirectoryContextType.Domain, domainName); + + Domain retDomain = Domain.GetDomain(ctx); + return retDomain; + } + + private string GetLDAPString(ADDomain domain, string dc, out string respondingDC) + { + string format = "LDAP://{0}/{1}"; + respondingDC = GetRespondingDomainController(domain, dc); + string ldapStr = string.Format(format, respondingDC, domain.DefaultNamingContext); + return ldapStr; + } + + private string GetRespondingDomainController(Domain domain, string dc) + { + string retName = null; + if (string.IsNullOrEmpty(dc)) + { + using (DomainController domCon = domain.FindDomainController()) + { + retName = domCon.Name; + } + } + else retName = !dc.Contains(domain.Name) + ? string.Format("{0}.{1}", dc, domain.Name) + : dc; + + return retName; + } + private static int FindMissingNumber(List list) { //' Missing number return value diff --git a/ConfigMgrWebService/ConfigMgrWebService.csproj b/ConfigMgrWebService/ConfigMgrWebService.csproj index e5a83af..ad4991a 100644 --- a/ConfigMgrWebService/ConfigMgrWebService.csproj +++ b/ConfigMgrWebService/ConfigMgrWebService.csproj @@ -10,7 +10,6 @@ 2.0 {9A0DC841-CDB0-4B6D-B1B4-42E307A7675C} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} Library Properties ConfigMgrWebService @@ -44,17 +43,15 @@ 4 - - False - ..\References\AdminUI.WqlQueryEngine.dll + + Assemblies\AdminUI.WqlQueryEngine.dll ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll True - - False - ..\References\Microsoft.ConfigurationManagement.ManagementProvider.dll + + Assemblies\Microsoft.ConfigurationManagement.ManagementProvider.dll @@ -93,9 +90,24 @@ + + + + + Component + + + + + Component + + + + + @@ -103,6 +115,9 @@ + + Component + @@ -116,6 +131,9 @@ ConfigMgrWebService.asmx + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) @@ -126,24 +144,7 @@ - - - - - True - True - 60167 - / - http://localhost:60167/ - False - False - - - False - - - - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. diff --git a/ConfigMgrWebService/Constants.cs b/ConfigMgrWebService/Constants.cs new file mode 100644 index 0000000..7c82caa --- /dev/null +++ b/ConfigMgrWebService/Constants.cs @@ -0,0 +1,31 @@ +using System; + +namespace ConfigMgrWebService +{ + public partial class ConfigMgrWebService + { + internal const string COMMON_NAME = "cn"; + internal const string COMPUTER = "computer"; + internal const string DISTINGUISHED_NAME = "distinguishedName"; + internal const string DNS_HOST_NAME = "dNSHostName"; + internal const string NAME = "name"; + internal const string ORG_UNIT = "organizationalUnit"; + internal const string PATH = "path"; + internal const string SAM_ACCOUNT_NAME = "sAMAccountName"; + + private static string[] COMPUTER_PROPERTIES => new string[4] + { + COMMON_NAME, DISTINGUISHED_NAME, DNS_HOST_NAME, SAM_ACCOUNT_NAME + }; + + private static string[] GROUP_PROPERTIES => new string[2] + { + DISTINGUISHED_NAME, SAM_ACCOUNT_NAME + }; + + private static string[] ORG_UNIT_PROPERTIES => new string[3] + { + DISTINGUISHED_NAME, NAME, PATH + }; + } +} \ No newline at end of file