I am using this code to populate a combobox with Active Directory users but from time to time I get a COM exception at the 'for each' beside that the code works.
System.DirectoryServices.DirectoryEntry entry = new System.DirectoryServices.DirectoryEntry("LDAP://DC=DOMAIN, DC=local");
System.DirectoryServices.DirectorySearcher mySearcher = new System.DirectoryServices.DirectorySearcher(entry);
mySearcher.Filter = "(&(objectClass=user)(objectCategory=person))";
foreach (System.DirectoryServices.SearchResult resEnt in mySearcher.FindAll())
{
try
{
//DirectoryEntry de = new DirectoryEntry(resEnt.GetDirectoryEntry());
System.DirectoryServices.DirectoryEntry de = resEnt.GetDirectoryEntry();
comboBox2.Items.Add(de.Properties["GivenName"].Value.ToString() + " " + de.Properties["sn"].Value.ToString() + " " + "[" + de.Properties["sAMAccountName"].Value.ToString() + "]");
}
catch (Exception e)
{
// MessageBox.Show(e.ToString());
}
}
Is there a more efficient way to do this or resolve the error?
The first thing I'd do is include the property you want to grab from the result into the search result - that way, you don't have to do a .GetDirectoryEntry() call on each result:
using System.DirectoryServices;
DirectoryEntry entry = new DirectoryEntry("LDAP://DC=DOMAIN, DC=local");
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(&(objectClass=user)(objectCategory=person))";
// define the properties you want to be loaded into the search result object
mySearcher.PropertiesToLoad.Add("GivenName");
mySearcher.PropertiesToLoad.Add("samAccountName");
mySearcher.PropertiesToLoad.Add("sn");
foreach (SearchResult resEnt in mySearcher.FindAll())
{
try
{
string givenName = "";
string samAccountName = "";
string surName = "";
// check if you got a value - not all properties have to be filled -
// and if they're not filled, they might be "null".
if(resEnt.Properties["GivenName"] != null &&
resEnt.Properties["GivenName"].Count > 0)
{
givenName = resEnt.Properties["GivenName"].Value;
}
// samAccountName is a *must* property - it has to be set.
samAccountName = resEnt.Properties["samAccountName"].Value;
if(resEnt.Properties["sn"] != null &&
resEnt.Properties["sn"].Count > 0)
{
surName = resEnt.Properties["sn"].Value;
}
comboBox2.Items.Add(givenName + " " + surName + " " + "[" + samAccountName + "]");
}
catch (Exception e)
{
// MessageBox.Show(e.ToString());
}
}
The second point is: if you're on .NET 3.5 or newer, you can use a PrincipalSearcher and a "query-by-example" principal to do your searching; also, working with the result set using the UserPrincipal objects is a lot easier, since things like GivenName and Surname are surfaced as properties on the UserPrincipal:
// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// define a "query-by-example" principal - here, we search for any UserPrincipal
UserPrincipal qbeUser = new UserPrincipal(ctx);
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here
UserPrincipal foundUser = found as UserPrincipal;
if(foundUser != null)
{
comboBox2.Items.Add(foundUser.GivenName + " " + foundUser.Surname + " " + "[" + foundUser.SamAccountName + "]");
}
}
If you haven't already - absolutely read the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 which shows nicely how to make the best use of the new features in System.DirectoryServices.AccountManagement. Or see the MSDN documentation on the System.DirectoryServices.AccountManagement namespace.
Of course, depending on your need, you might want to specify other properties on that "query-by-example" user principal you create:
DisplayName (typically: first name + space + last name)
SAM Account Name - your Windows/AD account name
User Principal Name - your "username#yourcompany.com" style name
You can specify any of the properties on the UserPrincipal and use those as "query-by-example" for your PrincipalSearcher.
Put the foreach loop inside the catch block of the try...catch statement.
Related
I tried to create reset password and user creation functions for Active Directory. On my PC with below code is works just fine without any error. But when I publish to the server, I received error: Exception has been thrown by the target of an invocation.
ADResult hasil = new ADResult();
DirectoryEntry de = new DirectoryEntry(_path, _adminID, _adminPassword, AuthenticationTypes.Secure);
DirectorySearcher ds = new DirectorySearcher(de);
string query = string.Format("(&(objectCategory=person)(sAMAccountName={0}))", user.userID);
ds.Filter = query;
ds.Sort.PropertyName = "CN";
ds.SearchScope = SearchScope.Subtree;
ds.CacheResults = false;
try
{
SearchResult sr = ds.FindOne();
if (sr == null)
{
hasil.errorCode = -1;
hasil.result = "User name not found in this domain.";
}
else
{
DirectoryEntry userCredentials = sr.GetDirectoryEntry();
userCredentials.Invoke("SetPassword", new Object[] { user.password });
userCredentials.CommitChanges();
userCredentials.Close();
hasil.errorCode = 0;
hasil.result = "Password for " + user.userID + " changed successfully.";
}
}
catch (Exception e)
{
hasil.errorCode = -1;
hasil.result = e.Message + "<br/>" + e.StackTrace + "<br/>" + e.Source;
}
return hasil;
Is there something configuration/settings that I missed on the server side?
I changed my code using
UserPrincipal
instead of
DirectoryEntry
and it works perfectly.
I use this code:
PrincipalContext PrincipalContext4 = new PrincipalContext(ContextType.Domain, "full_domain_name.com", "OU=User_OU,DC=domain_name,DC=co,DC=id", _adminID, _adminPassword);
UserPrincipal UserPrincipal1 = new UserPrincipal(PrincipalContext4, user.userID, user.password, true);
//User Logon Name
UserPrincipal1.UserPrincipalName = user.userID;
UserPrincipal1.Name = user.firstName + " " + user.lastName;
UserPrincipal1.GivenName = user.firstName;
UserPrincipal1.Surname = user.lastName;
UserPrincipal1.DisplayName = user.firstName + " " + user.lastName;
UserPrincipal1.Enabled = true;
UserPrincipal1.Save();
I still don't know why I use DirectoryEntry is not working on windows server 2019
That't not the exact error message,real error must be wrapped.You can write loggers or event logging after lines which you think could be culprit.You can check event log on that server if you can find elaborated stack Trace. You can check that user have admin privilege for that server to lookup in AD.
So I have a program that needs to add a new organizational unit under another OU. The format has to be as it is in the code below. Problem is I keep getting the same exception if I put spaces in in the name. I am able to manually add OUs with spaces. What am I a doing wrong here?
Here is the code:
string ou = "OU=" + "New Company 99999";
try
{
if (DirectoryEntry.Exists("LDAP://" + ou + ",OU=MainOrganizationalUnit,DC=domain,DC=com"))
{
MessageBox.Show(ou + " exists.");
}
else
{
MessageBox.Show(ou + " does not exist. Creating...");
using (DirectoryEntry entry = new DirectoryEntry("LDAP://OU=MainOrganizationalUnit,DC=domain,DC=com"))
{
using (DirectorySearcher searcher = new DirectorySearcher(entry))
{
searcher.Filter = "(" + ou + ")";
searcher.SearchScope = SearchScope.Subtree;
SearchResult result = searcher.FindOne();
if (result == null)
{
/* OU Creation */
DirectoryEntry de = entry.Children.Add(ou, "organizationalUnit");
de.Properties["description"].Value = "This is a Test";
de.CommitChanges();
}
}
}
}
}
catch (Exception Ex)
{
LogWriter.Exception(Ex);
}
When I run this code I get the following error logged:
System.DirectoryServices.DirectoryServicesCOMException (0x80072037): There is a naming violation.
at System.DirectoryServices.DirectoryEntry.CommitChanges()
at MyProgram.MyStaticClass.function()
Renaming an OU doesnt seem to be the ideal solution.
Just try escaping the Spaces with a backSlash
string ou = "OU=" + "New\\ Company\\ 99999";
This article shows the characters that has to be escaped when using LDAP with AD.
So, I am currently using a work around but I feel I should not have to do this. Essentially, I am now creating a temporary OU name without spaces, then I rename it.
DirectoryEntries des = entry.Children;
DirectoryEntry badObject = des.Find(ou);
badObject.Rename("OU=With Spaces 99999");
entry.CommitChanges();
how to enable a user to access vpn in active directory using c# programming language.
string username = "Abc user";
string _path;
string _filterAttribute;
try
{
DirectoryEntry myLdapconnection=new DirectoryEntry("domain");
myLdapconnection.Path = "LDAP://OU=,OU=,DC=,DC=,DC=";
myLdapconnection.AuthenticationType = AuthenticationTypes.Secure;
object obj = myLdapconnection.NativeObject;
DirectorySearcher search = new DirectorySearcher(myLdapconnection);
search.Filter = "(cn=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
s="True";
if (null == result)
{
s= "false";
}
// Update the new path to the user in the directory.
_path = result.Path;
_filterAttribute = (string)result.Properties["cn"][0];
}
catch (Exception ex)
{
s="Error authenticating user. " + ex.Message;
}
from the above code what the function of following statement is?
object obj = myLdapconnection.NativeObject;
Is this the statement to enable vpn?
if I add user to group then will he can use vpn connection?
Since obj is not used in the above code; it has no function and has nothing to do with VPN.
The code seems like it is trying to verify that a user exists, BUT it is weird.
I want to create an online user directory and pull the information directly from Active Directory. So after hours of searching I came up with this solution(which is not much of a solution). When I run my program all it does is spin like it wants to do something but after all of the spinning it gives me a blank white page.
protected void btnClick_Click1(object sender, EventArgs e)
{
string dom = txtDomainName.Text;
System.DirectoryServices.DirectoryEntry entry = new System.DirectoryServices.DirectoryEntry("LDAP://" + dom);
System.DirectoryServices.DirectorySearcher mySearcher = new System.DirectoryServices.DirectorySearcher(entry);
mySearcher.Filter = ("(objectClass=user)");
Console.WriteLine("Listing of users in the Active Directory");
Console.WriteLine("========================================");
foreach (System.DirectoryServices.SearchResult resEnt in mySearcher.FindAll())
{
try
{
System.DirectoryServices.DirectoryEntry de = resEnt.GetDirectoryEntry();
Console.WriteLine("Display Name : " + de.Properties["DisplayName"].Value.ToString());
Console.WriteLine("Email : " + de.Properties["Mail"].Value.ToString());
Console.WriteLine("Title : " + de.Properties["Title"].Value.ToString());
Console.WriteLine("User Name : " + de.Properties["sAMAccountName"].Value.ToString());
Console.WriteLine("First Name : " + de.Properties["GivenName"].Value.ToString());
Console.WriteLine("Last Name : " + de.Properties["sn"].Value.ToString());
Console.WriteLine("Initials : " + de.Properties["Initials"].Value.ToString());
Console.WriteLine("Company : " + de.Properties["Company"].Value.ToString());
Console.WriteLine("Department : " + de.Properties["Department"].Value.ToString());
Console.WriteLine("Telephone No. : " + de.Properties["TelephoneNumber"].Value.ToString());
}
catch (Exception ex)
{
}
Console.WriteLine("=========== End of user =============");
}
Console.WriteLine("=========== End of Listing =============");
}
Please note that I know little to nothing about active directory, only that it can be use to store Employee Information and create and manage user groups. I have used C# and LDAP to create login pages that requires and verifies username and password from ID to pass authentication.
Edited
The application posted requires the user to put in their domain. After I enter the domain name it should list all users or something, it just spins and gives me a white page of nothing
Instead of using
Console.WriteLine(
try
Response.Write(string.Format(
This will give you a print out and that should fix your blank page issue.
I tested this in a console based application. I used the Directory.Services.AccountManagement class to achieve this. In my example, I am just listing the names.
private static string SearchUsers(UserPrincipal parUserPrincipal)
{
PrincipalSearcher insPrincipalSearcher = new PrincipalSearcher {QueryFilter = parUserPrincipal};
PrincipalSearchResult<Principal> results = insPrincipalSearcher.FindAll();
var builder = new StringBuilder();
foreach (UserPrincipal p in results)
{
builder.AppendFormat("SamAccountName:{0}\t DisplayName:{1}\tUserPrincipal:{2}\tDescription:{3}\tEmail:{4}\tTel:{5}\n", p.SamAccountName, p.DisplayName, p.UserPrincipalName, p.Description, p.EmailAddress, p.VoiceTelephoneNumber);
}
return builder.ToString();
}
public static string SetPrincipal()
{
// **Make sure you set the correct domain name**
var pc = new PrincipalContext(ContextType.Domain, "myCompany");
UserPrincipal insUserPrincipal = new UserPrincipal(pc) {Name = "*"};
return SearchUsers(insUserPrincipal);
}
How to remove windows group account using C#
I'm using this code to remove user account, but I need to remove the whole group.
DirectoryEntry localDirectory = new DirectoryEntry("WinNT://" + Environment.MachineName.ToString());
DirectoryEntries users = localDirectory.Children;
DirectoryEntry user = users.Find(userDn);
users.Remove(user);
I need to remove the Group with it's users.
public void Delete(string ouPath, string groupPath)
{
if (DirectoryEntry.Exists("LDAP://" + groupPath))
{
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + ouPath);
DirectoryEntry group = new DirectoryEntry("LDAP://" + groupPath);
entry.Children.Remove(group);
group.CommitChanges();
}
catch (Exception e)
{
Console.WriteLine(e.Message.ToString());
}
}
else
{
Console.WriteLine(path + " doesn't exist");
}
}
Howto: (Almost) Everything In Active Directory via C#