问题
Go easy on me, this is my first question ;)
I've spent a lot of time looking, but I haven't found what I'm looking for. I've got an intranet based reporting tool (VB.Net + ASP.Net Integrated Windows Authentication) that looks up users and managers from a SQL Server 2005 table to roll up the reporting to manager level.
This table is currently manually maintained and I've been asked to make it more dynamic as it is going to be up-scaled for far more users. Therefore I'm looking to link in with the Active Directory to create an Org table in the back end which will replace the current manually entered one.
I'm comfortable getting user data from the AD, but not so sure as to the best approach to set this up, I was thinking of the following table:
CREATE TABLE dbo.Employees
(
EmpID nvarchar(8) PRIMARY KEY,
EmpName nvarchar(30),
EmpNo nvarchar(15),
EmpEmail nvarChar(255),
EmpTitle nvarchar(255),
MgrID nvarchar(8) FOREIGN KEY REFERENCES Employees(EmpID)
)
GO
EmpID
will be the NetworkID
(sAMAccountName).
Then this will need populating from the AD, I'm guessing through recursive calls to fill in the fields.
I'm then not sure how to structure the code so that it will capture every employee under every manager starting at a given level.
I'm currently using the below to capture the direct reports for a given manager:
Public Function GetDirectReports(ByVal ADFullName As String) As ArrayList
Dim adItems As ArrayList = New ArrayList
Dim rootEntry As New DirectoryEntry("LDAP://" & ADFullName)
Dim searcher As New DirectorySearcher(rootEntry)
searcher.PropertiesToLoad.Add("directReports")
searcher.PropertiesToLoad.Add("sAMAccountName")
searcher.PropertiesToLoad.Add("cn")
searcher.PageSize = 5
searcher.ServerTimeLimit = New TimeSpan(0, 0, 30)
searcher.ClientTimeout = New TimeSpan(0, 10, 0)
Dim queryResults As SearchResultCollection
queryResults = searcher.FindAll()
Dim x As Integer
For Each result As SearchResult In queryResults
For x = 0 To result.Properties("directReports").Count - 1
adItems.Add(New ADReports(result.Properties("directReports")(x), _
ExtractUser(result.Properties("directReports")(x))))
Next
Next
Return adItems
End Function
Private Function ExtractUser(ByVal username) As String
Return Split(Split(username, "CN=")(1), ",")(0)
End Function
Any comments suggestions and help would be very much appreciated :)
回答1:
Basically what I would do is simply recurse through the entire AD and grab out all the users, with the relevant info needed, and store them in SQL Server. While enumerating, don't worry and care about the hierarchies - you'll handle those later.
Once the data is inside SQL Server, you could then create e.g. a recursive CTE (Common Table Expression) to get the hierarchy of the employees - who reports to whom etc.
As a side-note: the sAMAccountName
is not guaranteed to stay stable - it could change (rare, but possible) - so maybe you need another item as the unique identifier for each user? Does your company use the userID
attribute, or something else? Or could you use the AD user GUID (which will stay the same forever) instead of the samAccountName
?
Also: if you choose to stick with the sAMAccountName
: be aware it could be up to 20 characters long - NVARCHAR(8)
won't be enough. Also: do you really need the Unicode strings? Those are just always twice as long as the non-Unicode VARCHAR(20)
strings - just asking, you might need it, then that's fine.
I would probably add an artificial EmployeeID
(INT IDENTITY
) column to the table to handle all the requirements for a good clustering key on that table: unique, stable, narrow. A nvarchar(20)
is first of all variable length which isn't terribly good, and it could be up to 40 bytes long - which again is not optimal.
回答2:
You can use this code snippet to get manager name for certain employee. If you want to know subordinates of manager, then please replace directreports with manager.
lblUser.Text = My.User.Name
Dim _UserName As String = GetDomainUserName(My.User.Name)
Dim context As PrincipalContext = New PrincipalContext(ContextType.Domain)
' find a user
Dim user As UserPrincipal = UserPrincipal.FindByIdentity(context, lblUser.Text)
Dim allUsers As New ArrayList()
Dim searchRoot As New DirectoryEntry("LDAP://DOMAIN")
Dim search As New DirectorySearcher(searchRoot)
'search.Filter = "(&(objectClass=user)(manager=" + user.DistinguishedName + "))"
search.Filter = "(&(objectClass=user)(directReports=" + user.DistinguishedName + "))"
search.PropertiesToLoad.Add("samaccountname")
Dim result As SearchResult
Dim resultCol As SearchResultCollection = search.FindAll()
If resultCol IsNot Nothing Then
For counter As Integer = 0 To resultCol.Count - 1
result = resultCol(counter)
If result.Properties.Contains("samaccountname") Then
allUsers.Add(DirectCast(result.Properties("samaccountname")(0), [String]))
End If
Next
End If
来源:https://stackoverflow.com/questions/9498908/looping-through-active-directory-to-get-managers-and-direct-reports