How to search all the user accounts in a domain in .NET? - c#

How do I search all the user accounts in a domain in .NET?
Not the computer names in the domain, but the user accounts, that's what you are using to log on Windows.

You can try the following.
PrincipalContext ctx = new PrincipalContext(ContextType.Machine,Environment.MachineName);
UserPrincipal user = new UserPrincipal(ctx);
user.Name = "*";
PrincipalSearcher ps = new PrincipalSearcher();
ps.QueryFilter = user;
PrincipalSearchResult<Principal> result = ps.FindAll();
foreach (Principal p in result)
{
using (UserPrincipal up = (UserPrincipal)p)
{
MessageBox.Show(up.Name);
}
}
Or this:
using System.Management;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
SelectQuery query = new SelectQuery("Win32_UserAccount");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject envVar in searcher.Get())
{
Console.WriteLine("Username : {0}", envVar["Name"]);
}
Console.ReadLine();
}
See also How to list all Windows Users.

You can use something like the following:
List<string> LdapUsers = new List<string>();
if (String.IsNullOrWhiteSpace(domain))
{
string username = WindowsIdentity.GetCurrent().Name;
domain = username.Substring(0, username.IndexOf("\\"));
}
PrincipalContext context;
if (!String.IsNullOrWhiteSpace(user) && !String.IsNullOrWhiteSpace(password) && !String.IsNullOrWhiteSpace(domain))
context = new PrincipalContext(ContextType.Domain, domain, user, password);
if (!String.IsNullOrWhiteSpace(domain))
context = new PrincipalContext(ContextType.Domain, domain);
else
context = new PrincipalContext(ContextType.Domain);
UserPrincipal userP = new UserPrincipal(context);
userP.Enabled = true;
PrincipalSearcher pS = new PrincipalSearcher();
pS.QueryFilter = userP;
PrincipalSearchResult<Principal> result = pS.FindAll();
foreach (Principal p in result)
LdapUsers.Add(domain + "\\" + p.SamAccountName);

One more way to search for domain users:
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using (var domain = Domain.GetCurrentDomain())
using (var directoryEntry = domain.GetDirectoryEntry())
using (var directorySearcher = new DirectorySearcher(directoryEntry, "(&(objectCategory=person)(objectClass=user))"))
{
directorySearcher.PageSize = 1000;
using (var searchResults = directorySearcher.FindAll())
{
foreach (SearchResult searchResult in searchResults)
{
using (var userEntry = searchResult.GetDirectoryEntry())
{
Console.WriteLine(userEntry.Properties["cn"][0]);
}
}
}
}

Related

get all users from a group in Active Directory using GroupPrincipal

Im trying to get all users of a particular group in AD but i am getting Exception : "The specified directory service attribute or value does not exist."
//using (var principalContext = new PrincipalContext(ContextType.Domain))
using (var principalContext = new PrincipalContext(ContextType.Domain, "domainName"))
{
//using (var group = GroupPrincipal.FindByIdentity(context, windowsGroup.TrimEnd('*')))
using (var groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, "groupName"))
{
if (groupPrincipal != null)
{
var users = groupPrincipal.GetMembers();
foreach (UserPrincipal userPrincipal in users)
{
//user variable has the details about the user
}
}
}
}
use container to specify your root
using (var principalContext = new PrincipalContext(ContextType.Domain, "TEST.COM", "DC=TEST,DC=COM"))
{
//using (var group = GroupPrincipal.FindByIdentity(context, windowsGroup.TrimEnd('*')))
using (var groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, "groupName"))
{
if (groupPrincipal != null)
{
var users = groupPrincipal.GetMembers();
foreach (UserPrincipal userPrincipal in users)
{
//user variable has the details about the user
}
}
}
}

What info do I need to connect to Active Directory in C#?

