Thursday, March 3, 2011

Quick Organizational Chart from Active Directory

Building on my blog post, Export Manager's Nested Direct Reports, I quickly threw together a revision of the code that will create visual (ASCII at least) organizational chart based on the directReports attribute of an employee in Active Directory. The nesting method I am using could easy be converted to simulate the "tree" DOS command using Get-ChildObject on file systems or about any programming challenge that deals with nested objects. The one main fault of the code, is that it is not pretty when it gets to the last nested object of a parent. It leaves the "|" in front of the last nested subordinate object. A little more work and I could clean this presentation issue, but not today.
Function Get-DirectReports($distinguishedName,$level) {
 $managerObject = Get-ActiveDirectoryObject $distinguishedName
 if($managerObject.directReports.count -gt 0) {
  foreach($directReport in $managerObject.directReports) {
   $directReportObject = Get-ActiveDirectoryObject $directReport
   Write-Output (("|  " * $level) + "|")
   Write-Output (("|  " * $level) + "+-" + ($directReportObject.givenName).ToString() + " " + ($directReportObject.sn).ToString())
   Get-DirectReports $directReport ($level + 1)
  }
 }
}

Function Get-LocalDomainController($objectDomain) {
 return ([System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite()).Servers | Where-Object { $_.Domain.Name -eq $objectDomain } | ForEach-Object { $_.Name } | Select-Object -first 1
}
   
Function Get-ObjectADDomain($distinguishedName) {
 return ((($distinguishedName -replace "(.*?)DC=(.*)",'$2') -replace "DC=","") -replace ",",".")
}
   
Function Get-ActiveDirectoryObject($distinguishedName) {
 return [ADSI]("LDAP://" + (Get-LocalDomainController (Get-ObjectADDomain $distinguishedName)) + "/" + ($distinguishedName -replace "/","\/"))
}
#--------------------------------------------------------------------------------------------------#
Set-Variable -name forestRootDn -option Constant -value ([ADSI]("LDAP://" + (([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()).name) + "/rootDSE")).defaultNamingContext
#--------------------------------------------------------------------------------------------------#
$objectConnection = New-Object -comObject "ADODB.Connection"
$objectCommand = New-Object -comObject "ADODB.Command"
$objectConnection.Open("Provider=ADsDSOObject;")
$objectCommand.ActiveConnection = $objectConnection

$manager = "the.ceo@mycompany.local"
 
$ldapBase = "GC://$forestRootDn"
$ldapAttr = "distinguishedName"
$ldapScope = "subtree"
$ldapFilter = "(&(objectClass=user)(proxyAddresses=smtp:$manager))"
$ldapQuery = "<$ldapBase>;$ldapFilter;$ldapAttr;$ldapScope"
$objectCommand.CommandText = $ldapQuery
$objectRecordSet = $objectCommand.Execute()
 
while(!$objectRecordSet.EOF) {
 $firstLevelObject = Get-ActiveDirectoryObject $objectRecordSet.Fields.Item('distinguishedName').Value
 $topLevelManager = (($firstLevelObject.givenName).ToString() + " " + ($firstLevelObject.sn).ToString())
 Write-Output $topLevelManager
 Get-DirectReports $firstLevelObject.distinguishedName 0
 $objectRecordSet.MoveNext()
}

No comments:

Post a Comment