2

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
Nkosi
  • 235,767
  • 35
  • 427
  • 472
TonyW
  • 766
  • 8
  • 17

1 Answers1

1

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
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Testing this now, though after looking through what you're doing I see my issue... cannot believe I didn't see that. Still learning though, thanks. Will post as solution as soon as I test in a few minutes. – TonyW Jun 11 '16 at 04:13
  • Thank you for the help! Works like a charm, went from 10 seconds, to 1 for entire AD structure. – TonyW Jun 11 '16 at 06:06