I need to connect to a clients AD server to display information for all users. They've given me the following:
fqdn, netbios name and a domain controller. Is this enough to connect?
using (var context = new PrincipalContext(ContextType.Domain, "",))
using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{
foreach (var result in searcher.FindAll())
{
DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
}
}
Thanks!
I think Ryan was showing you the old way to do it. From your code it looks like you are using the newer classes.
// create a principal searcher for running a search operation
using (PrincipalSearcher pS = new PrincipalSearcher(uParams))
{
// assign the query filter property for the principal object you created
// you can also pass the user principal in the PrincipalSearcher constructor
pS.QueryFilter = uParams;
// run the query
using (PrincipalSearchResult<Principal> results = pS.FindAll())
{
foreach (Principal item in results)
{
UserPrincipal u = item as UserPrincipal;
list.Add(new MyCustomClass(u.UserPrincipalName)
{
Cn = u.Name,
Email = u.EmailAddress,
EmployeeId = u.EmployeeId,
NameFirst = u.GivenName,
NameLast = u.Surname,
ObjectSid = u.Sid.ToString(),
DistinguishedName = u.DistinguishedName,
SamAccount = u.SamAccountName
});
}
}
}
Note that the AD still imposes sometihng like a 1500 item limit on your queries so you will likely need to send your DirectoryEntry top to something like this:
/// <summary>
/// group member enumeration, simple and fast for large AD groups
/// </summary>
/// <param name="deGroup"></param>
/// <returns>list if distinguished names</returns>
public static List<string> GetMemberList(DirectoryEntry deGroup)
{
List<string> list = new List<string>();
DirectoryEntry entry = deGroup;
uint rangeStep = 1000;
uint rangeLow = 0;
uint rangeHigh = rangeLow + (rangeStep - 1);
bool lastQuery = false;
bool quitLoop = false;
do
{
string attributeWithRange;
if (!lastQuery)
{
attributeWithRange = String.Format("member;range={0}-{1}", rangeLow, rangeHigh);
}
else
{
attributeWithRange = String.Format("member;range={0}-*", rangeLow);
}
using (DirectorySearcher searcher = new DirectorySearcher(entry))
{
searcher.Filter = "(objectClass=*)";
//searcher.Filter = LdapObjectMgr.filterDisabledUsers;
searcher.PropertiesToLoad.Clear();
searcher.PropertiesToLoad.Add(attributeWithRange);
SearchResult results = searcher.FindOne();
foreach (string res in results.Properties.PropertyNames)
{
//list the property names
System.Diagnostics.Debug.WriteLine(res.ToString());
}
if (results.Properties.Contains(attributeWithRange))
{
foreach (object obj in results.Properties[attributeWithRange])
{
//Console.WriteLine(obj.GetType());
if (obj.GetType().Equals(typeof(System.String)))
{
}
else if (obj.GetType().Equals(typeof(System.Int32)))
{
}
//Console.WriteLine(obj.ToString());
list.Add(obj.ToString());
}
if (lastQuery)
{
quitLoop = true;
}
}
else
{
if (lastQuery == false)
{ lastQuery = true; }
else
{ quitLoop = true; }
}
if (!lastQuery)
{
rangeLow = rangeHigh + 1;
rangeHigh = rangeLow + (rangeStep - 1);
}
}
}
while (!quitLoop);
return list;
}
To connect via C# you will need something like this:
DirectoryEntry child = new DirectoryEntry("LDAP://" + domainControllerName + "/" +
objectDn, userName, password);
If you have the domain controller name, the object domain, a user name and a password, you should be good to go.
Just a heads up, you got downvoted because you didn't mention anything that you tried previously.

How to get list of Users from Active Directory by attributes such as Department

