I am finding user name from Active Directory by passing email id. It is working fine. But it takes 30-40 seconds to get the username. Is there any other better way to find the username from Active Directory by email address?
Please refer to my code:
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, "domainname"))
{
UserPrincipal userPrincipal = new UserPrincipal(context);
PrincipalSearcher principalSearch = new PrincipalSearcher(userPrincipal);
foreach (UserPrincipal result in principalSearch.FindAll())
{
if (result != null && result.EmailAddress != null && result.EmailAddress.Equals(user.Email, StringComparison.OrdinalIgnoreCase))
{
user.FirstName = result.GivenName;
user.LastName = result.Surname;
}
}
}
You don't need to enumerate all users to to find one of them! Try this code:
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, "domainname"))
{
UserPrincipal yourUser = UserPrincipal.FindByIdentity(context, EmailAddress);
if (yourUser != null)
{
user.FirstName = yourUser.GivenName;
user.LastName = yourUser.Surname;
}
}
If that shouldn't work, or if you need to search for several criteria at once, used the PrincipalSearcher with the QBE (query-by-example) approach - search the one user you need - don't cycle through all users!
// create your domain context
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, "domainname"))
{
// define a "query-by-example" principal -
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.EmailAddress = yourEmailAddress;
// 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 - "found" is of type "Principal" - it could be user, group, computer.....
}
}
using System.DirectoryServices.AccountManagement;
// Lock user
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
UserPrincipal yourUser = UserPrincipal.FindByIdentity(context, logonName);
if (yourUser != null)
{
if(!yourUser.IsAccountLockedOut())
{
yourUser.Enabled = False;
yourUser.Save();
}
}
}
Related
I have one gMSA user created. I am trying to get the user sid-
ContextType contextType= ContextType.Domain;
PrincipalContext domainContext = new PrincipalContext(contextType, domain);
using (var foundUser = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName))
{
if (foundUser != null)
{
identity = foundUser.Sid.Value;
result = true;
}
}
The gMSA user is under a domain such as contoso.ab.cd.com
I ran in to this issue as well. In my environment, I noticed that the gMSA accounts are not in the UserPrincipal at all. Rather, they are in ComputerPrincipal. Try the following:
ContextType contextType= ContextType.Domain;
PrincipalContext domainContext = new PrincipalContext(contextType, domain);
using (var foundUser = ComputerPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName))
{
if (foundUser != null)
{
identity = foundUser.Sid.Value;
result = true;
}
}
My C# application communicates with the active directory and is able to provide me when i select a user i can see the groups he is a member of and if i select the group i am able to see the users in the group. Now the new requirement i want to see the computers each user is associated with.
private void FillComputers()
{
computers.Items.Clear();
PrincipalContext PrincipalContext1 = new PrincipalContext(ContextType.Domain);
ComputerPrincipal cp = new ComputerPrincipal(PrincipalContext1);
PrincipalSearcher search = new PrincipalSearcher(cp);
foreach (var cpn in search.FindAll())
{
computers.Items.Add(cpn.SamAccountName);
}
}
Gives me all the computers how do i pass the selected user as a parameter to the FillComputers above??? Thanks in Advance for all your suggestions.
For example when i have users and i had to find out the groups they were memebers of i did this
The below fills the listbox with all users:
private void filluser()
{
// 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())
{
try
{
// do whatever here
UserPrincipal foundUser = found as UserPrincipal;
if (foundUser != null)
{
foundUser.IsAccountLockedOut();
user.Items.Add(foundUser.GivenName + " " + foundUser.Surname + " " + "[" + foundUser.SamAccountName + "]");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
To Fill another list box with the groups the users were members of I did this
private void fillmembersof()
{
Groups.Items.Clear();
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
String input = user.Text;
string username = input.Split(new char[] { '[', ']' })[1];
// define a "query-by-example" principal - here, we search for any UserPrincipal
UserPrincipal usr = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, username);
if (usr != null)
{
foreach (var group in usr.GetGroups())
{
Groups.Items.Add(group.Name);
}
usr.Dispose();
}
ctx.Dispose();
}
Than to fill the above text box based on users selected i did this:
private void user_SelectedIndexChanged(Object sender, EventArgs e)
{
fillmembersof();
**FillComputers();** -> i want to be able to do the same for computers the user has access to?????
Thanks you in advance for all your valuable suggestions!!!!
I need to let users bind there accounts to the Active Directory. This means that admin needs a GUI where he/she can write a Active Directory account like this : MyDomain\MyName and then get a validation if the users exists before save.
Im using this code to validate the name :
public static bool CheckActiveDirectoryAccount(string account)
{
string ADServer = null;
string ADDomain = null;
string ADUserName = null;
string ADUserPassword = null;
SetADSettings(out ADServer, out ADDomain, out ADUserName, out ADUserPassword);
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, ADServer, ADUserName, ADUserPassword))
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(context, account))
{
if(user != null)
return true;
else
return false;
}
}
}
The problem with this code is that there seems to be no way to check the user for a specific domain? Instead I have to input the server, if I try to input the domain instead there will be exception(Server not found).
How do I let the admin enter domain and username of a AD account and then check it against the AD?
I am able to pass the domain into the principalcontext without issue, I'm not passing in the server. I would expect this to work for you.
public static bool CheckActiveDirectoryAccount(string account, string domain)
{
using (var pc = new PrincipalContext(ContextType.Domain, domain))
{
// Find a user
UserPrincipal user = UserPrincipal.FindByIdentity(pc, account);
if (user == null)
return false;
return true;
}
}
I have noticed poor performance when passing in the NetBIOS domain name, though it does work. As a result I pass in the DNS domain name whenever possible.
I ended up with this :
public static string CheckActiveDirectoryAccount(string account)
{
UserPrincipal user;
PrincipalContext context;
List<string> userPrincipalNameList;
string ADServer = null;
string ADUserName = null;
string ADUserPassword = null;
string userAccount;
account = account.ToLower();
GetADSettings(out ADServer, out ADUserName, out ADUserPassword);
if (ADUserName.Length > 0)
context = new PrincipalContext(ContextType.Domain, ADServer, null, ADUserName, ADUserPassword);
else
context = new PrincipalContext(ContextType.Domain, ADServer);
using (context)
{
if((user = UserPrincipal.FindByIdentity(context, account)) == null)
{
if(account.Contains("\\"))
{
userPrincipalNameList = user.UserPrincipalName.Split('\\').ToList();
if (userPrincipalNameList.Count > 0)
user = UserPrincipal.FindByIdentity(context, userPrincipalNameList[0]);
}
}
if (user != null)
{
using (user)
{
userPrincipalNameList = user.UserPrincipalName.Split('#').ToList();
userAccount = userPrincipalNameList.First();
if (userPrincipalNameList.Count > 1)
userAccount = userPrincipalNameList.Last() + "\\" + userAccount;
if (user != null)
return userAccount.ToLower();
}
}
}
return string.Empty;
}
I am logged in under user User001 under domain DomainA and with password Pass001.
I use this code
//var principalContext = new PrincipalContext(
//ContextType.Domain,
//"DomainA",
//"User001",
//"Pass001");
var principalContext = new PrincipalContext(
ContextType.Domain,
domain,
userName,
password);
var userPrincipal = new UserPrincipal(principalContext);
And userPrincipal is always NULL.
How to fix it?
Somehow this code I found is working fine...
using (var context = new PrincipalContext(ContextType.Domain))
{
using (UserPrincipal principal = UserPrincipal.FindByIdentity(context, userName))
{
var uGroups = principal.GetGroups();
foreach (var group in uGroups)
{
Debug.WriteLine(group.DisplayName);
}
}
}
When using DirectoryEntry, it is possible to set the CN of the new user account, but how to do it using UserPrincipal? The property is readonly.
// From : http://msdn.microsoft.com/en-us/magazine/cc135979.aspx
DirectoryEntry container = new DirectoryEntry("LDAP://ou=TechWriters,dc=fabrikam,dc=com");
// create a user directory entry in the container
DirectoryEntry newUser = container.Children.Add("cn=user1Acct", "user");
// add the samAccountName mandatory attribute
newUser.Properties["sAMAccountName"].Value = "User1Acct";
// save to the directory
newUser.CommitChanges();
But using UserPrincipal:
// For the example
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, null, "ou=TechWriters,dc=fabrikam,dc=com")
{
using (UserPrincipal user = new UserPrincipal(ctx, "User1Acct", "pwd", true))
{
// I would like to do :
user.DistinguishedName = "user1Acct";
//
user.Save();
}
}
Not the answer you want, but to my knowledge its not doable that way... The CN is 'protected' om the userprinciple class, as too much elsewhere relies on that being stable information.
I don't know why one would mix things up, but you could try this:
using (var ctx = new PrincipalContext(ContextType.Domain, null, "ou=TechWriters,dc=fabrikam,dc=com"))
{
using (var user = new UserPrincipal(ctx, "User1Acct", "pwd", true))
{
user.Save();
}
using (var entry = new DirectoryEntry("LDAP://cn=User1Acct;ou=TechWriters,dc=fabrikam,dc=com",null,null,AuthenticationTypes.Secure))
{
entry.Rename("cn=user1Acct");
}
}
(Maybe getting the LDAP string from the userPrinciple instead of hardcoding)
I do not have the possibillity to test this though..