ฉันจะรับรายชื่อผู้ใช้จาก Active Directory ได้อย่างไร


109

ฉันจะรับรายชื่อผู้ใช้จาก Active Directory ได้อย่างไร มีวิธีดึง username, firstname, lastname หรือไม่? ฉันเห็นโพสต์ที่คล้ายกันซึ่งใช้สิ่งนี้:

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

ฉันไม่เคยทำอะไรกับไดเรกทอรีที่ใช้งานอยู่ดังนั้นฉันจึงหลงทาง ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมอย่างมาก!


3
อ่านบทความ MSDN ที่ยอดเยี่ยมการจัดการหลักการรักษาความปลอดภัยของไดเรกทอรีใน. NET Framework 3.5สำหรับบทนำที่ยอดเยี่ยมในการใช้ AD กับ. NET 3.5
marc_s

ดูเหมือนว่าบทความของ @ marc_s จะถูกเก็บถาวรนี่คือลิงค์ที่อัปเดต
jb

@marc_s ฉันชอบที่จะอ่านคุณชาย แต่ลิงก์นั้นตายไปแล้ว ฉันลองใช้blogs.msdn.microsoft.com/msdnmagazine/2008/01/16/…แต่ลิงก์ในบทความนั้นยังนำไปสู่หน้าพันธุกรรมสำหรับนิตยสารไมโครซอฟท์
Malcolm Salvador

1
@ Malky.Kid ฉันพบทางไปที่บทความแล้ว ใช้การเชื่อมโยงของความคิดเห็นแรกกับคำถามนี้และดาวน์โหลดปัญหามกราคม 2008 อย่าลืมปลดบล็อก chm-file ในหน้าคุณสมบัติ Explorer ก่อนอ่าน
OneWorld

คำตอบ:


229

หากคุณเพิ่งเริ่มใช้ Active Directory ขอแนะนำให้คุณทำความเข้าใจว่า Active Directory จัดเก็บข้อมูลอย่างไรก่อน

Active Directory เป็นเซิร์ฟเวอร์ LDAP ออบเจ็กต์ที่จัดเก็บในเซิร์ฟเวอร์ LDAP จะถูกจัดเก็บตามลำดับชั้น คล้ายกับคุณเก็บไฟล์ไว้ในระบบไฟล์ของคุณ นั่นเป็นเหตุผลว่าทำไมจึงมีเซิร์ฟเวอร์ชื่อไดเรกทอรีและ Active Directory

คอนเทนเนอร์และอ็อบเจ็กต์บน Active Directory สามารถระบุได้โดยไฟล์distinguished name. CN=SomeName,CN=SomeDirectory,DC=yourdomain,DC=comชื่อที่แตกต่างเป็นเช่นนี้ เช่นเดียวกับฐานข้อมูลเชิงสัมพันธ์แบบดั้งเดิมคุณสามารถเรียกใช้แบบสอบถามกับเซิร์ฟเวอร์ LDAP เรียกว่าการสืบค้น LDAP

มีหลายวิธีในการเรียกใช้แบบสอบถาม LDAP ใน. NET คุณสามารถใช้DirectorySearcherจากSystem.DirectoryServicesหรือSearchRequestSystem.DirectoryServices.Protocolจาก

สำหรับคำถามของคุณเนื่องจากคุณจะถามเพื่อหาวัตถุผู้ใช้หลักโดยเฉพาะอย่างยิ่งผมคิดว่าวิธีที่ง่ายที่สุดคือการใช้PrincipalSearcherSystem.DirectoryServices.AccountManagementจาก คุณสามารถค้นหาตัวอย่างต่างๆมากมายจาก google ได้อย่างง่ายดาย นี่คือตัวอย่างที่ทำในสิ่งที่คุณต้องการ

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

