VB.Net DirectorySearcher在更改为使用多个线程后返回0结果

时间:2014-09-24 19:33:48

标签: vb.net multithreading directoryservices

我有一个类在Active Directory中搜索所有OU,然后搜索其中的所有计算机对象。它工作得很好......然后我决定利用一些线程来允许OU搜索和计算机对象搜索同时运行。现在,计算机搜索者突然返回0结果......(没有错误,只是没有结果)

我还添加了一个额外的属性来加载(objectGUID),但我尝试删除它,但它没有解决问题。我看不出我做了什么来打破它。这可能是一种愚蠢的盯着我的脸,但我找不到它。我希望一副新鲜的眼睛能够发现我的错误。

在破碎的代码中,Public Sub FindComputers(...)就是我遇到问题的地方。 在工作代码中,它是Private Function FindComputers(...)。我改变它,因为它现在在一个单独的类中。

编辑: 我在FindComputers子上设置了一个断点并逐步完成它。行queryResults = searcher.FindAll()执行后,queryResults count始终为0.循环中的事件永远不会被触发。

提前致谢。

这是原始的WORKING代码:

Public Class ADSearcher

'Removed properties and events etc

Public Sub StartSearch()

#If Not Debug Then
    Try
#End If

    Dim rootEntry As New DirectoryEntry(RootPath)
    Dim rootNode As New TreeNode(rootEntry.Name)
    rootNode.Name = rootEntry.Path

    If Not IntegratedAuthentication Then
        rootEntry.Username = UserID
        rootEntry.Password = Password
    End If

    Dim searcher As New DirectorySearcher(rootEntry)
    searcher.PropertiesToLoad.AddRange(PropertiesToLoad)
    searcher.SearchScope = SearchScope
    searcher.PageSize = PageSize
    searcher.ServerTimeLimit = New TimeSpan(0, 10, 0)
    searcher.Filter = FilterString

    Dim queryResults As SearchResultCollection
    queryResults = searcher.FindAll()

    Dim result As SearchResult
    For Each result In queryResults

        FindComputers(result) 'Search the current OU for computer objects

        Dim childNode As New TreeNode(CStr(result.Properties("name")(0)))
        childNode.Name = result.Path
        rootNode.Nodes.Add(SearchSub(result, childNode))

        ouResultCount += 1
        RaiseEvent ResultFound(ouResultCount, pcResultCount)
    Next

    RaiseEvent SearchCompleted(rootNode)
    ouResultCount = 0 'Reset the result count
    pcResultCount = 0 'Reset the computer result count


#If Not Debug Then
    Catch Ex as Exception
        MsgBox(ex.Message, MsgBoxStyle.Critical)
    End Try
#End If

End Sub

Private Function SearchSub(ByVal parent As SearchResult, ByVal node As TreeNode)
#If Not Debug Then
    Try
#End If
    Dim subEntry As New DirectoryEntry(parent.Path)

    If Not IntegratedAuthentication Then
        subEntry.Username = UserID
        subEntry.Password = Password
    End If

    Dim searcher As New DirectorySearcher(subEntry)
    searcher.PropertiesToLoad.AddRange(PropertiesToLoad)
    searcher.SearchScope = SearchScope
    searcher.PageSize = PageSize
    searcher.ServerTimeLimit = New TimeSpan(0, 10, 0)
    searcher.Filter = FilterString

    Dim queryResults As SearchResultCollection
    queryResults = searcher.FindAll()

    Dim result As SearchResult
    For Each result In queryResults
        FindComputers(result) 'Search for computer objects in the current OU

        Dim childNode As New TreeNode(CStr(result.Properties("name")(0)))
        childNode.Name = result.Path
        SearchSub(result, childNode)
        node.Nodes.Add(childNode)
        ouResultCount += 1
        RaiseEvent ResultFound(ouResultCount, pcResultCount)
    Next

    Return node

#If Not Debug Then
    Catch Ex as Exception
        MsgBox(ex.Message, MsgBoxStyle.Critical)
    End Try
#End If

End Function

Private Function FindComputers(ByVal parent As SearchResult)
#If Not Debug Then
    Try
