I am trying to create a new AD-User with this code:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "Domain", "ou=some_ou, dc=Mydomain");
UserPrincipal user = new UserPrincipal(ctx, account, passwd, true);
user.GivenName = Givenname;
user.Surname = Surname;
user.DisplayName = Displayname;
user.UserPrincipalName = account + "#Domain";
user.Save();
The User is created without error. But I also have to set properties like Address etc, so the code continues with:
string distname = user.DistinguishedName;
DirectoryEntry duser = new DirectoryEntry(distname);
try
{
duser.Properties["company"].Value = "Company";
}
catch (Exception e)
{
}
Now I am getting
Error: System.Exception._COMPlusExceptionCode -532459699
The string distname shows the correct distinguished name.
I am not 100% sure what is causing your problem but one thing that may make things easier on you and may clear up some errors due to you improperly using both DirectoryServices and DirectoryServices.AccountManagement at the same time is creating a new class that includes the company attribute.
Its actually not that hard to do.
[DirectoryObjectClass("user")]
[DirectoryRdnPrefix("CN")]
public class UserPrincipalEx : UserPrincipal
{
public UserPrincipalEx(PrincipalContext context) : base(context) { }
public UserPrincipalEx(PrincipalContext context, string samAccountName, string password, bool enabled)
: base(context, samAccountName, password, enabled)
{
}
[DirectoryProperty("company")]
public string Company
{
get
{
if (ExtensionGet("company").Length != 1)
return null;
return (string)ExtensionGet("company")[0];
}
set { this.ExtensionSet("company", value); }
}
}
You can then just modify your code to
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "Domain", "ou=some_ou, dc=Mydomain");
UserPrincipalEx user = new UserPrincipalEx(ctx, account, passwd, true);
user.GivenName = Givenname;
user.Surname = Surname;
user.DisplayName = Displayname;
user.UserPrincipalName = account + "#Domain";
user.Company = "Company";
user.Save();
My hunch is you are having some kind of interaction with the two methods of interfacing with active directory, if you switch to a single interface your problem may just go away.
For DirectoryEntry, you have to specify the protocol (LDAP, GC, WinNT, ...). So you would have to do:
DirectoryEntry duser = new DirectoryEntry("LDAP://" + distname);
Note that the protocol is case sensitive, LDAP has to be all caps.
I see you are using credentials in the UserPrincipal,
Did you forgot to use them when creating your DirectoryEntry?
Also, you need to add "LDAP://" before you server name
Try something like :
DirectoryEntry duser = new DirectoryEntry("LDAP://" + distname);
duser.Username = account;
duser.Password = passwd;
duser.AuthenticationType = AuthenticationTypes.Secure;
Related
Working on pulling user info from an AD based on an ID that is entered. The error I get is:
Cannot implicitly convert type "string" to type "System.DirectoryServices.DirectoryEntry"
happening here in the Save method:
DirectoryEntry de = new DirectoryEntry();
de = QueryAD(objSearchRolesViewModel.NID);
Opening the connection:
private DirectoryEntry GetDirectoryObject()
{
DirectoryEntry oDE;
oDE = new DirectoryEntry("LDAP://myConnection");
return oDE;
}
Querying AD:
public string QueryAD(string userNID)
{
DirectorySearcher ds = new DirectorySearcher
{
SearchRoot = new DirectoryEntry(""),
//start searching from local domain
Filter = userNID
};
ds.PropertiesToLoad.Add("givenname");
ds.PropertiesToLoad.Add("sn");
ds.PropertiesToLoad.Add("mail");
// start searching
SearchResultCollection searchCollection = ds.FindAll();
try
{
foreach (SearchResult result in searchCollection)
{
if (result.Properties.PropertyNames != null)
foreach (string propKey in result.Properties.PropertyNames)
{
// Display each of the values for the property identified by the property name.
foreach (object prop in result.Properties[propKey])
{
if ((propKey == "userPrincipalName"))
{
return prop.ToString();
}
}
}
return "Unknown User";
}
catch (Exception ex)
{
return "Unknown User";
}
}
Save new user:
public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
DirectoryEntry de = new DirectoryEntry();
de = QueryAD(objSearchRolesViewModel.NID);
USERACCOUNT objUserAccount = new USERACCOUNT
{
HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
DOMAIN = "Aeth",
NTUSERID = objSearchRolesViewModel.User_Id,
ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
FIRSTNAME = GIVENNAME GOES HERE,
LASTNAME = SURNAME GOES HERE,
EMAIL = MAIL GOES HERE,
ACTIVE = true/*Convert.ToBoolean(objSearchRolesViewModel.ActiveStatus)*/,
DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
CREATEID = userID,
CREATEDATE = DateTime.Now,
UPDATEID = userID,
UPDATEDATE = DateTime.Now
};
_context.USERACCOUNTs.Add(objUserAccount);
_context.SaveChanges();
}
I need to be able to access the properties from Active Directory and add them to what is being sent to the DB when a new user is added.
A couple nit-picky things:
Opening the connection
Creating a DirectoryEntry object doesn't actually open any connection. That is how almost all of Microsoft's libraries work: constructors do not make any I/O requests. The first network request is made when you first start using the object.
Also, new DirectoryEntry("") has exactly the same effect as new DirectoryEntry() - the empty string doesn't get you anything. But also, if you don't set the SearchRoot property, it will automatically set it to the current domain anyway. So you don't even need to set it unless you need to set it to a different domain or OU.
Now on to answering the question:
You have gotten a couple answers already, but they aren't ideal. You certainly can use the System.DirectoryServices.AccountManagement namespace if you want, which is just a wrapper around System.DirectoryServices to make things easier. But like all things that make things easier, it does so at the cost of performance. It always has worse performance over using System.DirectoryServices directly, yourself. One reason is because whenever a UserPrincipal object is created, it retrieves every attribute that has a value for the account. You probably aren't using every attribute.
If you can wrap your head around using DirectoryEntry/DirectorySearcher yourself, you will have better performing code.
Jawad's answer will also work, but it has one key issue that will slow down your code: DirectorySearcher will return all the attributes you request. You already set PropertiesToLoad, which is good - it will limit the results to only the attributes you need. But if you use GetDirectoryEntry(), that info is lost. If you then start using .Properties on the DirectoryEntry, it will make a new network request and ask for all attributes that have values. That can be a lot of data that you aren't using, apart from being a second network request that you could avoid.
I would suggest just returning a SearchResult from QueryAD, which will let you use the data that was returned in the search.
You can also use FindOne() instead of FindAll(), since you are only using the first result anyway. This will make AD stop looking after it finds one result. Just test for null in case the user wasn't found.
public SearchResult QueryAD(string userNID)
{
DirectorySearcher ds = new DirectorySearcher(userNID) {
PropertiesToLoad = {"givenname", "sn", "mail"}
};
return ds.FindOne();
}
public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
var result = QueryAD(objSearchRolesViewModel.NID);
if (result == null)
{
//user wasn't found!
}
USERACCOUNT objUserAccount = new USERACCOUNT
{
HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
DOMAIN = "Aeth",
NTUSERID = objSearchRolesViewModel.User_Id,
ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
FIRSTNAME = (string) result.Properties["givenName"]?[0],
LASTNAME = (string) result.Properties["sn"]?[0],
EMAIL = (string) result.Properties["mail"]?[0],
ACTIVE = true/*Convert.ToBoolean(objSearchRolesViewModel.ActiveStatus)*/,
DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
CREATEID = userID,
CREATEDATE = DateTime.Now,
UPDATEID = userID,
UPDATEDATE = DateTime.Now
};
_context.USERACCOUNTs.Add(objUserAccount);
_context.SaveChanges();
}
The Properties of a SearchResult will always present properties as arrays, even if they are single-valued attributes in AD. This is different than DirectoryEntry. But that is the reason for the [0] in result.Properties["givenName"]?[0] as string. The ? is to test for null, because if the attribute is not set in AD, then it won't appear in the Properties collection at all.
I wrote an article about getting better performance when programming with AD, with a focus on C#. You might enjoy reading it.
In your code, QueryAD(objSearchRolesViewModel.NID); returns a string but you are assigning it to a DirectoryEntity. This wont work.
public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
DirectoryEntry de = new DirectoryEntry();
de = QueryAD(objSearchRolesViewModel.NID); // <--- This is the issue.
...
Look up DirectoryEntry from the QueryAD function and return that object to make your call work.
public string QueryAD(string userNID) // You will need to return DirectoryEntry to make your code work.
{
DirectorySearcher ds = new DirectorySearcher
EDIT:
I find using UserPrincipal with PrincipalContext to be much simpler. Look up PrincipalContext by using your domain name and provide creds if not running with domain account. Then, simply, lookup user by SamAccountName, Name/ID or DistinguishedName.
You will need, 'System.DirectoryServices.AccountManagement' nuget package for Principal usage.
public static UserPrincipal QueryAD(string UserName)
{
PrincipalContext context = new PrincipalContext(ContextType.Domain, "Aeth", "user", "password");
// Without creds if the account running the code is already a domain account
//PrincipalContext context = new PrincipalContext(ContextType.Domain, "Aeth");
// You can search the account by SamAccountName, DistinguishedName, UserPrincipalName or SID
return UserPrincipal.FindByIdentity(context, IdentityType.Name, UserName);
}
public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
UserPrincipal user = QueryAD(objSearchRolesViewModel.User_Id);
USERACCOUNT objUserAccount = new USERACCOUNT
{
HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
DOMAIN = "Aeth",
NTUSERID = objSearchRolesViewModel.User_Id,
ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
FIRSTNAME = user.GivenName, // Get FirstName
LASTNAME = user.Surname, // Get LastName
EMAIL = user.EmailAddress, // Get Email Address
ACTIVE = user.Enabled, // Get User Status
DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
CREATEID = userID,
CREATEDATE = DateTime.Now,
UPDATEID = userID,
UPDATEDATE = DateTime.Now
};
_context.USERACCOUNTs.Add(objUserAccount);
_context.SaveChanges();
}
Following is your code that uses DirectoryEntry method. Make sure you add credentials if you are running this code with account that does not have access to AD.
Method to search AD
public DirectoryEntry QueryAD(string UserName)
{
try
{
DirectorySearcher ds = new DirectorySearcher
{
SearchRoot = new DirectoryEntry(),
//start searching from local domain
Filter = "(&" +
"(objectClass=user)" +
"(name=" + UserName + "))" // This is Username
};
// start searching
return ds.FindOne().GetDirectoryEntry();
}
catch (Exception ex)
{
throw new ApplicationException("error occured while querying AD");
}
}
Method to Check if Account is Active
private bool IsActive(DirectoryEntry de)
{
if (de.NativeGuid == null) return false;
int flags = (int)de.Properties["userAccountControl"].Value;
return !Convert.ToBoolean(flags & 0x0002);
}
Method to Save the User to your DB
public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
DirectoryEntry userEntry = QueryAD(objSearchRolesViewModel.User_Id);
if (userEntry == null)
{
//Handle error where No User was Found.
throw new ApplicationException("User Not Found");
}
USERACCOUNT objUserAccount = new USERACCOUNT
{
HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
DOMAIN = "Aeth",
NTUSERID = objSearchRolesViewModel.User_Id,
ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
FIRSTNAME = userEntry.Properties["givenname"].Value.ToString(),
LASTNAME = userEntry.Properties["sn"].Value.ToString(),
EMAIL = userEntry.Properties["mail"].Value.ToString(),
ACTIVE = IsActive(userEntry),
DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
CREATEID = userID,
CREATEDATE = DateTime.Now,
UPDATEID = userID,
UPDATEDATE = DateTime.Now
};
_context.USERACCOUNTs.Add(objUserAccount);
_context.SaveChanges();
}
I am working on some code that creates an AD user programmatically (to be pulled into a MS DYnamics CRM 2013 environment), and the code works with one weird quirk. I have a list of UPN's created on our AD structure, but for some reason my AD users aren't resolving to them.
So, I have a list of UPN suffix's that include example.com. I set the username to be first.last#example.com, and it's not letting me use this to sign in to CRM. When I check the AD entry, I can see that it kind of correctly assigned the logon name to first.last#example.com, but #example.com appears in the list twice, the entry that was actually created and this new one. So it's not recognizing that #example.com is a pre-existing UPN suffix, and I can't use the first.last#example.com to sign in to CRM with, I have to use the example.local\first.last. I hope this made sense. Thank you very much.
So how do I tell then AD record when it signs in to use the pre-existing UPN and not... do whatever it's doing? Here's my code:
try
{
string connectionPrefix = "LDAP://" + ldapPath;// ldapPart;// ldapPath
var adminUsername = ConfigurationHelper.GetConfigSettingByName(orgservice,
"ADPasswordReset.AdminUsername", unsecureConfig, secureConfig);
var adminPassword = ConfigurationHelper.GetConfigSettingByName(orgservice,
"ADPasswordReset.AdminPassword", unsecureConfig, secureConfig);
if (CheckIfUserExists(getSAMNameFromUserName(userName), trace) == true)
{
throw new Exception("A User with that name already exists.");
}
DirectoryEntry dirEntry = new DirectoryEntry(connectionPrefix, adminUsername, adminPassword, AuthenticationTypes.Secure);
DirectoryEntry newUser;
string cn = firstName + " " + lastName;
newUser = dirEntry.Children.Add("CN=" + cn, "user"); //display name - This is the "Display" name that shows up on the AD list.
newUser.Properties["displayName"].Value = cn;
newUser.Properties["samAccountName"].Value = getSAMNameFromUserName(userName);//userName;
newUser.Properties["userPrincipalName"].Value = checkUserName(userName);
newUser.Properties["givenName"].Value = firstName; //Firstname
newUser.Properties["sn"].Value = lastName; //Lastname? -Surname
newUser.Properties["LockOutTime"].Value = 0; //unlock account. Set this to 0 to unlock the account.
newUser.CommitChanges();
oGUID = newUser.Guid.ToString();
//Must be handled after the previous stuff. Unsure why.
newUser.Invoke("SetPassword", new object[] { userPassword });
newUser.CommitChanges();
//For some reason, can't be handled before the password is set?
newUser.Properties["userAccountControl"].Value = 0x0200; //0x0200
newUser.CommitChanges();
dirEntry.Close();
newUser.Close();
}
public static string checkUserName(string userName)
{
if (!userName.Contains("#"))
{
return userName + "#example.local";
}
return userName;
}
public static string getSAMNameFromUserName(string domainUserName)
{
int stop;
string s = domainUserName;
if (s.Contains("#"))
{
stop = s.IndexOf("#");
return (stop > -1) ? s.Substring(0, stop) : string.Empty;
}
return domainUserName;// string.Empty;
}
In your code you set the UPN to example.local not example.com:
public static string checkUserName(string userName)
{
if (!userName.Contains("#"))
{
return userName + "#example.local";
}
return userName;
}
A user can only have one UPN even if the domain has multiple possible suffixes configured. If you want username#example.com to resolve, the user must have example.com set as it's suffix.
Thank you all who took the time to help.
Whitespace. Grrr, whitespace.
For anybody who comes across this thread in the future, the problem was that something during the AD creation was appending whitespace to my username and domain. So instead of "example.com" it was saving the domain as "example.com " (notice the whitespace at the end?). I .Trim()'d everything and it appears to be working just fine. :)
My new code becomes:
public static string checkUserName(string userName)
{
if (!userName.Contains("#"))
{
return userName.Trim() + "#domain.local".Trim();
}
return userName.Trim();
}
try
{
string connectionPrefix = "LDAP://" + ldapPath;// ldapPart;// ldapPath
var adminUserName = GetAdminUserName(orgservice, unsecureConfig, secureConfig);
var adminPassword = GetAdminPassword(orgservice, unsecureConfig, secureConfig);
if (CheckIfUserExists(getSAMNameFromUserName(userName), trace) == true)
{
trace.Trace("About to handle success. A User already exists: " + getSAMNameFromUserName(userName));
trace.HandleSuccess();
throw new Exception("User " + getSAMNameFromUserName(userName) + " already exists.");
}
DirectoryEntry dirEntry = new DirectoryEntry(connectionPrefix, adminUserName, adminPassword, AuthenticationTypes.Secure);
DirectoryEntry newUser;
string cn = firstName.Trim() + " " + lastName.Trim();
newUser = dirEntry.Children.Add("CN=" + cn, "user"); //display name - This is the "Display" name that shows up on the AD list.
newUser.Properties["displayName"].Value = cn;
newUser.Properties["samAccountName"].Value = getSAMNameFromUserName(userName).Trim();
newUser.Properties["userPrincipalName"].Value = checkUserName(userName).Trim();
newUser.Properties["givenName"].Value = firstName.Trim(); //Firstname
newUser.Properties["sn"].Value = lastName.Trim(); //Lastname? -Surname
//newUser.Properties["LockOutTime"].Value = 0; //unlock account. Set this to 0 to unlock the account.
newUser.CommitChanges();
oGUID = newUser.Guid.ToString();
//Must be handled after the previous stuff. Unsure why.
newUser.Invoke("SetPassword", new object[] { userPassword });
newUser.CommitChanges();
//For some reason, can't be handled before the password is set?
newUser.Properties["userAccountControl"].Value = 0x10200; //0x0200
newUser.CommitChanges();
//http://stackoverflow.com/questions/20710535/is-there-a-way-to-set-a-new-users-domain-suffix-through-the-userprincipal-class
newUser.Close();
dirEntry.Close();
//newUser.Close(); //Close user first, then dirEntry because of the heirarchy call?
}
catch (System.DirectoryServices.DirectoryServicesCOMException E)
{
System.DirectoryServices.DirectoryServicesCOMException newE = new System.DirectoryServices.DirectoryServicesCOMException(E.Message);
//DoSomethingwith --> E.Message.ToString();
throw newE;
}
I'm trying to do a couple of things. First off this c# program verifies against Active Directory user credentials using:
var ADentry = new DirectoryEntry("LDAP://domain", uname, pword);
But obviously you need to pass in the username and password somehow. Is there a way that you can retrieve it automatically when the user signs in on the network from Active Directory and use that in the fields without having the username type in the username and password.
If not, I made it so the user can type in their credentials in the console. But if it doesn't work it ends up hanging forever. What type of code can I use to timeout after say 1 minute if this keeps hanging otherwise it hangs forever? thanks
I was trying to do an LDAP query and the following will do it for you. Most of it are methods but you may be interested in this line of code: PrincipalContext oPrincipalContext = new PrincipalContext(ContextType.Domain, sDomain, sDefaultOU, ContextOptions.Negotiate);
The full code is here:
IsUserGroupMember("username", "group name the user is in");
public string sDomain = "your.domainName.com"
public string sDefaultOU = OU=**,OU=**,DC=**,DC=**,DC=**
public void IsUserGroupMember(string sUserName, string sGroupName)
{
try
{
UserPrincipal oUserPrincipal = GetUser(sUserName);
GroupPrincipal oGroupPrincipal = GetGroup(sGroupName);
if (oUserPrincipal != null && oGroupPrincipal != null)
{
//do something
}
else
{
//nothing
}
}
catch (PrincipalServerDownException)
{
throw;
}
catch (Exception)
{
throw;
}
}
public UserPrincipal GetUser(String sUserName)
{
PrincipalContext oPrincipalContext = GetPrincipalContext();
UserPrincipal oUserPrincipal = UserPrincipal.FindByIdentity(oPrincipalContext, sUserName);
return oUserPrincipal;
}
public GroupPrincipal GetGroup(string sGroupName)
{
PrincipalContext oPrincipalContext = GetPrincipalContext();
GroupPrincipal oGroupPrincipal = GroupPrincipal.FindByIdentity(oPrincipalContext, sGroupName);
return oGroupPrincipal;
}
public PrincipalContext GetPrincipalContext()
{
PrincipalContext oPrincipalContext = new PrincipalContext(ContextType.Domain, sDomain, sDefaultOU, ContextOptions.Negotiate);
return oPrincipalContext;
}
I hope this code will be of use for you.
How to get user manager email id from active directory? I have written code with which I can get user's firstname, lastname, email id and his manager name based on userid, but I want to get manager email id along with his manager name.
Can somebody please help me how to get this? Here is my code:
protected void ddlAdsuser_SelectedIndexChanged(object sender, EventArgs e)
{
DirectoryEntry root = new DirectoryEntry("LDAP://RootDSE");
string myDomain = root.Properties["defaultNamingContext"].Value.ToString();
DirectoryEntry domain = new DirectoryEntry("LDAP://" + myDomain);
DirectorySearcher dsUsers = new DirectorySearcher(domain);
dsUsers.Filter = "(userPrincipalName=" + ddlAdsuser.Text + ")";
foreach (SearchResult sResultSet in dsUsers.FindAll())
{
lblfname.Text = GetProperty(sResultSet, "givenName");
lbllname.Text = GetProperty(sResultSet, "sn");
lblemail.Text = GetProperty(sResultSet, "mail");
string Manager = string.Empty;
Manager = GetProperty(sResultSet, "manager");
if (Manager != "")
{
if (Manager.Contains("CN="))
{
int Length = Manager.IndexOf(',');
Manager = Manager.Substring(3, Length - 3);
}
else
{
Manager = string.Empty;
}
}
lblManagerID.Text = Manager; //Here displaying the manager name.
}
}
public static string GetProperty(SearchResult searchResult, string PropertyName)
{
if (searchResult.Properties.Contains(PropertyName))
{
return searchResult.Properties[PropertyName][0].ToString();
}
else
{
return string.Empty;
}
}
DirectorySearcher objDirSearch = new DirectorySearcher(SearchRoot);
DirectoryEntry dentUser = null;
string pstrFieldName, pstrValue;
pstrFieldName = "company";
pstrValue = "12345"; //Employee number
/*setting the filter as per the employee number*/
objDirSearch.Filter = "(&(objectClass=user)(" + pstrFieldName + "=" + pstrValue + "))";
SearchResult objResults = objDirectorySearch.FindOne();
dentUser = new DirectoryEntry(objResults.Path);}
string strManager = dentUser.Properties["manager"].Value.ToString();
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.DistinguishedName, strManager);
string strManagerMailID = user.EmailAddress;
Simple code and working great:
public static string GetEmail(string userId)
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, userId);
return user.EmailAddress;
}
You must add assembly System.DirectoryServices.AccountManagement.dll.
If you have any troubles with connection to AD, you can try to add AD server name in PrincipalContext constructor.
Just do a second search for the manager.
Note that you way of building the query filter is buggy, you need to escape some characters (Especially the " quote) in order to avoid broken queries depending on user input.
I just want to Add a new method on an existing code below.
Method is a simply check a given User_ID if it is exists on the AD.
It's my 1st time dealing with AD.
public class AD
{
// Fields
private static string ADPassword = ConfigurationManager.AppSettings["ADPassword"].ToString();
private static string ADPath = ConfigurationManager.AppSettings["ADConnection"].ToString();
private static string ADServerName = ConfigurationManager.AppSettings["ADServerName"].ToString();
private static string ADUserName = ConfigurationManager.AppSettings["ADUserName"].ToString();
// Methods
public static string GetLogin(string sUserName, string sPassword)
{
try
{
DirectoryEntry entry = new DirectoryEntry(ADPath, ADServerName + sUserName, sPassword);
object nativeObject = entry.NativeObject;
return string.Empty;
}
catch
{
return "Invalid Username or Password";
}
}
public static string Update(string sUserName, string sOldPassword, string sNewPassword)
{
string message;
try
{
DirectoryEntry searchRoot = new DirectoryEntry();
searchRoot.Path = ADPath;
searchRoot.Username = ADServerName + ADUserName;
searchRoot.Password = ADPassword;
DirectorySearcher searcher = new DirectorySearcher(searchRoot);
searcher.Filter = "(SAMAccountName=" + sUserName + ")";
DirectoryEntry directoryEntry = searcher.FindOne().GetDirectoryEntry();
directoryEntry.Invoke("ChangePassword", new object[] { sOldPassword, sNewPassword });
directoryEntry.CommitChanges();
directoryEntry.Close();
message = string.Empty;
}
catch (Exception exception)
{
try
{
message = exception.InnerException.Message;
}
catch
{
message = exception.Message;
}
}
return message;
}
}
Which version of the .NET Framework are you on??
In .NET before 3.5, you could probably do a DirectorySearch on the whole server (or alternatively a more constrained subtree):
public bool UserExists(string userName)
{
DirectoryEntry searchRoot = new DirectoryEntry("LDAP://dc=yourcompany,dc=com", userName, password);
DirectorySearcher searchForUser = new DirectorySearcher(searchRoot);
searchForUser.SearchScope = SearchScope.SubTree;
searchForUser.Filter = string.Format("(&(objectCategory=Person)(anr={0}))", userName);
if(searchForUser.FindOne() != null)
{
return true;
}
else
{
return false;
}
}
This is just off the top of my head, can't test it right now. This will search in your entire domain - check the LDAP path for the searchRoot - it would have to be something like
LDAP://dc=yourcompany,dc=com
or if you want to search just inside the "Users" container:
LDAP://cn=Users,dc=yourcompany,dc=com
With .NET 3.5 things got a lot easier - see this MSDN Article for a lot of useful info on how to search and find users and groups in .NET 3.5 using the new System.DirectoryServices.AccountManagement namespace. You can basically now do a FindByIdentity call:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN");
UserPrincipal foundUser = UserPrincipal.FindByIdentity(ctx, "your user name");
and that's all there is.
Marc
If it's your first AD experience, it might be worth taking a look at this codeproject article: Howto: (Almost) Everything In Active Directory via C#. It contains lots of examples that might help you.
What do you mean exactly by User_ID? Account name? LDAP distinguished name?