Wednesday, March 20, 2013

Global Catalog query with Powershell and missing attributes

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:
  1. (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:
  1. $dom = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()  
  2. $root = [ADSI]"LDAP://$($dom.Name)"  
  3. $search = new-Object System.DirectoryServices.DirectorySearcher($root,"(objectcategory=computer)")  
  4. $resultLDAP = $search.FindOne()  
Then I run:
  1. $resultLDAP | % {($_.properties).count}  
and the resulting number of properties was 34.

Then I made the same query using the GC: moniker:
  1. $root = [ADSI]"GC://$($dom.Name)"  
  2. $search = new-Object System.DirectoryServices.DirectorySearcher($root,"(objectcategory=computer)")  
  3. $resultGC = $search.FindOne()  
  4. $resultGC | % {($_.properties).count}  
And I got 24 attributes back. Ten atrributes where missing...

At this point the best option was to use Compare-Object and see which attributes where missing from the GC: query:
  1. Compare-Object -ReferenceObject ($resultLDAP | % {$_.properties.propertynames}) -DifferenceObject ($resultGC | % {$_.properties.propertynames})  
  2.   
  3. InputObject                      SideIndicator  
  4. -----------                        -------------  
  5. iscriticalsystemobject        <=  
  6. ridsetreferences                <=  
  7. codepage                         <=  
  8. countrycode                     <=  
  9. accountexpires                 <=  
  10. operatingsystem               <=  
  11. lastlogontimestamp           <=  
  12. operatingsystemservicepack           <=  
  13. operatingsystemversion                   <=  
  14. 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:
  1. (New-Object -typename ADSISearcher -ArgumentList @([ADSI]'LDAP://DC=domain,DC=com',"(&(objectcategory=computer)(OperatingSystem=*server*))")).FindAll() | %{$_.properties}  
I hope this post will help you. Be kind, share if you find some useful information here!

1 comment:

  1. One more item that was preventing me from grabbing the values was not running the PS console as administrator... right click, run as. Thanks for the write up. Found it very useful.

    ReplyDelete

Related Posts Plugin for WordPress, Blogger...