Làm cách nào để lấy danh sách người dùng từ thư mục đang hoạt động?


109

Làm cách nào để lấy danh sách người dùng từ thư mục đang hoạt động? Có cách nào để kéo tên người dùng, tên, họ không? Tôi đã thấy một bài đăng tương tự trong đó điều này đã được sử dụng:

 PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN");

Tôi chưa bao giờ làm bất cứ điều gì với thư mục hoạt động vì vậy tôi hoàn toàn bị mất. Mọi sự trợ giúp sẽ rất được trân trọng!


3
Đọc bài viết MSDN xuất sắc Quản lý Hiệu Trưởng Bảo mật thư mục trong .NET Framework 3.5 cho một giới thiệu tuyệt vời để sử dụng AD với .NET 3.5
marc_s

Có vẻ như bài viết của @ marc_s đã được lưu trữ, đây là liên kết được cập nhật
jb.

@marc_s Tôi rất thích đọc thưa ông, nhưng liên kết đã chết. Tôi cố gắng này blogs.msdn.microsoft.com/msdnmagazine/2008/01/16/... nhưng ngay cả các liên kết trên mà dẫn bài viết đến một trang di truyền cho tạp chí microsoft
Malcolm Salvador

1
@ Malky. Tôi đã tìm thấy đường đến bài viết. Sử dụng liên kết của nhận xét đầu tiên cho câu hỏi này và tải xuống số tháng 1 năm 2008 . Đừng quên bỏ chặn tệp chm trong trang thuộc tính của Explorer trước khi đọc.
OneWorld

Câu trả lời:


229

Nếu bạn chưa quen với Active Directory, tôi khuyên bạn nên hiểu cách Active Directory lưu trữ dữ liệu trước.

Active Directory thực sự là một máy chủ LDAP. Các đối tượng được lưu trữ trong máy chủ LDAP được lưu trữ theo thứ bậc. Nó rất giống với việc bạn lưu trữ tệp trong hệ thống tệp của mình. Đó là lý do tại sao nó có tên là Directory server và Active Directory

Các vùng chứa và đối tượng trên Active Directory có thể được chỉ định bởi a distinguished name. Tên phân biệt là như thế này CN=SomeName,CN=SomeDirectory,DC=yourdomain,DC=com. Giống như cơ sở dữ liệu quan hệ truyền thống, bạn có thể chạy truy vấn với máy chủ LDAP. Nó được gọi là truy vấn LDAP.

Có một số cách để chạy truy vấn LDAP trong .NET. Bạn có thể sử dụng DirectorySearcher từ System.DirectoryServiceshoặc SearchRequest từ System.DirectoryServices.Protocol.

Đối với câu hỏi của bạn, vì bạn đang yêu cầu tìm đối tượng chính của người dùng một cách cụ thể, tôi nghĩ cách trực quan nhất là sử dụng PrincipalSearcher từ System.DirectoryServices.AccountManagement. Bạn có thể dễ dàng tìm thấy rất nhiều ví dụ khác nhau từ google. Đây là một mẫu đang làm chính xác những gì bạn đang yêu cầu.

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();

Lưu ý rằng trên đối tượng người dùng AD, có một số thuộc tính. Đặc biệt, givenNamesẽ cung cấp cho bạn First Namesnsẽ cung cấp cho bạn Last Name. Về tên người dùng. Tôi nghĩ bạn có nghĩa là tên đăng nhập người dùng. Lưu ý rằng có hai tên đăng nhập trên đối tượng người dùng AD. Một là samAccountName, còn được gọi là tên đăng nhập người dùng trước Windows 2000. userPrincipalNamethường được sử dụng sau Windows 2000.


2
Có gì nếu máy chủ không chứa tên miền

Làm cách nào để bạn sử dụng cùng một mã để liệt kê người dùng từ một nhóm QUẢNG CÁO?
nJoshi,

Có cách nào sử dụng phương pháp này để thu hẹp tìm kiếm chỉ những người trong thư mục đã được chỉ định địa chỉ email không?
ARidder101

Không sao đâu, tôi đã đoán ra. Tôi chỉ cần thêm if (((UserPrincipal)result).EmailAddress != null)trước khi thêm kết quả vào danh sách của mình.
ARidder101

2
Và nếu máy tính hiện tại không thuộc tên miền thì sao?
Marcus

23

Nếu bạn muốn lọc các tài khoản đang hoạt động, hãy thêm tài khoản này vào mã của Harvey:

 UserPrincipal userPrin = new UserPrincipal(context);
 userPrin.Enabled = true;

sau lần đầu tiên sử dụng. Sau đó thêm

  searcher.QueryFilter = userPrin;

trước khi tìm thấy tất cả. Và điều đó sẽ giúp bạn có được những hoạt động tích cực.


Tôi không nghĩ bạn cần searcher.QueryFilter = userPrin;vì chúng tôi đã chuyển quyền chính của người dùng cho người tìm kiếm chính khi khởi chạy, nhưng nếu không, cảm ơn bạn đã biết mẹo chỉ lọc người dùng đang hoạt động!
Andrey

1
Yeah, Andrey là đúng Vì vậy, về cơ bản này có thể được thay thế bằng cách thêm thuộc tính này trong lần thứ hai sử dụng tuyên bố:using (var searcher = new PrincipalSearcher(new UserPrincipal(context){ Enabled = true }))
Marko Jovanov

Nhưng tôi nghĩ bạn phải kiểm tra xem Enabledcó giá trị nào trước không:if (userPrincipal.Enabled.HasValue)
JohnB

4

Chắc chắn tín dụng được chuyển đến @Harvey Kwok ở đây, nhưng tôi chỉ muốn thêm ví dụ này vì trong trường hợp của tôi, tôi muốn có được Danh sách Thành viên chính thực tế. Có lẽ sẽ hiệu quả hơn nếu lọc trước truy vấn này, nhưng trong môi trường nhỏ của tôi, sẽ dễ dàng hơn để kéo mọi thứ và sau đó lọc khi cần từ danh sách của tôi.

Tùy thuộc vào những gì bạn cần, bạn có thể không cần truyền tới DirectoryEntry, nhưng một số thuộc tính không có sẵn từ UserPrincipal.

using (var searcher = new PrincipalSearcher(new UserPrincipal(new PrincipalContext(ContextType.Domain, Environment.UserDomainName))))
{
    List<UserPrincipal> users = searcher.FindAll().Select(u => (UserPrincipal)u).ToList();
    foreach(var u in users)
        {
            DirectoryEntry d = (DirectoryEntry)u.GetUnderlyingObject();
            Console.WriteLine(d.Properties["GivenName"]?.Value?.ToString() + d.Properties["sn"]?.Value?.ToString());
        }
}

Xin vui lòng 'e' là gì?
Fandango68

1
Cảm ơn, không bao giờ nhận thấy điều đó. Tôi đã thay đổi nó, được cho là "u". Tôi cũng đã thêm? S để xử lý các giá trị null nếu thuộc tính bị thiếu.
Jordan

1

Bao gồm System.DirectoryServices.dll, sau đó sử dụng mã bên dưới:

DirectoryEntry directoryEntry = new DirectoryEntry("WinNT://" + Environment.MachineName);
string userNames="Users: ";

foreach (DirectoryEntry child in directoryEntry.Children)
{
    if (child.SchemaClassName == "User")
    {
        userNames += child.Name + Environment.NewLine   ;         
    }

}
MessageBox.Show(userNames);

1
@ Fandango68: LOL, đúng vậy !!! System.Windows.Forms.MessageBox.Show (ex.Message + ex.StackTrace);
Jhollman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.