I need to provide a search on Active Directory using filters such as Display name, Telephone and Department. Display name and Telephone are easy but I'm stuck on department. This is the bit that works:
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
UserPrincipal userPrincipal = new UserPrincipal(context);
if (txtDisplayName.Text != "")
userPrincipal.DisplayName = "*" + txtDisplayName.Text + "*";
using (PrincipalSearcher searcher = new PrincipalSearcher(userPrincipal))
{
foreach (Principal result in searcher.FindAll())
{
DirectoryEntry directoryEntry = result.GetUnderlyingObject() as DirectoryEntry;
DataRow drName = dtProfile.NewRow();
drName["displayName"] = directoryEntry.Properties["displayName"].Value;
drName["department"] = directoryEntry.Properties["department"].Value;
dtProfile.Rows.Add(drName);
}
}
}
I was hoping that I could just add something like:
DirectoryEntry userDirectoryEntry = userPrincipal.GetUnderlyingObject() as DirectoryEntry;
if (ddlDepartment.SelectedValue != "")
userDirectoryEntry.Properties["title"].Value = ddlDepartment.SelectedValue;
But that doesn't work. Anyone know how I can do this?
Edit:
I'm an idiot, changed the search term and found the answer. The extra fields are called attibutes. Thanks Raymund Macaalay for your blog article on extending Principals.
My extended UserPrincipal:
[DirectoryObjectClass("user")]
[DirectoryRdnPrefix("CN")]
public class UserPrincipalExtended : UserPrincipal
{
public UserPrincipalExtended(PrincipalContext context) : base(context)
{
}
[DirectoryProperty("department")]
public string department
{
get
{
if (ExtensionGet("department").Length != 1)
return null;
return (string)ExtensionGet("department")[0];
}
set { this.ExtensionSet("department", value); }
}
}
Since you've already extended the UserPrincipal to include the Department attribute, you'll need to use that extended version of the user principal when you want to search.
Try this:
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
UserPrincipalExtended userPrincipal = new UserPrincipalExtended(context);
if (txtDisplayName.Text != "")
{
userPrincipal.DisplayName = "*" + txtDisplayName.Text + "*";
}
if (!string.IsNullOrEmpty(txtDepartment.Text.Trim())
{
userPrincipal.department = txtDepartment.Text.Trim();
}
using (PrincipalSearcher searcher = new PrincipalSearcher(userPrincipal))
{
foreach (Principal result in searcher.FindAll())
{
UserPrincipalExtended upe = result as UserPrincipalExtended;
if (upe != null)
{
DataRow drName = dtProfile.NewRow();
drName["displayName"] = upe.DisplayName;
drName["department"] = upe.department;
dtProfile.Rows.Add(drName);
}
}
}
}

Get parent OU of user in Active Directory using C#

I want to check, if a a user is in a specific parent OU.
How can I do that?
Check below code for a clear desciption of what I am looking for.
using System.DirectoryServices.AccountManagement;
public bool IsUserInOU(string samAccountName, string OUName){
using (var context = new PrincipalContext(ContextType.Domain))
{
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, samAccountName))
{
//Check if the user is in the OU specified in OUName
//Something like:
//return user.IsInOU(OUName);
}
}
}
public void TestIt_1(){
//The parent OU of this user is "AwesomeOU"
string samAccountName = "Joe";
string OUName = "AwesomeOU";
bool expected = true;
bool actual = IsUserInOU(samAccountName, OUName);
Assert.AreEqual(expected, actual);
}
public void TestIt_2(){
//The parent OU of this user is "WhateverOU"
string samAccountName = "Mike";
string OUName = "AwesomeOU";
bool expected = false;
bool actual = IsUserInOU(samAccountName, OUName);
Assert.AreEqual(expected, actual);
}
The Domain:
National OU
Awesome OU
Joe
Whatever OU
Mike
Solution 1 after empi's answer
With the information given by empi, I wrote the below method to extract the first OU in the DistinguishedName. Having done that, the rest is a breeze.
public static string GetOUForUser(string samAccountName)
{
using (var context = new PrincipalContext(ContextType.Domain))
{
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, samAccountName))
{
//System.Console.WriteLine(user.DistinguishedName);
int startIndex = user.DistinguishedName.IndexOf("OU=", 1) + 3; //+3 for length of "OU="
int endIndex = user.DistinguishedName.IndexOf(",", startIndex);
var group = user.DistinguishedName.Substring((startIndex), (endIndex - startIndex));
return group;
}
}
}
Solution 2 after JPBlanc's answer
public static string GetOUForUser(string samAccountName)
{
using (var context = new PrincipalContext(ContextType.Domain))
{
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, samAccountName))
{
using (DirectoryEntry deUser = user.GetUnderlyingObject() as DirectoryEntry)
{
using (DirectoryEntry deUserContainer = deUser.Parent)
{
return deUserContainer.Properties["Name"].Value.ToString();
}
}
}
}
}
Ok #Empi solution is working, but UserPrincipal is built on DirectoryEntry objects that provides a parent or container properties that just give you the object you are looking for, without using string way.
/* Retreiving a principal context
*/
PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "WM2008R2ENT:389", "dc=dom,dc=fr", "dom\\jpb", "MyPwd");
/* Retreive a user
*/
UserPrincipal user = UserPrincipal.FindByIdentity(domainContext, "user1");
/* Retreive the container
*/
DirectoryEntry deUser = user.GetUnderlyingObject() as DirectoryEntry;
DirectoryEntry deUserContainer = deUser.Parent;
Console.WriteLine (deUserContainer.Properties["distinguishedName"].Value);
This information is in UserPrincipal.DistinguishedName. You should check if DistinguishedName ends with "," + ou distinguished name (case insensitive). However, you must know the distingushed name of ou you're checking.
For example, if dn is: CN=Jeff Smith,OU=Sales,DC=Fabrikam,DC=COM, then it says that user is in OU=Sales,DC=Fabrikam,DC=COM ou.
This is how I would get the Distinguished Name for a specific AD user, hope it helps :-)
private static string GetDNOfUser(string user)
{
var ctx = new PrincipalContext(ContextType.Domain, Environmentals.Domain, Environmentals.OUPath);
//Creating object for search filter
UserPrincipal userPrin = new UserPrincipal(ctx)
{
//Only getting users with the same name as the input
Name = user
};
var searcher = new PrincipalSearcher
{
//Applying filter to query
QueryFilter = userPrin
};
//Finding the user
var results = searcher.FindOne();
searcher.Dispose();
//Return the distinguishedname
return results.DistinguishedName;
}