#End If
    Dim subEntry As New DirectoryEntry(parent.Path)

    If Not IntegratedAuthentication Then
        subEntry.Username = UserID
        subEntry.Password = Password
    End If

    Dim searcher As New DirectorySearcher(subEntry)
    searcher.PropertiesToLoad.AddRange(PropertiesToLoad)
    searcher.SearchScope = SearchScope
    searcher.PageSize = PageSize
    searcher.ServerTimeLimit = New TimeSpan(0, 10, 0)
    searcher.Filter = "(objectCategory=computer)"

    Dim queryResults As SearchResultCollection
    queryResults = searcher.FindAll()

    Dim result As SearchResult
    For Each result In queryResults
        pcResultCount += 1

        Dim dNSHostName As String
        If result.Properties.Contains("dNSHostName") Then
            dNSHostName = result.Properties("dNSHostName")(0)
        Else
            dNSHostName = result.Properties("name")(0) 'If the computer object has a value in dNSHostName (FQDN) store it else store the basic name
        End If

        RaiseEvent ComputerFound(result.Properties("name")(0), dNSHostName, result.Path)
        RaiseEvent ResultFound(ouResultCount, pcResultCount)
    Next

    Return 1

#If Not Debug Then
    Catch Ex as Exception
        MsgBox(ex.Message, MsgBoxStyle.Critical)
    End Try
#End If

End Function

End Class

这是当前的BROKEN代码:

Public Class ADSearcher

'Removed properties and events etc

<MTAThread()>
Public Sub StartSearch()

#If Not Debug Then
    Try
#End If

    Dim rootEntry As New DirectoryEntry(RootPath)
    Dim rootNode As New TreeNode(rootEntry.Name)
    rootNode.Name = rootEntry.Path

    If Not IntegratedAuthentication Then
        rootEntry.Username = UserID
        rootEntry.Password = Password
    End If

    Dim searcher As New DirectorySearcher(rootEntry)
    searcher.PropertiesToLoad.AddRange(PropertiesToLoad)
    searcher.SearchScope = SearchScope
    searcher.PageSize = PageSize
    searcher.ServerTimeLimit = New TimeSpan(0, 10, 0)
    searcher.Filter = FilterString

    Dim queryResults As SearchResultCollection
    queryResults = searcher.FindAll()

    Dim result As SearchResult
    For Each result In queryResults

        Dim freeThread As Integer = WaitHandle.WaitAny(compSearchThreads)

        Dim threadParams As Object
        threadParams = New Object() {result, freeThread} 'Create an object to pass the parameters

        compSearchInstances(freeThread) = New ComputerSearcher(compSearchThreads(freeThread))

        With compSearchInstances(freeThread)
            .FilterString = "(objectCategory=computer)"
            If Not IntegratedAuthentication Then
                .UserID = UserID
                .Password = Password
            End If
            .PageSize = 5
            .PropertiesToLoad = New String() {"cn", "name", "distinguishedName", "dNSHostName", "objectCategory", "objectGUID"}
        End With

        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf compSearchInstances(freeThread).FindComputers), threadParams)
        'FindComputers(result) 'Search the current OU for computer objects

        Dim childNode As New TreeNode(CStr(result.Properties("name")(0)))
        childNode.Name = result.Path
        childNode.Tag = result.Properties("objectGUID")(0)
        rootNode.Nodes.Add(SearchSub(result, childNode))

        ouResultCount += 1
        RaiseEvent OUResultFound(ouResultCount) ', pcResultCount)
    Next

    WaitHandle.WaitAll(compSearchThreads)
    RaiseEvent SearchCompleted(rootNode)
    ouResultCount = 0 'Reset the result count
    'pcResultCount = 0 'Reset the computer result count


#If Not Debug Then
    Catch Ex as Exception
        MsgBox(ex.Message, MsgBoxStyle.Critical)
    End Try
#End If

End Sub

Private Function SearchSub(ByVal parent As SearchResult, ByVal node As TreeNode)
#If Not Debug Then
    Try
