TonyW TonyW - 5 months ago 77
Vb.net Question

Using PrincipalContext to search LDAP (Active Directory) for all usernames, and their information

I'm having problems with this code... apparently, it works, but is too slow for me, does anyone have any ideas? It slows down when I try to get access the following

Dim u As UserPrincipal = UserPrincipal.FindByIdentity(ctx, p.SamAccountName)


Again, the following code works just fine, but it's slow as crap. If I take out the above, piece of code and just search for
p.SamAccountName
it's done within 1 second, so I'm sure I'm doing something incorrect.

Dim sw As New Stopwatch

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

sw.Start()

DataGridView1.ColumnCount = 3
DataGridView1.Columns(0).Name = "Account Name"
DataGridView1.Columns(1).Name = "First Name"
DataGridView1.Columns(2).Name = "Last Name"

Dim ctx = New PrincipalContext(ContextType.Domain, "JOI", DomainName)
Dim userPrin As New UserPrincipal(ctx)
userPrin.Name = "*"
Dim searcher = New System.DirectoryServices.AccountManagement.PrincipalSearcher()
searcher.QueryFilter = userPrin
Dim results = searcher.FindAll()

For Each p As Principal In results
Dim u As UserPrincipal = UserPrincipal.FindByIdentity(ctx, p.SamAccountName)
Dim row As String() = New String() {u.SamAccountName, u.GivenName, u.Surname}
DataGridView1.Rows.Add(row)
Next

sw.Stop()
MessageBox.Show("Finished in :" & sw.Elapsed.Duration.Seconds & " seconds")

End Sub

Private Shared Function DomainName() As String

Dim objRootDSE As New DirectoryEntry("LDAP://RootDSE")
DomainName = objRootDSE.Properties("defaultNamingContext")(0)

End Function

Answer

You already have access to the UserPrincipal in your result from the search and then you are performing another new search for each item in the result. That is exactly what is slowing down your function.

I usually filter the filter (LINQ) and only take result items that are of UserPrincipal type. That way it's just one pass through search

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    sw.Start()

    DataGridView1.ColumnCount = 3
    DataGridView1.Columns(0).Name = "Account Name"
    DataGridView1.Columns(1).Name = "First Name"
    DataGridView1.Columns(2).Name = "Last Name"

    Using context As PrincipalContext = New PrincipalContext(ContextType.Domain, "JOI", DomainName)
        Using userPrin As UserPrincipal = New UserPrincipal(context)
            userPrin.Name = "*"
            Using searcher As PrincipalSearcher = New PrincipalSearcher(userPrin)

                Dim results = searcher _
                    .FindAll() _
                    .OfType(Of UserPrincipal)()

                For Each p As UserPrincipal In results
                    Dim row As String() = New String() {p.SamAccountName, p.GivenName, p.Surname}
                    DataGridView1.Rows.Add(row)
                Next
            End Using
        End Using
    End Using

    sw.Stop()
    MessageBox.Show("Finished in :" & sw.Elapsed.Duration.Seconds & " seconds")

End Sub