How can I get a list of users from active directory?
If you are new to Active Directory, I suggest you should understand how Active Directory stores data first.
Active Directory is actually a LDAP server. Objects stored in LDAP server are stored hierarchically. It's very similar to you store your files in your file system. That's why it got the name Directory server and Active Directory
The containers and objects on Active Directory can be specified by a distinguished name
. The distinguished name is like this CN=SomeName,CN=SomeDirectory,DC=yourdomain,DC=com
. Like a traditional relational database, you can run query against a LDAP server. It's called LDAP query.
There are a number of ways to run a LDAP query in .NET. You can use DirectorySearcher from System.DirectoryServices
or SearchRequest from System.DirectoryServices.Protocol
.
For your question, since you are asking to find user principal object specifically, I think the most intuitive way is to use PrincipalSearcher from System.DirectoryServices.AccountManagement
. You can easily find a lot of different examples from google. Here is a sample that is doing exactly what you are asking for.
using (var context = new PrincipalContext(ContextType.Domain, "yourdomain.com"))
{
using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{
foreach (var result in searcher.FindAll())
{
DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
Console.WriteLine("First Name: " + de.Properties["givenName"].Value);
Console.WriteLine("Last Name : " + de.Properties["sn"].Value);
Console.WriteLine("SAM account name : " + de.Properties["samAccountName"].Value);
Console.WriteLine("User principal name: " + de.Properties["userPrincipalName"].Value);
Console.WriteLine();
}
}
}
Console.ReadLine();
Note that on the AD user object, there are a number of attributes. In particular, givenName
will give you the First Name
and sn
will give you the Last Name
. About the user name. I think you meant the user logon name. Note that there are two logon names on AD user object. One is samAccountName
, which is also known as pre-Windows 2000 user logon name. userPrincipalName
is generally used after Windows 2000.
How to efficiently obtain list of users from windows active directory using C#
I had a crack at this using a number of different approaches, as a learning experience.
What I found for myself was that all methods could list a set of adspath
values pretty quickly, but once introducing a Console.WriteLine in the iteration caused the performance to drastically vary.
My limited C# knowledge led me to experiment with various methods such as IEnumerator
straight over the DirectoryEntry, PrincipleSearcher
with context, but both of these methods are slow, and vary greatly depending on what is being done with the information
In the end, this is what I ended up with. It was far and away the fastest, and doesn't take any noticeable performance hit when increasing the options to parse.
Note: this is actually a complete copy/paste powershell wrapper for the class, as I am not currently near a VM with Visual Studio.
$Source = @"
// " " <-- this just makes the code highlighter work
// Syntax: [soexample.search]::Get("LDAP Path", "property1", "property2", "etc...")
// Example: [soexample.search]::Get("LDAP://CN=Users,DC=mydomain,DC=com","givenname","sn","samaccountname","distinguishedname")
namespace soexample
{
using System;
using System.DirectoryServices;
public static class search
{
public static string Get(string ldapPath, params string[] propertiesToLoad)
{
DirectoryEntry entry = new DirectoryEntry(ldapPath);
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.SearchScope = SearchScope.OneLevel;
foreach (string p in propertiesToLoad) { searcher.PropertiesToLoad.Add(p); }
searcher.PageSize = 100;
searcher.SearchRoot = entry;
searcher.CacheResults = true;
searcher.Filter = "(sAMAccountType=805306368)";
SearchResultCollection results = searcher.FindAll();
foreach (SearchResult result in results)
{
foreach (string propertyName in propertiesToLoad)
{
foreach (object propertyValue in result.Properties[propertyName])
{
Console.WriteLine(string.Format("{0} : {1}", propertyName, propertyValue));
}
}
Console.WriteLine("");
}
return "";
}
}
}
"@
$Asem = ('System.DirectoryServices','System')
Add-Type -TypeDefinition $Source -Language CSharp -ReferencedAssemblies $Asem
I ran this on a particular domain that had 160 users, and here is the outcome;
Using the example command in the code comments:
PS > Measure-Command { [soexample.search]::Get(args as above..) }
Output:
givenname : John
sn : Surname
samaccountname : john.surname
distinguishedname : CN=John Surname,CN=Users,DC=mydomain,DC=com
etc ... 159 more ...
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 431
Ticks : 4317575
TotalDays : 4.99719328703704E-06
TotalHours : 0.000119932638888889
TotalMinutes : 0.00719595833333333
TotalSeconds : 0.4317575
TotalMilliseconds : 431.7575
Every additional string argument given, seems to increase the total processing time by about 100ms.
Running it with only samaccountname
takes only 0.1s to list 160 users, parsed into the console.
Using Microsoft's example here, and modifying it to just list one property, took over 3 seconds, and every additional property took about a second.
A couple notes:
(sAMAccountType=805306368)
turns out to be more efficient than(&(objectClass=user)(objectCategory=person))
(see https://stackoverflow.com/a/10053397/3544399) and many other examplessearcher.CacheResults = true;
didn't seem to make any difference (in my domain anyway) whether it was true or explicitly false.searcher.PageSize = 100;
makes a measurable difference. I believe the defaultMaxPageSize
on a 2012R2 DC is 1000 (https://technet.microsoft.com/en-us/library/cc770976(v=ws.11).aspx)The properties are not case sensitive (i.e. whatever is given to the searcher is returned in
result.Properties.PropertyNames
, hence why theforeach
loop simply iterates thosepropertiesToLoad
)The three
foreach
loops at first glance seem un-necessary, but every successful removal of a loop ended up costing much more overhead in cast conversions and running through method extensions.
There may be better ways still, I've seen some elaborate examples with threading and result caching that I just wouldn't know what to do with, but the tuned DirectorySearcher
does seem to be the most flexible, and this code here only requires System
and System.DirectoryServices
namespaces.
Not sure exactly what you do with your "//do stuff"
as to whether this would help or not, but I did find this an interesting exercise as I didn't know there were so many ways to do something like this.
Get List of all users of specific ActiveDirectoryGroup
As @Chris Pratt mentioned in his comment, there is no build in way to solve this issue with asp.net core 2.0, but there is an easy way, doing it with C#.
So what I did is very simple, first I created the following class (heavily inspired by: https://stackoverflow.com/a/19604001/9641435)
using System.DirectoryServices.AccountManagement; //can be downloaded via NUGET Package manager
using System.Collections.Generic;
namespace MYNAMESPACE
{
public static class ActiveDirectoryHelper
{
public static List<string> GetAllUserRealNamesFromAdGroup(string i_activeDirectyGroup)
{
var users = new List<string>();
using (var context = new PrincipalContext(ContextType.Domain, "MY.DOMAIN.NAME"))
{
using (var group = GroupPrincipal.FindByIdentity(context, i_activeDirectyGroup))
{
if (group != null)
{
var usersPrincipals = group.GetMembers(true);
foreach (UserPrincipal user in usersPrincipals)
{
//There are also other properties available, but in my case I just need the first and surname:
users.Add($"{user.GivenName} {user.Surname}");
}
}
}
return users;
}
}
}
}
And now from my Controller I simply do the following:
[HttpGet]
public IActionResult MyAction()
{
var myVm = new MyViewModel();
List<string> userList = ActiveDirectoryHelper.GetAllUserRealNamesFromAdGroup("MYGROUP");
//do whatever you want with this list right here:
return View(myVm);
}
I hope this post might help someone else in the future, that's why I posted it as an answer.
How can I get all Active Directory Users username and display name
I did it this way it worked great:
1- Add reference to Active Directory services DLL
2- Add using in your controller:
using System.DirectoryServices.AccountManagement;
than I created a function to store All Active directory users in database table
bellow is the code hope help someone needs it.
public ActionResult Create()
{
List<MyADUsers> TheAllADUsers = new List<MyADUsers>();
var context = new PrincipalContext(ContextType.Domain, "MyDoman.org");
var searcher = new PrincipalSearcher(new UserPrincipal(context));
foreach (var result in searcher.FindAll())
{
TheAllADUsers.Add(new MyADUsers { ADUserName = result.SamAccountName, AD_IsMemberOf = result.UserPrincipalName, FullName = result.Name });
}
db.MyADUsersContext.AddRange(TheAllADUsers);
db.SaveChanges();
return View();
}
Add a value to all users in AD
You can use the PowerShell ActiveDirectory module, which is included in the Remote Server Administration Tools (RSAT). Details on how to install it are here.
Then you can use Get-ADUser
and pipe the results into Set-ADUser
. Something like this:
$badusers = Get-ADUser -Filter "company -ne 'Your Company Name'"
$badusers | Set-ADUser -Company "Your Company Name"
You could do this in one line, but I split it into two so you can inspect the $badusers
collection to actually see the users that you changed (just type $badusers
into the PowerShell prompt and hit enter).
It may be wise to limit it to, say, 5 or 10 users just to make sure it works the way you want before attempting to change every user. You can do this by adding -ResultSetSize 5
to the Get-ADUsers
line.
This also assumes you want to change all user objects to have your company name, even administrative accounts. Keep in mind that this will stop processing users if it hits one that you don't have permission to modify. If you want to limit it to a single OU, you can use the -SearchBase
parameter of Get-ADUsers
, like this:
$badusers = Get-ADUser -Filter "company -ne 'Your Company Name'" -SearchBase "OU=Users,DC=example,DC=com"
How to filter users based on several criteria in Powershell when using Get-AdUser
As Abraham pointed out in his helpful comment, you can do the filtering using exclusively the AD Filter / LDAP Filter.
Here is a -LDAPFilter
alternative:
$map = @{
department = @(
'Sales & Admin - All'
'Field - Support'
'HKLM - All'
'SOD - 1'
'Home - 1080'
)
title = @(
'Client Manager'
'Local Sales'
'Outside Sales'
'Region Manager'
'Deployment Manager'
)
}
$ldapfilter = "(&"
foreach($key in $map.Keys) {
$clause = "(|"
foreach($value in $map[$key]) {
$clause += "($key=$value)"
}
$clause += ")"
$ldapfilter += $clause
}
$ldapfilter += ")"
Get-ADUser -LDAPFilter $ldapfilter -Properties Department, Title, SamAccountName |
Export-Csv path\to\export.csv -NoTypeInformation
The title
filter is an exact match of each clause, hence the "get rid of / filter that list further of any other Titles
that have -
in their name" should be covered.
The generated LDAP String would look like this after formatting for readability:
(&
(|
(department=Sales & Admin - All)
(department=Field - Support)
(department=HKLM - All)
(department=SOD - 1)
(department=Home - 1080)
)
(|
(title=Client Manager)
(title=Local Sales)
(title=Outside Sales)
(title=Region Manager)
(title=Deployment Manager)
)
)
How can i get List of users from Azure AD?
using Microsoft.Graph;
using Microsoft.Graph.Auth;
using Microsoft.Identity.Client;
using System;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("application id")
.WithTenantId("tenant id")
.WithClientSecret("application secret")
.Build();
ClientCredentialProvider authenticationProvider = new ClientCredentialProvider(confidentialClientApplication);
GraphServiceClient graphServiceClient = new GraphServiceClient(authenticationProvider);
var result = graphServiceClient.Users.Request().GetAsync();
foreach (var item in result.Result)
{
Console.WriteLine(item.DisplayName);
}
Console.ReadKey();
}
}
}
UPDATE
1.https://github.com/microsoftgraph/msgraph-training-aspnet-core
You can download this project directly
2.https://github.com/microsoftgraph/msgraph-training-aspnet-core/tree/master/demo
This is the documentation required to establish the above.
3.The screenshot below is an example of me.This asp.net core mvc project using microsoft graph is feasible.
This is an example of a page-only lists ad users.Just put the following access token in var accessToken="your access token******"***;and you can run it.
<html>
<style>
.userItem {
background-color:lightgrey;
list-style-type: none;
margin: 0;
padding: 0;
}
.userItem p {
display: inline-block;
width:25%
}
.LicenseItem {
background-color: lightgoldenrodyellow;
margin: 0;
padding: 0;
height: 45%;
overflow: auto;
}
.LicenseItem p {
display: inline-block;
width: 20%;
}
.loadMore {
background-color: aqua;
font-style: italic;
text-align: center;
padding: 15px;
}
</style>
<body>
<div id="message"></div>
<div id="userListView">
<div class="userItem" style="background-color: aqua;font-style: italic;">
<hr>
<p> user display name </p>
<p> user email address </p>
<p> user principal name </p>
</div>
<div id="userList"></div>
<div id="loadMore" class="loadmore"></div>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
var accessToken="your access token*********";
var ItemView = " <div id='@id' class='userItem'><hr><p id='@id-obj' style='display:none'>@obj</p><p > @displayName </p><p > @mail </p><p > @upn </p></div>"
function initPage(){
$("#loadMore").empty();
$.ajax({
url: 'https://graph.microsoft.com/v1.0/users?$top=10',
type: 'get',
headers: {
"Content-type": 'application/json',
"Authorization":"Bearer " + accessToken
},
success: function (data) {
var userlist = data.value;
var nextpageUrl = data['@odata.nextLink'];
if(nextpageUrl){
$("#loadMore").append("<div onclick='loadMore(\""+ nextpageUrl +" \")'>load more...</div>");
}
userlist.forEach(element => {
var view = ItemView.replace(/@id/g,element.id).replace("@displayName",element.displayName).replace("@mail",element.mail).replace("@upn",element.userPrincipalName).replace("@obj",JSON.stringify(element));
console.log(JSON.stringify(element));
$("#userList").append(view);
});
},
error:function(data){
var response = JSON.parse(data.responseText)
document.getElementById("message").innerHTML="ERROR:" + response.error.message;
}
});
}
function loadMore(url){
$.ajax({
url: url,
type: 'get',
headers: {
"Content-type": 'application/json',
"Authorization":"Bearer " + accessToken
},
success: function (data) {
var userlist = data.value;
var nextpageUrl = data['@odata.nextLink'];
if(nextpageUrl){
$("#loadMore").empty();
$("#loadMore").append("<div onclick='loadMore(\""+ nextpageUrl +" \")'>load more...</div>");
}
userlist.forEach(element => {
var view = ItemView.replace(/@id/g,element.id).replace("@displayName",element.displayName).replace("@mail",element.mail).replace("@upn",element.userPrincipalName).replace("@obj",JSON.stringify(element));
$("#userList").append(view);
});
},
error:function(data){
var response = JSON.parse(data.responseText)
document.getElementById("message").innerHTML="ERROR:" + response.error.message;
}
});
}
initPage();
</script>
</html>
Related Topics
Create an Array or List of All Dates Between Two Dates
How to Bind Wpf Button to a Command in Viewmodelbase
How to Split a String by a Multi-Character Delimiter in C#
How to Parse Huge JSON File as Stream in JSON.Net
Up, Down, Left and Right Arrow Keys Do Not Trigger Keydown Event
How to Get Text Formatting with Itextsharp
C# Download All Files and Subdirectories Through Ftp
How to Represent 0.1 in Floating Point Arithmetic and Decimal
How to Use a C# Keyword as a Property Name
Can't View Designer When Coding a Form in C#
How to Deserialize a Child Object with Dynamic (Numeric) Key Names
What Are the Differences Between Delegates and Events
Create Instance of Generic Type Whose Constructor Requires a Parameter
Recommended Servicestack API Structure
Difference Between Observablecollection and Bindinglist