#End If
    Dim subEntry As New DirectoryEntry(parent.Path)

    If Not IntegratedAuthentication Then
        subEntry.Username = UserID
        subEntry.Password = Password
    End If

    Dim searcher As New DirectorySearcher(subEntry)
    searcher.PropertiesToLoad.AddRange(PropertiesToLoad)
    searcher.SearchScope = SearchScope
    searcher.PageSize = PageSize
    searcher.ServerTimeLimit = New TimeSpan(0, 10, 0)
    searcher.Filter = FilterString

    Dim queryResults As SearchResultCollection
    queryResults = searcher.FindAll()

    Dim result As SearchResult
    For Each result In queryResults

        Dim freeThread As Integer = WaitHandle.WaitAny(compSearchThreads)

        Dim threadParams As Object
        threadParams = New Object() {result, freeThread} 'Create an object to pass the parameters

        compSearchInstances(freeThread) = New ComputerSearcher(compSearchThreads(freeThread))

        With compSearchInstances(freeThread)
            .FilterString = "(objectCategory=computer)"
            If Not IntegratedAuthentication Then
                .UserID = UserID
                .Password = Password
            End If
            .PageSize = 5
            .PropertiesToLoad = New String() {"cn", "name", "distinguishedName", "dNSHostName", "objectCategory", "objectGUID"}
        End With

        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf compSearchInstances(freeThread).FindComputers), threadParams)

        'FindComputers(result) 'Search for computer objects in the current OU

        Dim childNode As New TreeNode(CStr(result.Properties("name")(0)))
        childNode.Name = result.Path
        childNode.Tag = result.Properties("objectGUID")(0) 'New Object() {}
        SearchSub(result, childNode)
        node.Nodes.Add(childNode)
        ouResultCount += 1
        RaiseEvent OUResultFound(ouResultCount) ', pcResultCount)
    Next

    Return node

#If Not Debug Then
    Catch Ex as Exception
        MsgBox(ex.Message, MsgBoxStyle.Critical)
    End Try
#End If

End Function

End Class

Public Class ComputerSearcher

'Removed properties and events etc

Public Sub FindComputers(ByVal threadParams As Object)
#If Not Debug Then
    Try
#End If

    _doneEvent.Reset() 'Signal that the thread is working

    System.Diagnostics.Debug.Print("Computer search thread " + threadParams(1).ToString + " is starting")

    Dim parent As SearchResult = threadParams(0)

    Dim subEntry As New DirectoryEntry(parent.Path)

    If Not IntegratedAuthentication Then
        subEntry.Username = UserID
        subEntry.Password = Password
    End If

    Dim searcher As New DirectorySearcher(subEntry)
    searcher.PropertiesToLoad.AddRange(PropertiesToLoad)
    searcher.SearchScope = SearchScope
    searcher.PageSize = PageSize
    searcher.ServerTimeLimit = New TimeSpan(0, 10, 0)
    searcher.Filter = FilterString

    Dim queryResults As SearchResultCollection
    queryResults = searcher.FindAll()

    Dim result As SearchResult
    For Each result In queryResults
        pcResultCount += 1

        Dim dNSHostName As String
        If result.Properties.Contains("dNSHostName") Then 'If the computer object has a value in dNSHostName (FQDN) store it else store the basic name
            dNSHostName = result.Properties("dNSHostName")(0)
        Else
            dNSHostName = result.Properties("name")(0)
        End If

        RaiseEvent ComputerFound(result.Properties("name")(0), dNSHostName, result.Path, result.Properties("objectGUID")(0).ToString)
        RaiseEvent CompResultFound(pcResultCount) '### TO DO: Rename event to CompIncrementResult

    Next

    System.Diagnostics.Debug.Print("Computer search thread " + threadParams(1).ToString + " is ending")
    _doneEvent.Set() 'Signal that the thread is finished

#If Not Debug Then
    Catch Ex as Exception
        MsgBox(ex.Message, MsgBoxStyle.Critical)
    End Try
#End If

End Sub
End Class

1 个答案:

答案 0 :(得分:0)

我终于发现了自己的错误,正如我以为这是傻傻的直视着我的脸。在StartSearch()和SubSearch()的以下代码部分中,我忘了设置SearchScope。

With compSearchInstances(freeThread)
    .FilterString = "(objectCategory=computer)"
    If Not IntegratedAuthentication Then
        .UserID = UserID
        .Password = Password
    End If
    .PageSize = 5
    .PropertiesToLoad = New String() {"cn", "name", "distinguishedName", "dNSHostName", "objectCategory", "objectGUID"}
End With

我应该在那里有以下一行:

.SearchScope = SearchScope