Related
I need to refactor the below code so that the deleted_at logic will be outside of the foreach (var app in data) loop. I tried to create the list guids and then add guids to it but its not working because model.resources is inside the loop and it is still deleting all the apps.
I need deleted_at logic outside because I'm trying to delete all apps which are in the database but are not in new data that I'm receiving from API.
If you have a better approach on my code I would love to see that, Thank you.
public async Task GetBuilds()
{
var data = new List<GetBuildTempClass>();
var guids = new List<GetBuildTempClass>();
using (var scope = _scopeFactory.CreateScope())
{
var _DBcontext = scope.ServiceProvider.GetRequiredService<PCFStatusContexts>();
foreach (var app in data)
{
var request = new HttpRequestMessage(HttpMethod.Get,
"apps/" + app.AppGuid + "/builds?per_page=200&order_by=updated_at");
var response = await _client_SB.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
BuildsClass.BuildsRootObject model =
JsonConvert.DeserializeObject<BuildsClass.BuildsRootObject>(json);
foreach (var item in model.resources)
{
var x = _DBcontext.Builds.FirstOrDefault(o =>
o.Guid == Guid.Parse(item.guid));
if (x == null)
{
_DBcontext.Builds.Add(new Builds
{
Guid = Guid.Parse(item.guid),
State = item.state,
CreatedAt = item.created_at,
UpdatedAt = item.updated_at,
Error = item.error,
CreatedByGuid = Guid.Parse(item.created_by.guid),
CreatedByName = item.created_by.name,
CreatedByEmail = item.created_by.email,
AppGuid = app.AppGuid,
AppName = app.AppName,
Foundation = 2,
Timestamp = DateTime.Now
});
}
else if (x.UpdatedAt != item.updated_at)
{
x.State = item.state;
x.UpdatedAt = item.updated_at;
x.Timestamp = DateTime.Now;
}
var sqlresult = new GetBuildTempClass
{
AppGuid = Guid.Parse(item.guid)
};
guids.Add(sqlresult);
}
//var guids = model.resources.Select(r => Guid.Parse(r.guid));
var builds = _DBcontext.Builds.Where(o =>
guids.Contains(o.Guid) == false &&
o.Foundation == 2 && o.DeletedAt == null);
foreach (var build_item in builds)
{
build_item.DeletedAt = DateTime.Now;
}
}
await _DBcontext.SaveChangesAsync();
}
}
I got it working I added var guids = new List < Guid > (); list to store data,
added guids.Add(Guid.Parse(item.guid)); to populate the list and finally wrote var builds = _DBcontext.Builds.Where(o = >guids.Contains(o.Guid) == false && o.Foundation == 2 && o.DeletedAt == null); outside the loop.
If anyone has a better suggestion please add a new answer.
public async Task GetBuilds() {
var data = new List < GetBuildTempClass > ();
var guids = new List < Guid > ();
using(var scope = _scopeFactory.CreateScope()) {
var _DBcontext = scope.ServiceProvider.GetRequiredService < PCFStatusContexts > ();
foreach(var app in data) {
var request = new HttpRequestMessage(HttpMethod.Get, "apps/" + app.AppGuid + "/builds?per_page=200&order_by=updated_at");
var response = await _client_SB.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
BuildsClass.BuildsRootObject model = JsonConvert.DeserializeObject < BuildsClass.BuildsRootObject > (json);
foreach(var item in model.resources) {
var x = _DBcontext.Builds.FirstOrDefault(o = >o.Guid == Guid.Parse(item.guid));
if (x == null) {
_DBcontext.Builds.Add(new Builds {
Guid = Guid.Parse(item.guid),
State = item.state,
CreatedAt = item.created_at,
UpdatedAt = item.updated_at,
Error = item.error,
CreatedByGuid = Guid.Parse(item.created_by.guid),
CreatedByName = item.created_by.name,
CreatedByEmail = item.created_by.email,
AppGuid = app.AppGuid,
AppName = app.AppName,
Foundation = 2,
Timestamp = DateTime.Now
});
}
else if (x.UpdatedAt != item.updated_at) {
x.State = item.state;
x.UpdatedAt = item.updated_at;
x.Timestamp = DateTime.Now;
}
guids.Add(Guid.Parse(item.guid));
}
}
var builds = _DBcontext.Builds.Where(o = >guids.Contains(o.Guid) == false && o.Foundation == 2 && o.DeletedAt == null);
foreach(var build_item in builds) {
build_item.DeletedAt = DateTime.Now;
}
await _DBcontext.SaveChangesAsync();
}
}
I have got a request from a client to fetch all client user details from AD and finally dump to a db so that they can use it for reporting.
I have used DirectoryEntry and PrincipalContext class to retrieve all the information.The user volume is approx 7500 and and for each user i am binding 35 AD attributes in a list of object.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.IO;
using AccountCheck;
using Microsoft.ActiveDirectory.Management.Commands;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.ComponentModel;
namespace testproj1
{
class Class1
{
//private static DateTime LonTS1;
//static void Main(string[] args)
// public static int LoadADUsers()
static void Main(string[] args)
{
int userCount = 0;
int maxPasswordAge = 90;
string LDAP_QUERY = "LDAP://DC=xyz,DC=com";
string LDAP_FILTER = "(&(objectClass=user)(objectCategory=person))";
//string LDAP_FILTER = "(&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2))";
DirectoryEntry objDirEntry = new DirectoryEntry(LDAP_QUERY);
string[] aryPropertiesToRetrieve =
{"sAMAccountName","Company","whenCreated","department","description","Enabled","displayName","distinguishedName","mail","employeeID","accountExpires", "extensionAttribute11", "extensionAttribute12",
"extensionAttribute13", "extensionAttribute14","extensionAttribute7", "extensionAttribute9","givenName" ,"Initials","title","location","sn","LastLogoff","LastLogon","manager","ChangePasswordAtLogon",
"physicalDeliveryOfficeName", "pwdLastSet","PasswordNeverExpires","PasswordNotRequired","nTSecurityDescriptor","ProtectedFromAccidentalDeletion","usercannotchangepassword","userAccountControl","userPrincipalName","lastlogontimestamp",
};
List<string> adPropertyList = new List<string>(aryPropertiesToRetrieve);
DirectorySearcher objSearch = new DirectorySearcher(objDirEntry, LDAP_FILTER, aryPropertiesToRetrieve);
objSearch.Asynchronous = true;
objSearch.PageSize = 500;
objSearch.SizeLimit = 1000;
objSearch.SearchScope = SearchScope.Subtree;
SearchResultCollection objResults = objSearch.FindAll();
User adUser = new User();
List<User> allUsers = new List<User>();
//NewADObjectParameterSet na = new NewADObjectParameterSet();
//string SQL = string.Empty;
int userAccountControl = 0;
DateTime accountExpiration = DateTime.Now;
//DateTime? accountExpiration;
DateTime passwordLastSet = DateTime.Now;
int daysUntilPasswordExpiration = 0;
DateTime passwordExpiration = DateTime.Now;
int daysUntilAccountExpiration = 0;
double passwordAge = 0;
DateTime? LLon=null;
string Mgr;
bool MCPANL;
string pfcd;
foreach (SearchResult result in objResults)
{
PrincipalContext context = new PrincipalContext(ContextType.Domain);
UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, GetPropertyValue(result, "sAMAccountName").ToString());
//accountExpiration = (DateTime)GetPropertyValue_name(result, "accountExpires", "displayName", "sAMAccountName");
//accountExpiration = (DateTime)GetPropertyValue(result, "accountExpires");
accountExpiration = (DateTime)GetPropertyValue(result, "accountExpires");
//accountExpiration = user.AccountExpirationDate.HasValue ? (DateTime)user.AccountExpirationDate : (DateTime?)null;
daysUntilAccountExpiration = accountExpiration.Subtract(DateTime.Now).Days;
userAccountControl = (int)GetPropertyValue(result, "userAccountControl");
passwordLastSet = (DateTime)GetPropertyValue(result, "pwdLastSet");
pfcd = (string)GetPropertyValue(result, "ProtectedFromAccidentalDeletion");
if (passwordLastSet == null)
{ MCPANL = true; }
else { MCPANL = false; }
Mgr = GetPropertyValue(result, "manager").ToString();
if (Mgr == "" || Mgr == null)
{ Mgr = ""; }
else
{ Mgr = Mgr.Substring(3, Mgr.IndexOf(",") - 3); }
//LLoff = (string)GetPropertyValue(result, "LastLogoff");
// LLon = user.LastLogon.HasValue ? (DateTime)user.LastLogon : (DateTime?) null;
LLon = user.LastLogon;
if (userAccountControl > 10000) //password never expires
{
daysUntilPasswordExpiration = daysUntilAccountExpiration;
passwordExpiration = accountExpiration;
}
else
{
passwordAge = DateTime.Now.Subtract(passwordLastSet).TotalDays;
daysUntilPasswordExpiration = maxPasswordAge - (int)Math.Round(passwordAge + 1);
passwordExpiration = DateTime.Now.AddDays(daysUntilPasswordExpiration);
}
adUser = new User()
{
Name = GetPropertyValue(result, "sAMAccountName").ToString(),
Company = GetPropertyValue(result, "Company").ToString(),
Creation_Date = GetPropertyValue(result, "whenCreated").ToString(),
Department = GetPropertyValue(result, "department").ToString(),
Description = GetPropertyValue(result, "description").ToString(),
Enabled = user.Enabled,
Display_Name = GetPropertyValue(result, "displayName").ToString(),
Distinguished_Name = GetPropertyValue(result, "distinguishedName").ToString(),
Email = GetPropertyValue(result, "mail").ToString(),
EmployeeID = GetPropertyValue(result, "employeeID").ToString(),
Expiration_Date = accountExpiration,
extensionAttribute11 = GetPropertyValue(result, "extensionAttribute11").ToString(),
extensionAttribute12 = GetPropertyValue(result, "extensionAttribute12").ToString(),
extensionAttribute13_Room = GetPropertyValue(result, "extensionAttribute13").ToString(),
extensionAttribute14_Ext = GetPropertyValue(result, "extensionAttribute14").ToString(),
extensionAttribute7_IAM_ID = GetPropertyValue(result, "extensionAttribute7").ToString(),
extensionAttribute9_CostCenter = GetPropertyValue(result, "extensionAttribute9").ToString(),
First_Name = GetPropertyValue(result, "givenName").ToString(),
Initials = GetPropertyValue(result, "Initials").ToString(),
Job_Title = GetPropertyValue(result, "title").ToString(),
//Last_Known_Location = GetPropertyValue(result, "location").ToString(),
Last_Name = GetPropertyValue(result, "sn").ToString(),
// lastLogoff = new DateTime(1601, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(LLoff),
//lastLogoff=
lastLogon = LLon,
Manager = Mgr,
Must_Change_Password_At_Next_Logon = MCPANL,
Office = GetPropertyValue(result, "physicalDeliveryOfficeName").ToString(),
Password_Age_In_Days = passwordAge,
Password_Expiration_Date = passwordExpiration,
Password_Last_Changed = passwordLastSet,
Password_Never_Expire = user.PasswordNeverExpires,
Password_Not_Required = user.PasswordNotRequired,
physicalDeliveryOfficeName = GetPropertyValue(result, "physicalDeliveryOfficeName").ToString(),
//Protected_From_Accidental_Deletion = GetPropertyValue(result, "ProtectedFromAccidentalDeletion").ToString(),
User_Cannot_Change_Password = user.UserCannotChangePassword,
userAccountControl = GetPropertyValue(result, "userAccountControl").ToString(),
Username = GetPropertyValue(result, "userPrincipalName").ToString(),
Username_pre_2000 = GetPropertyValue(result, "sAMAccountName").ToString(),
//lastLogon_value= LLonTS1
};
allUsers.Add(adUser);
userCount++;
//Console.WriteLine("the count is" + userCount);
// Console.ReadLine();
} // end foreach SearchResult loop
string connectionstring = ConfigurationManager.ConnectionStrings["LDAP_ALLUSER"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connectionstring))
{
conn.Open();
string query = "truncate table [dbo].[adlook] ";
SqlCommand cmd1 = new SqlCommand(query, conn);
cmd1.ExecuteNonQuery();
SqlCommand cmd =
new SqlCommand(
"INSERT INTO [dbo].[ADlook] (name, company, creation_date,department,description,enabled,display_name,distinguished_name,email,employeeid,expiration_date,extensionattribute11,extensionattribute12,extensionattribute13_room,extensionattribute14_ext,extensionattribute7_iam_id,extensionattribute9_costcenter,first_name,initials,job_title,last_name,lastlogon,manager,must_change_password_at_next_logon,office,password_age_in_days,password_expiration_date,password_last_changed,password_never_expire,password_not_required,physicaldeliveryofficename,user_cannot_change_password,useraccountcontrol,username,username_pre_2000) " +
" VALUES (#name,#company,#creation_date,#department,#description,#enabled,#display_name,#distinguished_name,#email,#employeeid,#expiration_date,#extensionattribute11,#extensionattribute12,#extensionattribute13_room,#extensionattribute14_ext,#extensionattribute7_iam_id,#extensionattribute9_costcenter,#first_name,#initials,#job_title,#last_name,#lastlogon,#manager,#must_change_password_at_next_logon,#office,#password_age_in_days,#password_expiration_date,#password_last_changed,#password_never_expire,#password_not_required,#physicaldeliveryofficename,#user_cannot_change_password,#useraccountcontrol,#username,#username_pre_2000)");
cmd.CommandType = CommandType.Text;
cmd.Connection = conn;
cmd.Parameters.Add("#name",DbType.String); cmd.Parameters.Add("#company",DbType.String); cmd.Parameters.Add("#creation_date",DbType.DateTime); cmd.Parameters.Add("#department",DbType.String); cmd.Parameters.Add("#description",DbType.String); cmd.Parameters.Add("#enabled",DbType.Boolean);
cmd.Parameters.Add("#display_name",DbType.String); cmd.Parameters.Add("#distinguished_name",DbType.String); cmd.Parameters.Add("#email",DbType.String); cmd.Parameters.Add("#employeeid",DbType.String); cmd.Parameters.Add("#expiration_date",DbType.DateTime); cmd.Parameters.Add("#extensionattribute11",DbType.String);
cmd.Parameters.Add("#extensionattribute12",DbType.String); cmd.Parameters.Add("#extensionattribute13_room",DbType.String); cmd.Parameters.Add("#extensionattribute14_ext",DbType.String); cmd.Parameters.Add("#extensionattribute7_iam_id",DbType.String); cmd.Parameters.Add("#extensionattribute9_costcenter",DbType.String); cmd.Parameters.Add("#first_name",DbType.String);
cmd.Parameters.Add("#initials",DbType.String); cmd.Parameters.Add("#job_title",DbType.String); cmd.Parameters.Add("#last_name",DbType.String); cmd.Parameters.Add("#lastlogon",DbType.DateTime); cmd.Parameters.Add("#manager",DbType.String); cmd.Parameters.Add("#must_change_password_at_next_logon",DbType.Boolean);
cmd.Parameters.Add("#office",DbType.String); cmd.Parameters.Add("#password_age_in_days",DbType.Int32); cmd.Parameters.Add("#password_expiration_date",DbType.DateTime); cmd.Parameters.Add("#password_last_changed",DbType.DateTime); cmd.Parameters.Add("#password_never_expire",DbType.Boolean); cmd.Parameters.Add("#password_not_required",DbType.Boolean);
cmd.Parameters.Add("#physicaldeliveryofficename",DbType.String); cmd.Parameters.Add("#user_cannot_change_password",DbType.Boolean); cmd.Parameters.Add("#useraccountcontrol",DbType.String); cmd.Parameters.Add("#username",DbType.String); cmd.Parameters.Add("#username_pre_2000",DbType.String);
foreach (var item in allUsers)
{
cmd.Parameters[0].Value = item.Name; cmd.Parameters[1].Value = item.Company; cmd.Parameters[2].Value = item.Creation_Date; cmd.Parameters[3].Value = item.Department; cmd.Parameters[4].Value = item.Description;
cmd.Parameters[5].Value = item.Enabled; cmd.Parameters[6].Value = item.Display_Name; cmd.Parameters[7].Value = item.Distinguished_Name; cmd.Parameters[8].Value = item.Email; cmd.Parameters[9].Value = item.EmployeeID;
cmd.Parameters[10].Value = item.Expiration_Date; cmd.Parameters[11].Value = item.extensionAttribute11; cmd.Parameters[12].Value = item.extensionAttribute12; cmd.Parameters[13].Value = item.extensionAttribute13_Room; cmd.Parameters[14].Value = item.extensionAttribute14_Ext;
cmd.Parameters[15].Value = item.extensionAttribute7_IAM_ID; cmd.Parameters[16].Value = item.extensionAttribute9_CostCenter; cmd.Parameters[17].Value = item.First_Name; cmd.Parameters[18].Value = item.Initials; cmd.Parameters[19].Value = item.Job_Title;
cmd.Parameters[20].Value = item.Last_Name;cmd.Parameters[21].Value = (object)item.lastLogon ?? DBNull.Value;cmd.Parameters[22].Value = item.Manager; cmd.Parameters[23].Value = item.Must_Change_Password_At_Next_Logon; cmd.Parameters[24].Value = item.Office;
cmd.Parameters[25].Value = item.Password_Age_In_Days; cmd.Parameters[26].Value = item.Password_Expiration_Date; cmd.Parameters[27].Value = item.Password_Last_Changed; cmd.Parameters[28].Value = item.Password_Never_Expire; cmd.Parameters[29].Value = item.Password_Not_Required;
cmd.Parameters[30].Value = item.physicalDeliveryOfficeName; cmd.Parameters[31].Value = item.User_Cannot_Change_Password; cmd.Parameters[32].Value = item.userAccountControl; cmd.Parameters[33].Value = item.Username; cmd.Parameters[34].Value = item.Username_pre_2000;
cmd.ExecuteNonQuery();
}
conn.Close();
}
}
///////////////////////////////////////// 1st method starts
private static object GetPropertyValue(SearchResult result, string propertyName)
{
object propValue = null;
if (result.Properties.Contains(propertyName))
{
if (result.Properties[propertyName].Count > 0)
{
propValue = result.Properties[propertyName][0];
if (propertyName == "accountExpires" || propertyName == "pwdLastSet")
{
long dateValue = (long)propValue;
long maxDate = DateTime.MaxValue.ToFileTime();
if (dateValue == 0 || dateValue > maxDate || dateValue == null) //never expires
{
propValue = Convert.ToDateTime("12/31/2100"); //new DateTime(2100, 12, 31);
}
else //expires
{
propValue = DateTime.FromFileTime(dateValue);
}
}
}
}
else
{
propValue = string.Empty;
}
return propValue;
}
////////////////////////////// 1st method ends
}
}
there are no errors as of now and it is just code that takes long to retrieve information.`
The code iterates each user and adds the to the object allUsers.
It takes approximately 13mins to add all users to this object which seems like a long time and will appreciate if someone can help me if i am doing anything wrong in coding part.
i have wrote a User class where all the property definitions are there and connection string to dump into db is being inherited from App.Config.
In the below code *****allUsers.Add(adUser)*****; is the part where it will add one by one user details and until it adds all users (almost 7500) , it takes at-least 14 mins of time.
Please help so that i can do any changes to code to make this process faster and i can add all user data in the object faster.
There is more than One way to Access LDAP Data and They perform diffrent in Diffrent enviorments. I use This Method and its pretty fast. May be you wanna give it a try.
var context = new PrincipalContext(ContextType.Domain, "yourdomainasaString");
var qbeUser = new UserPrincipal(context);
var searcher = new PrincipalSearcher(qbeUser);
foreach (DirectoryEntry de in searcher.FindAll().Select(x => x.GetUnderlyingObject()))
{
var tmpsid = de.Properties["objectSid"].Value;
var tmproles = de.Properties["memberof"].Value;
var IsActive = de.Properties["userAccountControl"][0].ToString() != "514";
//And So on
}
I have a group, lets call it GotRocks. I am attempting to get all of its members, but I am getting wildly different results count-wise between DirectoryEntry and AccountManagement. Below are the counts by member retrieval method:
Method 1: DirectoryEntry.PropertyName.member = 350
Method 2: AccountManagement.GroupPrincipal.GetMembers(false) = 6500
Method 2: AccountManagement.GroupPrincipal.GetMembers(true) = 6500
As a sanity check, I went into ADUC and pulled the list of members from the group, which is limited to 2,000 by default. The important thing here is that ADUC seems to validate the AccountManagement result. I have checked the Children property as well, but it is blank. Also, none of the members listed in DirectoryEntry are of the SchemaName group - they are all users.
I do not think this is a code problem, but perhaps a lack of understanding of how DirectoryEntry and the GetMembers methods retrieve group members. Can anyone explain why the DirectoryEntry member list would yield a different result from the GetMembers recursive function? Is there a certain method or property I need to be aware of? Note: I have built a function that will query DirectoryEntry by "member;range={0}-{1}" where the loop gets members in chunks of 1,500. I am at a complete and utter loss here.
The fact that DirectoryEntry is returning so few results is problematic because I want to use DirectoryEntry for the simple fact that going this route is, at a minimum, two orders of magnitude faster than AccountManagement (i.e., stopwatch times of 1,100 milliseconds versus 250,000 milliseconds).
UPDATE 1: Methods:
Method 1: DirectoryEntry
private List<string> GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize)
{
// Variable declaration(s).
List<string> listGroupMemberDn = new List<string>();
string strPath = strActiveDirectoryHost + "/<GUID=" + strPropertyValue + ">";
string strMemberPropertyRange = null;
DirectoryEntry directoryEntryGroup = null;
DirectorySearcher directorySearcher = null;
SearchResultCollection searchResultCollection = null;
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms676302(v=vs.85).aspx
const int intIncrement = 1500;
// Load the DirectoryEntry.
try
{
directoryEntryGroup = new DirectoryEntry(strPath, null, null, AuthenticationTypes.Secure);
directoryEntryGroup.RefreshCache();
}
catch (Exception)
{ }
try
{
if (directoryEntryGroup.Properties["member"].Count > 0)
{
int intStart = 0;
while (true)
{
int intEnd = intStart + intIncrement - 1;
// Define the PropertiesToLoad attribute, which contains a range flag that LDAP uses to get a list of members in a pre-specified chunk/block of members that is defined by each loop iteration.
strMemberPropertyRange = string.Format("member;range={0}-{1}", intStart, intEnd);
directorySearcher = new DirectorySearcher(directoryEntryGroup)
{
Filter = "(|(objectCategory=person)(objectCategory=computer)(objectCategory=group))", // User, Contact, Group, Computer objects
SearchScope = SearchScope.Base,
PageSize = intActiveDirectoryPageSize,
PropertiesToLoad = { strMemberPropertyRange }
};
try
{
searchResultCollection = directorySearcher.FindAll();
foreach (SearchResult searchResult in searchResultCollection)
{
var membersProperties = searchResult.Properties;
// Find the property that starts with the PropertyName of "member;" and get all of its member values.
var membersPropertyNames = membersProperties.PropertyNames.OfType<string>().Where(n => n.StartsWith("member;"));
// For each record in the memberPropertyNames, get the PropertyName and add to the lest.
foreach (var propertyName in membersPropertyNames)
{
var members = membersProperties[propertyName];
foreach (string memberDn in members)
{
listGroupMemberDn.Add(memberDn);
}
}
}
}
catch (DirectoryServicesCOMException)
{
// When the start of the range exceeds the number of available results, an exception is thrown and we exit the loop.
break;
}
intStart += intIncrement;
}
}
return listGroupMemberDn;
}
finally
{
listGroupMemberDn = null;
strPath = null;
strMemberPropertyRange = null;
directoryEntryGroup.Close();
if(directoryEntryGroup != null) directoryEntryGroup.Dispose();
if (directorySearcher != null) directorySearcher.Dispose();
if(searchResultCollection != null) searchResultCollection.Dispose();
}
}
Method 2: AccountManagement (toggle bolRecursive as either true or false).
private List<Guid> GetGroupMemberList(string strPropertyValue, string strDomainController, bool bolRecursive)
{
// Variable declaration(s).
List<Guid> listGroupMemberGuid = null;
GroupPrincipal groupPrincipal = null;
PrincipalSearchResult<Principal> listPrincipalSearchResult = null;
List<Principal> listPrincipalNoNull = null;
PrincipalContext principalContext = null;
ContextType contextType;
IdentityType identityType;
try
{
listGroupMemberGuid = new List<Guid>();
contextType = ContextType.Domain;
principalContext = new PrincipalContext(contextType, strDomainController);
// Setup the IdentityType. Use IdentityType.Guid because GUID is unique and never changes for a given object. Make sure that is what strPropertyValue is receiving.
// This is required, otherwise you will get a MultipleMatchesException error that says "Multiple principals contain a matching Identity."
// This happens when you have two objects that AD thinks match whatever you're passing to UserPrincipal.FindByIdentity(principalContextDomain, strPropertyValue)
identityType = IdentityType.Guid;
groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, identityType, strPropertyValue);
if (groupPrincipal != null)
{
// Get all members that the group contains and add it to the list.
// Note: The true flag in GetMembers() specifies a recursive search, which enables the application to search a group recursively and return only principal objects that are leaf nodes.
listPrincipalSearchResult = groupPrincipal.GetMembers(bolRecursive);
// Remove the nulls from the list, otherwise the foreach loop breaks prematurly on the first null found and misses all other object members.
listPrincipalNoNull = listPrincipalSearchResult.Where(item => item.Name != null).ToList();
foreach (Principal principal in listPrincipalNoNull)
{
listGroupMemberGuid.Add((Guid)principal.Guid);
}
}
return listGroupMemberGuid;
}
catch (MultipleMatchesException)
{
// Multiple principals contain a matching identity.
// In other words, the same property value was found on more than one record in either of the six attributes that are listed within the IdentityType enum.
throw new MultipleMatchesException(strPropertyValue);
}
finally
{
// Cleanup objects.
listGroupMemberGuid = null;
if(listPrincipalSearchResult != null) listPrincipalSearchResult.Dispose();
if(principalContext != null) principalContext.Dispose();
if(groupPrincipal != null) groupPrincipal.Dispose();
}
}
UPDATE 2:
public static void Main()
{
Program objProgram = new Program();
// Other stuff here.
objProgram.GetAllUserSingleDc();
// Other stuff here.
}
private void GetAllUserSingleDc()
{
string strDomainController = "domain.com";
string strActiveDirectoryHost = "LDAP://" + strDomainController;
int intActiveDirectoryPageSize = 1000;
string[] strAryRequiredProperties = null;
DirectoryEntry directoryEntry = null;
DirectorySearcher directorySearcher = null;
SearchResultCollection searchResultCollection = null;
DataTypeConverter objConverter = null;
Type fieldsType = null;
fieldsType = typeof(AdUserInfoClass);
objConverter = new DataTypeConverter();
directoryEntry = new DirectoryEntry(strActiveDirectoryHost, null, null, AuthenticationTypes.Secure);
directorySearcher = new DirectorySearcher(directoryEntry)
{
//Filter = "(|(objectCategory=person)(objectCategory=computer)(objectCategory=group))", // User, Contact, Group, Computer objects
Filter = "(sAMAccountName=GotRocks)", // Group
SearchScope = SearchScope.Subtree,
PageSize = intActiveDirectoryPageSize
PropertiesToLoad = { "isDeleted","isCriticalSystemObject","objectGUID","objectSid","objectCategory","sAMAccountName","sAMAccountType","cn","employeeId",
"canonicalName","distinguishedName","userPrincipalName","displayName","givenName","sn","mail","telephoneNumber","title","department",
"description","physicalDeliveryOfficeName","manager","userAccountControl","accountExpires","lastLogon","logonCount","lockoutTime",
"primaryGroupID","pwdLastSet","uSNCreated","uSNChanged","whenCreated","whenChanged","badPasswordTime","badPwdCount","homeDirectory",
"dNSHostName" }
};
searchResultCollection = directorySearcher.FindAll();
try
{
foreach (SearchResult searchResult in searchResultCollection)
{
clsAdUserInfo.GidObjectGuid = objConverter.ConvertByteAryToGuid(searchResult, "objectGUID");
clsAdUserInfo.StrDirectoryEntryPath = strActiveDirectoryHost + "/<GUID=" + clsAdUserInfo.GidObjectGuid + ">";
clsAdUserInfo.StrSchemaClassName = new DirectoryEntry(clsAdUserInfo.StrDirectoryEntryPath, null, null, AuthenticationTypes.Secure).SchemaClassName;
if (clsAdUserInfo.StrSchemaClassName == "group")
{
// Calling the functions here.
List<string> listGroupMemberDnMethod1 = GetGroupMemberListStackOverflow(clsAdUserInfo.GidObjectGuid.ToString(), strActiveDirectoryHost, intActiveDirectoryPageSize);
List<Guid> listGroupMemberGuidMethod2 = GetGroupMemberList(clsAdUserInfo.GidObjectGuid.ToString(), strDomainController, false)
}
// More stuff here.
}
}
finally
{
// Cleanup objects.
// Class constructors.
objProgram = null;
clsAdUserInfo = null;
// Variables.
intActiveDirectoryPageSize = -1;
strActiveDirectoryHost = null;
strDomainController = null;
strAryRequiredProperties = null;
directoryEntry.Close();
if(directoryEntry !=null) directoryEntry.Dispose();
if(directorySearcher != null) directorySearcher.Dispose();
if(searchResultCollection != null) searchResultCollection.Dispose();
objConverter = null;
fieldsType = null;
}
}
UPDATE 3:
Below is the list of namespaces that I am using.
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.Security.Principal;
using System.Text;
using System.Linq;
using System.Collections;
UPDATE 4: Program.cs
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.Security.Principal;
using System.Text;
using System.Linq;
namespace activeDirectoryLdapExamples
{
public class Program
{
public static void Main()
{
Program objProgram = new Program();
objProgram.GetAllUserSingleDc();
}
#region GetAllUserSingleDc
private void GetAllUserSingleDc()
{
Program objProgram = new Program();
string strDomainController = "EnterYourDomainhere";
string strActiveDirectoryHost = "LDAP://" + strDomainController;
int intActiveDirectoryPageSize = 1000;
DirectoryEntry directoryEntry = null;
DirectorySearcher directorySearcher = null;
SearchResultCollection searchResultCollection = null;
DataTypeConverter objConverter = null;
objConverter = new DataTypeConverter();
directoryEntry = new DirectoryEntry(strActiveDirectoryHost, null, null, AuthenticationTypes.Secure);
directorySearcher = new DirectorySearcher(directoryEntry)
{
Filter = "(sAMAccountName=GotRocks)", // Group
SearchScope = SearchScope.Subtree,
PageSize = intActiveDirectoryPageSize,
PropertiesToLoad = { "isDeleted","isCriticalSystemObject","objectGUID","objectSid","objectCategory","sAMAccountName","sAMAccountType","cn","employeeId",
"canonicalName","distinguishedName","userPrincipalName","displayName","givenName","sn","mail","telephoneNumber","title","department",
"description","physicalDeliveryOfficeName","manager","userAccountControl","accountExpires","lastLogon","logonCount","lockoutTime",
"primaryGroupID","pwdLastSet","uSNCreated","uSNChanged","whenCreated","whenChanged","badPasswordTime","badPwdCount","homeDirectory",
"dNSHostName" }
};
searchResultCollection = directorySearcher.FindAll();
try
{
foreach (SearchResult searchResult in searchResultCollection)
{
Guid? gidObjectGuid = objConverter.ConvertByteAryToGuid(searchResult, "objectGUID");
string StrSamAccountName = objConverter.ConvertToString(searchResult, "sAMAccountName");
// Get new DirectoryEntry and retrieve the SchemaClassName from it by binding the current objectGUID to it.
string StrDirectoryEntryPath = strActiveDirectoryHost + "/<GUID=" + gidObjectGuid + ">";
string StrSchemaClassName = new DirectoryEntry(StrDirectoryEntryPath, null, null, AuthenticationTypes.Secure).SchemaClassName;
#region GetGroupMembers
if (StrSchemaClassName == "group")
{
// FAST!
var watch = System.Diagnostics.Stopwatch.StartNew();
List<string> listGroupMemberDn = GetGroupMemberList(gidObjectGuid.ToString(), strActiveDirectoryHost, intActiveDirectoryPageSize);
watch.Stop();
var listGroupMemberDnElapsedMs = watch.ElapsedMilliseconds;
// SLOW!
watch = System.Diagnostics.Stopwatch.StartNew();
List<Guid> listGroupMemberGuidRecursiveTrue = GetGroupMemberList(gidObjectGuid.ToString(), strDomainController, true);
watch.Stop();
var listGroupMemberGuidRecursiveTrueElapsedMs = watch.ElapsedMilliseconds;
watch = System.Diagnostics.Stopwatch.StartNew();
List<Guid> listGroupMemberGuidRecursiveFalse = GetGroupMemberList(gidObjectGuid.ToString(), strDomainController, false);
watch.Stop();
var listGroupMemberGuidRecursiveFalseElapsedMs = watch.ElapsedMilliseconds;
////// Display all members of the list.
//listGroupMemberDn.ForEach(item => Console.WriteLine("Member GUID: {0}", item));
//listGroupMemberGuidRecursiveTrue.ForEach(item => Console.WriteLine("Member GUID: {0}", item));
//listGroupMemberGuidRecursiveFalse.ForEach(item => Console.WriteLine("Member GUID: {0}", item));
Console.WriteLine("objectGUID: {0}", gidObjectGuid);
Console.WriteLine("sAMAccountName: {0}", strSamAccountName);
// Result: 350
Console.WriteLine("\nlistGroupMemberDn Count Members: {0}", listGroupMemberDn.Count);
Console.WriteLine("Total RunTime listGroupMemberDnElapsedMs (in milliseconds): {0}", listGroupMemberDnElapsedMs);
// Result: 6500
Console.WriteLine("\nlistGroupMemberGuidRecursiveTrue Count Members: {0}", listGroupMemberGuidRecursiveTrue.Count);
Console.WriteLine("Total RunTime listGroupMemberGuidRecursiveTrueElapsedMs (in milliseconds): {0}", listGroupMemberGuidRecursiveTrueElapsedMs);
// Result: 6500
Console.WriteLine("\nlistGroupMemberGuidRecursiveFalse Count Members: {0}", listGroupMemberGuidRecursiveFalse.Count);
Console.WriteLine("Total RunTime listGroupMemberGuidRecursiveFalseElapsedMs (in milliseconds): {0}", listGroupMemberGuidRecursiveFalseElapsedMs);
Console.WriteLine("\n");
}
#endregion
#region CurrentSearchResult
else
{
Console.WriteLine("ObjectGuid = {0}", gidObjectGuid);
Console.WriteLine("SamAccountName = {0}", strSamAccountName);
}
#endregion
}
Console.WriteLine("\nPress any key to continue.");
Console.ReadKey();
}
finally
{
objProgram = null;
intActiveDirectoryPageSize = -1;
strActiveDirectoryHost = null;
strDomainController = null;
directoryEntry.Close();
if (directoryEntry != null) directoryEntry.Dispose();
if (directorySearcher != null) directorySearcher.Dispose();
if (searchResultCollection != null) searchResultCollection.Dispose();
objConverter = null;
}
}
#endregion
#region GetGroupMemberListGuid
private List<Guid> GetGroupMemberList(string strPropertyValue, string strDomainController, bool bolRecursive)
{
List<Guid> listGroupMemberGuid = null;
List<Principal> listPrincipalNoNull = null;
GroupPrincipal groupPrincipal = null;
PrincipalSearchResult<Principal> listPrincipalSearchResult = null;
PrincipalContext principalContext = null;
ContextType contextType;
IdentityType identityType;
try
{
listGroupMemberGuid = new List<Guid>();
contextType = ContextType.Domain;
principalContext = new PrincipalContext(contextType, strDomainController);
identityType = IdentityType.Guid;
groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, identityType, strPropertyValue);
if (groupPrincipal != null)
{
listPrincipalSearchResult = groupPrincipal.GetMembers(bolRecursive);
listPrincipalNoNull = listPrincipalSearchResult.Where(item => item.Name != null).ToList();
foreach (Principal principal in listPrincipalNoNull)
{
listGroupMemberGuid.Add((Guid)principal.Guid);
}
}
return listGroupMemberGuid;
}
catch (MultipleMatchesException)
{
throw new MultipleMatchesException(strPropertyValue);
}
finally
{
// Cleanup objects.
listGroupMemberGuid = null;
listPrincipalNoNull = null;
principalContext = null;
if (groupPrincipal != null) groupPrincipal.Dispose();
if (listPrincipalSearchResult != null) listPrincipalSearchResult.Dispose();
if (principalContext != null) principalContext.Dispose();
}
}
#endregion
#region GetGroupMemberListDn
private List<string> GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize)
{
List<string> listGroupMemberDn = new List<string>();
string strPath = strActiveDirectoryHost + "/<GUID=" + strPropertyValue + ">";
const int intIncrement = 1500; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms676302(v=vs.85).aspx
var members = new List<string>();
// The count result returns 350.
var group = new DirectoryEntry(strPath, null, null, AuthenticationTypes.Secure);
//var group = new DirectoryEntry($"LDAP://{"EnterYourDomainHere"}/<GUID={strPropertyValue}>", null, null, AuthenticationTypes.Secure);
while (true)
{
var memberDns = group.Properties["member"];
foreach (var member in memberDns)
{
members.Add(member.ToString());
}
if (memberDns.Count < intIncrement) break;
group.RefreshCache(new[] { $"member;range={members.Count}-*" });
}
return members;
}
#endregion
#region DataTypeConvert
private class DataTypeConverter
{
public DataTypeConverter() { }
public String ConvertToString(SearchResult searchResult, string strPropertyName)
{
String bufferObjectString = null;
try
{
bufferObjectString = (String)this.GetPropertyValue(searchResult, strPropertyName);
if (string.IsNullOrEmpty(bufferObjectString))
{
return null;
}
else
{
return bufferObjectString;
}
}
finally
{
bufferObjectString = null;
}
}
public Guid? ConvertByteAryToGuid(SearchResult searchResult, string strPropertyName)
{
Guid? bufferObjectGuid = null;
try
{
bufferObjectGuid = new Guid((Byte[])(Array)this.GetPropertyValue(searchResult, strPropertyName));
if (bufferObjectGuid == null || bufferObjectGuid == Guid.Empty)
{
throw new NullReferenceException("The field " + strPropertyName + ", of type GUID, can neither be NULL nor empty.");
}
else
{
return bufferObjectGuid;
}
}
finally
{
bufferObjectGuid = null;
}
}
}
#endregion
}
}
The last code block (Update 2) is the answer!
The code you have for reading the member attribute is more complicated than it needs to be. There may be a reason in there why it's returning skewed results, but I didn't look too hard because you don't need to be using DirectorySearcher at all. I just rewrote it.
Here is what it should look like, in it's simplest form:
private static List<string> GetGroupMemberList(string groupGuid, string domainDns) {
var members = new List<string>();
var group = new DirectoryEntry($"LDAP://{domainDns}/<GUID={groupGuid}>", null, null, AuthenticationTypes.Secure);
while (true) {
var memberDns = group.Properties["member"];
foreach (var member in memberDns) {
members.Add(member.ToString());
}
if (memberDns.Count == 0) break;
try {
group.RefreshCache(new[] {$"member;range={members.Count}-*", "member"});
} catch (System.Runtime.InteropServices.COMException e) {
if (e.ErrorCode == unchecked((int) 0x80072020)) { //no more results
break;
}
throw;
}
}
return members;
}
Call it like this:
var members = GetGroupMemberList("00000000-0000-0000-0000-000000000000", "domain.com");
This is not recursive. To make it recursive, you will have to create a new DirectoryEntry from each member and test if it is a group, then get the members of that group.
I have the code open, so here's the recursive version. It is slow because it has to bind to each member to see if it's a group.
This is not bullet-proof. There are still cases where you might get weird results (like if you have users on trusted external domains in a group).
private static List<string> GetGroupMemberList(string groupGuid, string domainDns, bool recurse = false) {
var members = new List<string>();
var group = new DirectoryEntry($"LDAP://{domainDns}/<GUID={groupGuid}>", null, null, AuthenticationTypes.Secure);
while (true) {
var memberDns = group.Properties["member"];
foreach (var member in memberDns) {
if (recurse) {
var memberDe = new DirectoryEntry($"LDAP://{member}");
if (memberDe.Properties["objectClass"].Contains("group")) {
members.AddRange(GetGroupMemberList(
new Guid((byte[]) memberDe.Properties["objectGuid"].Value).ToString(), domainDns,
true));
} else {
members.Add(member.ToString());
}
} else {
members.Add(member.ToString());
}
}
if (memberDns.Count == 0) break;
try {
group.RefreshCache(new[] {$"member;range={members.Count}-*", "member"});
} catch (System.Runtime.InteropServices.COMException e) {
if (e.ErrorCode == unchecked((int) 0x80072020)) { //no more results
break;
}
throw;
}
}
return members;
}
Update:
I did have to edit your GetMembers example, since it kept throwing exceptions on me. I commented out the .Where line and changed the foreach loop that adds the members to the list:
//listPrincipalNoNull = listPrincipalSearchResult.Where(item => item.Name != null).ToList();
if (groupPrincipal != null) {
foreach (Principal principal in listPrincipalSearchResult) {
listGroupMemberGuid.Add(((DirectoryEntry)principal.GetUnderlyingObject()).Guid);
}
}
This, of course, is compiling a list of Guids rather than DNs.
Update 2: Here is a version that also pulls users who have the group as the primary group (but not listed in the member attribute of the group). GetMembers seems to do this. It would be odd for a user-created group to be the primary group, but it is technically possible. Parts of this are copied from the answer here: How to retrieve Users in a Group, including primary group users
private List<string> GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize)
{
// Variable declaration(s).
List<string> listGroupMemberDn = new List<string>();
string strPath = strActiveDirectoryHost + "/<GUID=" + strPropertyValue + ">";
const int intIncrement = 1500; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms676302(v=vs.85).aspx
var members = new List<string>();
// The count result returns 350.
var group = new DirectoryEntry(strPath, null, null, AuthenticationTypes.Secure);
//var group = new DirectoryEntry($"LDAP://{"EnterYourDomainHere"}/<GUID={strPropertyValue}>", null, null, AuthenticationTypes.Secure);
while (true)
{
var memberDns = group.Properties["member"];
foreach (var member in memberDns)
{
members.Add(member.ToString());
}
if (memberDns.Count < intIncrement) break;
group.RefreshCache(new[] { $"member;range={members.Count}-*" });
}
//Find users that have this group as a primary group
var secId = new SecurityIdentifier(group.Properties["objectSid"][0] as byte[], 0);
/* Find The RID (sure exists a best method)
*/
var reg = new Regex(#"^S.*-(\d+)$");
var match = reg.Match(secId.Value);
var rid = match.Groups[1].Value;
/* Directory Search for users that has a particular primary group
*/
var dsLookForUsers =
new DirectorySearcher {
Filter = string.Format("(primaryGroupID={0})", rid),
SearchScope = SearchScope.Subtree,
PageSize = 1000,
SearchRoot = new DirectoryEntry(strActiveDirectoryHost)
};
dsLookForUsers.PropertiesToLoad.Add("distinguishedName");
var srcUsers = dsLookForUsers.FindAll();
foreach (SearchResult user in srcUsers)
{
members.Add(user.Properties["distinguishedName"][0].ToString());
}
return members;
}
I am using Active Directory to return a list of Users in a autocomplete input field. The issue I am having when the user types the name of a group it returns data. Ideally what I would like is to only show Users, not groups. Is this possible? Would appreciate your help. Thanks in advance.
public List<Client> Search(string name)
{
List<Client> results = new List<Client>();
string domainname = "domain";
string rootQuery = "LDAP://domain.com/DC=domain,DC=com";
name = name + "*";
using (DirectoryEntry root = new DirectoryEntry(rootQuery))
{
domainname = root.Properties["Name"].Value.ToString();
using (DirectorySearcher searcher = new DirectorySearcher(root))
{
//searcher.Filter = "(ObjectClass=" + name + ")"; //searchFilter;
searcher.Filter = "(SAMAccountName=" + name + ")"; //searchFilter;
searcher.PropertiesToLoad.Add("displayName");
searcher.PropertiesToLoad.Add("sAMAccountName");
searcher.PropertiesToLoad.Add("mail");
SearchResultCollection src = searcher.FindAll();
foreach (SearchResult sr in src)
{
Client r = new Client();
r.domain = domainname;
// Iterate through each property name in each SearchResult.
foreach (string propertyKey in sr.Properties.PropertyNames)
{
ResultPropertyValueCollection valueCollection = sr.Properties[propertyKey];
if (propertyKey == "mail")
{
foreach (Object propertyValue in valueCollection)
{
r.email = propertyValue.ToString();
}
}
if (propertyKey == "displayname")
{
foreach (Object propertyValue in valueCollection)
{
r.name = propertyValue.ToString();
}
}
if (propertyKey == "samaccountname")
{
foreach (Object propertyValue in valueCollection)
{
r.loginName = propertyValue.ToString();
}
}
}
if (r.name != null && r.email != null)
{
results.Add(r);
}
}
}
}
return results;
}
How do I get users list from trusted domain?
I have tried to run a LDAP query but I am not able to get users from trusted domain. This is my code:
public virtual List<UserModel> SearchUsers(string textValue)
{
var users = new List<UserModel>();
string context;
const string nameProperty = "name";
const string samAccountNameProperty = "samaccountname";
const string distinguishedNameProperty = "distinguishedname";
if (textValue.Contains("(").Equals(true) || textValue.Contains(")").Equals(true) || textValue.Contains("*").Equals(true))
{
textValue = EscapeInvalidCharacters(textValue);
}
var filterForDomainUser ="(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(|(samaccountname=" + textValue + "*)(name=" + textValue + "*)))";
using (HostingEnvironment.Impersonate())
{
using (var root = new DirectoryEntry("LDAP://RootDSE"))
{
context = root.Properties["defaultNamingContext"].Value.ToString();
}
using (var entry = new DirectoryEntry("GC://" + context))
{
using (
var search = new DirectorySearcher(entry,filterForDomainUser,
new[]
{
samAccountNameProperty, nameProperty,
distinguishedNameProperty
}, SearchScope.Subtree))
{
search.ReferralChasing = ReferralChasingOption.All;
search.PageSize = 10;
var resultCol = search.FindAll();
for (var counter = 0; counter < resultCol.Count; counter++)
{
var result = resultCol[counter];
var distinguishedName = (String)result.Properties[distinguishedNameProperty][0];
var domainName =
distinguishedName.Substring(distinguishedName.IndexOf("DC=",
StringComparison
.InvariantCultureIgnoreCase))
.Split(',')[0].Replace("DC=", "");
var name = (String)result.Properties[nameProperty][0];
var samAccountName = string.Format("{0}{1}{2}", domainName, #"\",
result.Properties[samAccountNameProperty][0]);
var userModel = new UserModel
{
DisplayName = name,
UserName = samAccountName
};
users.Add(userModel);
}
}
}
}
//SearchLocalUser(textValue, users);
return users;
}