โปรดสังเกตว่าบนวัตถุผู้ใช้ AD มีแอตทริบิวต์จำนวนหนึ่ง โดยเฉพาะอย่างยิ่งgivenNameที่จะทำให้คุณFirst Nameและจะทำให้คุณsn Last Nameเกี่ยวกับชื่อผู้ใช้ ฉันคิดว่าคุณหมายถึงชื่อล็อกออนของผู้ใช้ โปรดสังเกตว่ามีชื่อล็อกออนสองชื่อบนวัตถุผู้ใช้ AD หนึ่งคือsamAccountNameซึ่งเรียกอีกอย่างว่าชื่อล็อกออนของผู้ใช้ก่อน Windows 2000 userPrincipalNameโดยทั่วไปจะใช้หลัง Windows 2000


2
จะเกิดอะไรขึ้นถ้าเซิร์ฟเวอร์ไม่มีโดเมน

คุณใช้รหัสเดียวกันเพื่อแสดงรายชื่อผู้ใช้จากกลุ่มโฆษณาได้อย่างไร
nJoshi

มีวิธีใดบ้างที่ใช้วิธีนี้เพื่อ จำกัด การค้นหาให้แคบลงเฉพาะผู้ที่อยู่ในไดเร็กทอรีที่ได้รับการกำหนดที่อยู่อีเมล
ARidder101

ไม่เป็นไรฉันคิดออกแล้ว ฉันต้องเพิ่มif (((UserPrincipal)result).EmailAddress != null)ก่อนที่จะเพิ่มผลลัพธ์ในรายการของฉัน
ARidder101

2
และจะเกิดอะไรขึ้นถ้าคอมพิวเตอร์เครื่องปัจจุบันไม่ได้เป็นของโดเมน?
Marcus

23

หากคุณต้องการกรองบัญชีที่ใช้งานอยู่ให้เพิ่มสิ่งนี้ในรหัสของ Harvey:

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

หลังจากใช้ครั้งแรก จากนั้นเพิ่ม

  searcher.QueryFilter = userPrin;

ก่อนที่จะพบทั้งหมด และนั่นจะทำให้คุณได้รับสิ่งที่กระตือรือร้น


ฉันไม่คิดว่าคุณต้องการsearcher.QueryFilter = userPrin;เพราะเราได้ส่งผู้ใช้หลักไปยังผู้ค้นหาหลักในการเริ่มต้นแล้ว แต่อย่างอื่นขอขอบคุณสำหรับเคล็ดลับในการกรองผู้ใช้ที่ใช้งานอยู่เท่านั้น!
Andrey

1
ใช่ Andrey พูดถูกโดยพื้นฐานแล้วสิ่งนี้สามารถแทนที่ได้ด้วยการเพิ่มคุณสมบัตินี้ในคำสั่งที่สอง:using (var searcher = new PrincipalSearcher(new UserPrincipal(context){ Enabled = true }))
Marko Jovanov

แต่ฉันคิดว่าคุณต้องทดสอบว่าEnabledมีค่าก่อน:if (userPrincipal.Enabled.HasValue)
JohnB

4

แน่นอนเครดิตไปที่ @Harvey Kwok ที่นี่ แต่ฉันแค่ต้องการเพิ่มตัวอย่างนี้เพราะในกรณีของฉันฉันต้องการได้รับรายชื่อ UserPrincipals จริง อาจมีประสิทธิภาพมากกว่าในการกรองแบบสอบถามนี้ล่วงหน้า แต่ในสภาพแวดล้อมขนาดเล็กของฉันมันง่ายกว่าที่จะดึงทุกอย่างแล้วกรองตามต้องการในภายหลังจากรายการของฉัน

คุณอาจไม่จำเป็นต้องแคสต์ไปยัง DirectoryEntry ทั้งนี้ขึ้นอยู่กับสิ่งที่คุณต้องการ แต่คุณสมบัติบางอย่างไม่สามารถใช้ได้จาก 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());
        }
}

'e' คืออะไร?
Fandango68

1
ขอบคุณไม่เคยสังเกตเลย ฉันเปลี่ยนมันควรจะเป็น "คุณ" ฉันยังเพิ่มเพื่อจัดการกับค่า null หากคุณสมบัติหายไป
จอร์แดน

1

รวม System.DirectoryServices.dll จากนั้นใช้รหัสด้านล่าง:

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: ฮ่า ๆ ใช่แล้ว !!! System.Windows.Forms.MessageBox.Show (เช่นข้อความ + เช่น StackTrace);
Jhollman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.