Searching AD using .net and a Global Catalog (GC) Server
Although I have been recently been exploring the world of R2 and AD-cmdlts, I have re-visited .net to search a the whole forest in one quick step. As A GC holds a subset of information on all objects in the forest, we can query any GC in the forest to return these values. Here, I am doing a search for a specific UPN, but the filter can inculde any attribute stored on the GC.
The rest of the script is the same as how we ended up in my AD Searcher
You might not want to find any GC in the forest, you might want to only choose one from a particular site. As $forest.FindGlobalCatalog() has an option for this, the command simply becomes
NOTE : I have found that PropertiesToLoad is a read only value. The searcher returns all GC attributes. Also SearchRoot is set to the GC server selected.
So, to query the whole forest in one go : (with the rest of the AD searcher script)
Although I have been recently been exploring the world of R2 and AD-cmdlts, I have re-visited .net to search a the whole forest in one quick step. As A GC holds a subset of information on all objects in the forest, we can query any GC in the forest to return these values. Here, I am doing a search for a specific UPN, but the filter can inculde any attribute stored on the GC.
$upn= "first.last@domain.name"
$Forest = [System.DirectoryServices.ActiveDirectory.forest]::getcurrentforest()
$GC = $forest.FindGlobalCatalog()
$searcher = $gc.GetDirectorySearcher()
$searcher.filter = "(userprincipalname=$upn)"
$Results = $Searcher.FindAll()
The rest of the script is the same as how we ended up in my AD Searcher
You might not want to find any GC in the forest, you might want to only choose one from a particular site. As $forest.FindGlobalCatalog() has an option for this, the command simply becomes
$GC = $forest.FindGlobalCatalog("Sitename")I'm a big fan of keeping things concise, and powershell allows you to do this quite easily. We can take lines 2, 3 and 4 from the above script and do it all in one go ...
$searcher = [System.DirectoryServices.ActiveDirectory.forest]::getcurrentforest().FindGlobalCatalog().GetDirectorySearcher()As before, you have the other search options you can configure, below is an output of the $searcher object ...
PS U:\> $searcherYou can set these the same way we set the filter.
CacheResults : True
ClientTimeout : -00:00:01
PropertyNamesOnly : False
Filter : (objectClass=*)
PageSize : 0
PropertiesToLoad : {}
ReferralChasing : External
SearchScope : Subtree
ServerPageTimeLimit : -00:00:01
ServerTimeLimit : -00:00:01
SizeLimit : 0
SearchRoot : System.DirectoryServices.DirectoryEntry
Sort : System.DirectoryServices.SortOption
Asynchronous : False
Tombstone : False
AttributeScopeQuery :
DerefAlias : Never
SecurityMasks : None
ExtendedDN : None
DirectorySynchronization :
VirtualListView :
Site :
Container :
NOTE : I have found that PropertiesToLoad is a read only value. The searcher returns all GC attributes. Also SearchRoot is set to the GC server selected.
So, to query the whole forest in one go : (with the rest of the AD searcher script)
$Collection = @()
$upn = "first.last@domain.name"
$ObjectCategory = "user"
$ObjectProplist = "samaccountname","userprincipalname","mail","whencreated","whenchanged","memberof"
$searcher = [System.DirectoryServices.ActiveDirectory.forest]::getcurrentforest().FindGlobalCatalog().GetDirectorySearcher()
$searcher.filter = "(&(objectCategory=user)(userprincipalname=$upn))"
$Searcher.pagesize = 1000
$Results = $Searcher.FindAll()
foreach ($Object in $Results){
$Store = "" | select $ObjectProplist
foreach ($prop in $ObjectProplist){
switch ($prop){
lastlogon {trap { $Store.lastlogon = "Last Logon value not valid";continue}&{$lastlogon =[DateTime]::FromFileTime($Object.Properties.lastlogon[0]);$Store.lastlogon = $lastlogon}}
lastlogontimestamp {trap { $Store.lastlogontimestamp = "Last Logon value not valid";continue}&{$Store.lastlogontimestamp = [DateTime]::FromFileTimeUTC($Object.Properties.lastlogontimestamp[0])}}
useraccountcontrol {$Store.$prop = $Object.Properties.$prop[0]}
memberof {trap { $Store.$prop = "null";continue}&{$Store.$prop = [string]::join(",",$($Object.Properties.$prop))}}
proxyaddresses {trap { $Store.$prop = "null";continue}&{$Store.$prop = [string]::join(",",$($Object.Properties.$prop))}}
Default {trap { $Store.$prop = $Object.Properties.$prop;continue}&$Store.$prop = $($Object.Properties.$prop).tostring()}}
}
}
$Collection += $Store
}
$Collection | export-csv "upn.csv" -NoTypeInformation
Comments
Post a Comment