I have a method that searches Active Directory for Usernames based on an email address. There are cases where there may be multiple usernames for a given email address, and I'm trying to capture those. I have rewritten my method, but can't seem to get the syntax quite right. the issue is this line I believe.
foreach (Object myObject in result.Properties[property])
thanks,
Jason
private String FindNameByEmail(string emailAddress)
{
DirectoryEntry entry = GetDirectoryEntry();
emailAddress = txtEmailID.Text;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(&(objectCategory=person)(sAMAccountName=*)(mail=" + emailAddress + "))";
string[] properties = new string[] { "SAMAccountName" };
foreach (String property in properties)
search.PropertiesToLoad.Add(property);
SearchResultCollection result = search.FindAll();
if (result != null)
{
foreach (String property in properties)
foreach (Object myObject in result.Properties[property])
lblUserName.Text = myObject.ToString();
return "User Found";
}
else
{
lblStatus.Text = "user does not exist";
return "User Does Not Exist";
}
}
EDIT: Changed it to output to a list of strings
Here we go:
List<string> usernames = new List<string>();
if (result != null)
{
foreach (SearchResult sr in result)
{
usernames.Add((string)sr.Properties["SAMAccountName"][0]);
}
}
listBox1.DataSource = usernames; //Where listbox is declared in your markup
listBox1.DataBind();
Just Replace your if (result != null) logic with myne
Related
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;
}
I'm doing a Query for a certain user in AD and looking to create a list of multiple properties. Code Below. When I do searchResult.Properties["manager"] or searchResult.Properties["mail"] i get the correct result each way. But how would i search for multiple properties?
DirectoryEntry dEntry = new DirectoryEntry(path);
DirectorySearcher dSearcher = new DirectorySearcher(dEntry);
dSearcher.Filter = "(&(ObjectClass=user)(samaccountname=mcavanaugh))";
sResults = dSearcher.FindAll();
foreach (SearchResult searchResult in sResults)
{
var sAMAccountName = searchResult.Properties["samaccountname"][0].ToString().ToLower();
if (sAMAccountName == "mcavanaugh")
{
//Right here is where i would select multiple ad properties
ResultPropertyValueCollection valueCollection = searchResult.Properties["manager, mail"];
foreach (Object propertyValue in valueCollection)
{
var PropertyName = (string)propertyValue.ToString();
testlist.Text = PropertyName;
}
}
}
The Properties property doesn't have an option to access multiple properties at once. Mixing the values from different properties doesn't seem wise. Your best solution is to run the foreach twice, possibly creating a function to be DRY.
void addPropertyValues<T>(SearchResult sr, T testlist, string propName) {
foreach (var pv in sr[propName]) {
testlist.Text = pv.ToString();
}
}
which you can use in your if
if (sAMAccountName == "mcavanaugh") {
addPropertyValues(searchResult, testlist, "manager");
addPropertyValues(searchResult, testlist, "mail");
}
I've been working with this lately. I found where to place multiple properties and put them into an array, assigning them to properties. It's been working out pretty well so far. :
DirectoryEntry myLdapConnection = new DirectoryEntry("LDAP://DC=demo,DC=Com");
DirectorySearcher search = new DirectorySearcher(myLdapConnection);
search.Filter = "(sAMAccountName=" + username + ")";
string[] requiredProperties = new string[] { "cn", "Displayname", "Title", "Department", "l", "Homedirectory", "telephoneNumber", "lockoutTime", "badlogoncount", "passwordexpired", "badPasswordTime", "whenCreated", "sAMAccountName", "pwdLastSet", "thumbnailPhoto", "givenName", "sn", "mail", "msRTCSIP-PrimaryUserAddress", "distinguishedName", "manager" };
foreach(String property in requiredProperties)
search.PropertiesToLoad.Add(property);
//next code will output to a usertextbox that I had set up in a Form. You can convert to console.writeline
if (searchResult != null) {
foreach(String property in requiredProperties)
foreach(Object myCollection in searchResult.Properties[property])
UserTextbox.Text += "\r\n" + (String.Format("{0,0} : {1} : {2}", property, myCollection.ToString(), myCollection.GetType().ToString()));
}
I'm learning C# and am a novice. Please be patient with me.
I've developed an app in C# to search for users, groups, and group members in AD by Piping PowerShell commands into it.
Now I'm trying to use DirectoryServices in C# to get the same results, however the time it take to get the same results back is much longer than it is in PowerShell.
Here is what I am doing now with DirectoryServices for a quick test:
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
private void button1_Click(object sender, EventArgs e)
{
string textbox = textBox1.Text.ToString();
listBox1.Items.Clear();
listView1.Items.Clear();
listView1.Columns.Clear();
try
{
// Bind to the object for which to retrieve property data.
DirectoryEntry de = new DirectoryEntry("");
DirectorySearcher ds = new DirectorySearcher(de);
ds.Filter = "(&(objectClass=Group)(cn="+ textbox + "))";
ds.SearchScope = SearchScope.Subtree;
SearchResultCollection rsAll = ds.FindAll();
listView1.Columns.Add("samsaccountname");
string samsaccountname = "";
foreach (SearchResult searchresult in rsAll)
{
if (searchresult.GetDirectoryEntry().Properties["samaccountname"].Value != null)
{ samsaccountname = searchresult.GetDirectoryEntry().Properties["samaccountname"].Value.ToString(); }
else { samsaccountname = ""; }
ListViewItem lvi = new ListViewItem(samsaccountname);
//lvi.SubItems.Add(givenName);
//lvi.SubItems.Add(sn);
//lvi.SubItems.Add(mail);
listView1.Items.Add(lvi);
}
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
}
catch
{
// Add error handling.
}
}
Here is what I did in PowerShell + C#
private string SearchDLScript(string searchDL)
{
listViewSearchDL.Items.Clear();
listViewSearchDL.Columns.Clear();
listViewSearchDL.Columns.Add("");
listViewSearchDL.Items.Add("Loading list, please wait.");
listViewSearchDL.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
if (textSearchDL.Text.Length < 8)
{
listViewSearchDL.Items.Add("Hint: The more you type, the quicker the seach.");
listViewSearchDL.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
}
string rbName = "";
if (radioButtonDisplayName.Checked == true)
{
rbName = "DisplayName";
} else if (radioButtonAlias.Checked == true)
{
rbName = "SamAccountName";
}
string searchDLScriptCommand = #"Import-Module ActiveDirectory
Get-ADGroup -Filter '"+rbName+ #" -Like """ + searchDL + #"*"" ' -Properties * | Select-Object DisplayName,SamAccountName | ConvertTo-Csv -NoTypeInformation | Select-Object -Skip 1";
string scriptOutput = RunPowerShellCommands.RunPowerShellCode(searchDLScriptCommand);
string[] strArr = scriptOutput.Split(new string[] { System.Environment.NewLine }, StringSplitOptions.None);
strArr = strArr.Where(x => !string.IsNullOrEmpty(x)).ToArray();
listViewSearchDL.Columns.Clear();
listViewSearchDL.Items.Clear();
listViewSearchDL.Columns.Add("Display Name");
listViewSearchDL.Columns.Add("Alias");
foreach (string user in strArr)
{
string userDetails = user.Replace("\"", "");
string[] columns = userDetails.Split(',');
ListViewItem lvi = new ListViewItem(columns[0]);
for (int i = 1; i < columns.Count(); i++)
{
lvi.SubItems.Add(columns[i]);
}
listViewSearchDL.Items.Add(lvi);
}
if (scriptOutput == "\r\n")
{
listViewSearchDL.Items.Clear();
listViewSearchDL.Columns.Clear();
listViewSearchDL.Columns.Add("");
listViewSearchDL.Items.Add("There are no records");
}
listViewSearchDL.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
listViewSearchDL.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
return "scriptOutput";
}
In the C# sample you implicitly perform two extra lookups per object returned by the DirectorySearcher, by calling GetDirectoryEntry():
foreach (SearchResult searchresult in rsAll)
{
if (searchresult.GetDirectoryEntry().Properties["samaccountname"].Value != null)
{ samsaccountname = searchresult.GetDirectoryEntry().Properties["samaccountname"].Value.ToString(); }
else { samsaccountname = ""; }
// and then updating the listview
}
The documentation for GetDirectoryEntry() even warns you about this:
Note
Calling GetDirectoryEntry on each SearchResult returned through DirectorySearcher can be slow.
What you'd want to do is add the list of property names that you'll need to the searcher (this is what the Get-AD* -Properties parameter does in the background), and have them returned after the very first search:
DirectorySearcher ds = new DirectorySearcher(de);
// do this before calling FindAll()
ds.PropertiesToLoad.Add("samaccountname")
and then when you process the search results, grab the property value directly from each search result instead of calling GetDirectoryEntry() again:
foreach (SearchResult searchresult in rsAll)
{
if (searchresult.Properties["samaccountname"].Value != null)
{
samsaccountname = searchresult.Properties["samaccountname"].Value.ToString();
}
else
{
samsaccountname = "";
}
// and then updating the listview
}
I try to get a List of all properties from an Object in the Active Directory.
What I have for now is this:
List<User> users = new List<User>();
try
{
DirectoryEntry root = new DirectoryEntry("LDAP://RootDSE");
root = new DirectoryEntry("LDAP://" + root.Properties["defaultNamingContext"][0]);
DirectorySearcher search = new DirectorySearcher(root);
search.Filter = "(&(objectClass=user)(objectCategory=person))";
search.PropertiesToLoad.Add("samaccountname");
search.PropertiesToLoad.Add("displayname");
search.PropertiesToLoad.Add("mail");
search.PropertiesToLoad.Add("telephoneNumber");
search.PropertiesToLoad.Add("department");
search.PropertiesToLoad.Add("title");
SearchResultCollection results = search.FindAll();
if (results != null)
{
foreach (SearchResult result in results)
{
foreach (DictionaryEntry property in result.Properties)
{
Debug.Write(property.Key + ": ");
foreach (var val in (property.Value as ResultPropertyValueCollection)) {
Debug.Write(val +"; ");
}
Debug.WriteLine("");
}
}
}
}
catch (Exception ex)
{
}
But it gets only the properties I added with PropertiesToLoad. Is it possible to get all properties dynamically?
If you don't specify anything in PropertiesToLoad, you should get all the properties. Just remove the lines with search.PropertiesToLoad.Add.
Getting all the properties of all the users in the domain could be pretty heavy, however.
To get all propertyNames you can do:
SearchResult result = search.FindOne();
ResultPropertyCollection temp = result.Properties;
string[] propertyNamesList = new string[temp.PropertyNames.Count];
temp.PropertyNames.CopyTo(propertyNamesList, 0);
and propertyNamesList will contain everything there.
Trying to learn LDAP queries in c# to access get all groups user is assigned to in active directory:
I am using System.DirectoryServices:
Havent tested it yet but from throwing examples together I have got:
//This should return all groups for particular user
public List<string> GetUserGroups(string UserName)
{
//create connection
DirectoryEntry entry = new DirectoryEntry(_lDAPPath);
DirectorySearcher search = new DirectorySearcher(entry);
//Get user with UserName
string query = "(&(objectCategory=User)(objectClass=person)(name=" + UserName + "*))";//(memberOf=*))";
search.Filter = query;
//properties returned by query
search.PropertiesToLoad.Add("memberOf");
search.PropertiesToLoad.Add("name");
System.DirectoryServices.SearchResultCollection mySearchResultColl = search.FindAll();
List<string> userGroups = new List<string>();
//Should only be one user in foreach loop
foreach (SearchResult result in mySearchResultColl)
{
//for user get each group assigned to
foreach (string prop in result.Properties["memberOf"])
{
if (prop.Contains(UserName))
{
//adds group name to string
userGroups.Add(result.Properties["memberOf"][0].ToString());
}
}
}
return userGroups;
}
hoping this works. does anyone see any poss problems? ta
It would be preferable to test your code and indicate any bugs you can't handle before posting. However here is tested code which I have been using for years. It searches by cn i.e. Common Name (user alias)
public static List<string> GetUserGroupDetails(string userName)
{
DirectorySearcher search = new DirectorySearcher();
List<string> groupsList = new List<string>();
search.Filter = String.Format("(cn={0})", userName);
search.PropertiesToLoad.Add("memberOf");
SearchResult result = search.FindOne();
if (result != null)
{
int groupCount = result.Properties["memberOf"].Count;
for (int counter = 0; counter < groupCount; counter++)
{
string s = (string)result.Properties["memberOf"][counter];
groupsList.Add(s);
// _log.DebugFormat("found group for user {0} : {1}", userName, s);
}
}
else
{
_log.Warn("no groups found for user " + userName);
}
return groupsList;
}
Note that the above code also returns email distribution lists for which the user is a member. When I want to exclude these I filter out the entries stating with "dl-".