While investigating an issue querying Active Directory using the [adsisearcher] accelerator, which by the way is my preferred way to query AD DS because nothing has to be added to Powershell, I discovered that there are missing properties when I bind using the GC: moniker instead of LDAP:.
The problematic command that pushed me to dig a bit is the following:
- (New-Object -typename ADSISearcher -ArgumentList @([ADSI]'GC://DC=domain,DC=com',"(&(objectcategory=computer)(OperatingSystem=*server*))")).FindAll() | %{$_.properties}
As you can see this command looks good and I was pretty astonished ot see that the resulting object was empty.
Suddenly many things from the past came back to my mind and one of them is that a Global Catalog stores only a subset of the attributes for each object in the Active Directory forest in order to speed up queries. I started wondering whether the attributes I was filtering on was part of that subset and changed my query to:
- $dom = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
- $root = [ADSI]"LDAP://$($dom.Name)"
- $search = new-Object System.DirectoryServices.DirectorySearcher($root,"(objectcategory=computer)")
- $resultLDAP = $search.FindOne()
- $resultLDAP | % {($_.properties).count}
Then I made the same query using the GC: moniker:
- $root = [ADSI]"GC://$($dom.Name)"
- $search = new-Object System.DirectoryServices.DirectorySearcher($root,"(objectcategory=computer)")
- $resultGC = $search.FindOne()
- $resultGC | % {($_.properties).count}
At this point the best option was to use Compare-Object and see which attributes where missing from the GC: query:
- Compare-Object -ReferenceObject ($resultLDAP | % {$_.properties.propertynames}) -DifferenceObject ($resultGC | % {$_.properties.propertynames})
- InputObject SideIndicator
- ----------- -------------
- iscriticalsystemobject <=
- ridsetreferences <=
- codepage <=
- countrycode <=
- accountexpires <=
- operatingsystem <=
- lastlogontimestamp <=
- operatingsystemservicepack <=
- operatingsystemversion <=
- localpolicyflags <=
Catch! I see 'operatingsystem' in there. That's why my initial query wasn't returning any result.
The solution to this was in the end to replace the GC: moniker with LDAP: as shown in the following one-liner:
- (New-Object -typename ADSISearcher -ArgumentList @([ADSI]'LDAP://DC=domain,DC=com',"(&(objectcategory=computer)(OperatingSystem=*server*))")).FindAll() | %{$_.properties}