How to remove windows user account using C#

How to remove windows user account using C#?
Clause Thomsen was close, you need to pass the DirectoryEntry.Remove method a DirectoryEntry paramenter and not a string, like:
DirectoryEntry localDirectory = new DirectoryEntry("WinNT://" + Environment.MachineName.ToString());
DirectoryEntries users = localDirectory.Children;
DirectoryEntry user = users.Find("userName");
users.Remove(user);
Something like this should do the trick(not tested):
DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName);
DirectoryEntries entries = localMachine.Children;
DirectoryEntry user = entries.Remove("User");
entries.CommitChanges();
Alternatively using System.DirectoryServices.AccountManagement in .NET 3.5:-
http://msdn.microsoft.com/en-us/library/bb924557.aspx
using System;
using System.DirectoryServices.AccountManagement;
namespace AdministratorsGroupSample
{
class Program
{
static void Main(string[] args)
{
PrincipalContext ctx = new PrincipalContext(ContextType.Machine);
GroupPrincipal grpp = new GroupPrincipal(ctx);
UserPrincipal usrp = new UserPrincipal(ctx);
PrincipalSearcher ps_usr = new PrincipalSearcher(usrp);
PrincipalSearchResult<Principal> fr_usr = ps_usr.FindAll();
PrincipalSearcher ps_grp = new PrincipalSearcher(grpp);
PrincipalSearchResult<Principal> fr_grp = ps_grp.FindAll();
foreach (var usr in fr_usr)
{
Console.WriteLine($"Name:{usr.Name} SID:{usr.Sid} Desc:{usr.Description}");
Console.WriteLine("\t Groups:");
foreach (var grp in usr.GetGroups())
{
Console.WriteLine("\t" + $"Name:{grp.Name} SID:{grp.Sid} Desc:{grp.Description}");
}
Console.WriteLine();
}
Console.WriteLine();
foreach (var grp in fr_grp)
{
Console.WriteLine($"{grp.Name} {grp.Description}");
}
Console.ReadLine();
}
private void Delete(string userName)
{
PrincipalContext ctx = new PrincipalContext(ContextType.Machine);
UserPrincipal usrp = new UserPrincipal(ctx);
usrp.Name = userName;
PrincipalSearcher ps_usr = new PrincipalSearcher(usrp);
var user = ps_usr.FindOne();
user.Delete();
}
}
}

Categories