Wrappers

I’ve been using PowerShell to explore Active Directory. Since I do most of my exploring from the command line and I’m inherently lazy, I’ve been creating “wrappers” for some .Net 2.0 AD stuff to add to my profile.ps1 file. (“The fewer keystrokes, the better” is my motto.) I started with the DirectorySearcher by creating a function “new-ADSearcher”.

I was always using the same “preamble” of setting the CacheResults, SearchScope and PageSize so at least I could get rid of typing those all the time. (Yeah, I know that those values for CacheResults and SearchScope are the PS defaults, but I don’t like to have to depend on defaults. So call me OCD.)

The Filter and SearchRoot attributes of the DirectorySearcher were the main things I seemed to be using so they became the parameters for the function. But since the SearchRoot attribute actually required a DirectoryEntry object, that lead to a separate function named (predictably enough) “get-ADEntry”.

get-ADEntry originally only had a single optional parameter of LdapPath, which met the need for the new-ADSearcher function. But I was also frequently needing to access user objects based on their sAMAccountName attribute, as well as other AD objects based on their objectGuid attribute. So get-ADEntry grew a little with the addition of the samAccount and Guid parameters. And now I needed two additional functions, get-UserDN and get-NativeGuid.

get-UserDN was pretty straightforward. All I needed to do was use new-ADSearcher with the appropriate filter. (Did I mention that I was lazy?) Of course, after I wrote get-UserDN, I found myself searching for users by their SMTP address so I just added this to get-USerDN also. (And now I can go back and add that as an option to get-ADEntry also since it’ll just need to call get-UserDN.)

get-NativeGuid was needed because GUIDs are IMHO weird things. By definition a GUID is a 128-bit integer (16 bytes). The most common representation that you seem to see is in the form “e1c9f329-a5c2-46c0-b900-ee8e4e3ebbf6”. But to search for a GUID in an LDAP filter in PowerShell with DirectorySearcher object, you seem to need to use the form “29f3c9e1c2a5c046b900ee8e4e3ebbf6” which is the form that you’ll get from the get_NativeGuid() method of a DirectoryEntry object in PowerShell. (I say “seem to need” because I can’t find this documented anywhere.) Unfortunately, the system.guid class.tostring formatting options don’t seem to provide this conversion so this function was needed.

Disclaimer: Since I primarily work in a single domain, single forest environment, these functions might have issues in a multi-domain forest. And I haven’t spent any time adding error-checking or usability features. (Did I mention that I was lazy?)

function new-ADSearcher {
  param ($Filter=””,$Root=””)
  $local:Searcher = New-Object DirectoryServices.DirectorySearcher
  $Searcher.CacheResults = $true
  $Searcher.SearchScope = “Subtree”
  $Searcher.PageSize = 1000
  if ($Filter -ne “”) { $Searcher.Filter = $Filter }
  if ($Root -ne “”) { $Searcher.SearchRoot = get-ADEntry -ldappath $Root }
  $Searcher
}

function get-ADEntry {
  param ($LdapPath=””, $samAccount=””, $Guid=””, $SmtpAddress=””)
  if ($LdapPath -ne “”) {
    New-Object DirectoryServices.DirectoryEntry (“LDAP://” + $LdapPath)
  }
  elseif ($samAccount -ne “”) {
    New-Object DirectoryServices.DirectoryEntry (“LDAP://” + (get-userDN -samAccount $samAccount))
  }
  elseif ($SmtpAddress -ne “”) {
    New-Object DirectoryServices.DirectoryEntry (“LDAP://” + (get-userDN -SmtpAddress $SmtpAddress))
  }
  elseif ($Guid -ne “”) {
    New-Object DirectoryServices.DirectoryEntry (“LDAP://<GUID=” + (get-NativeGuid $Guid) + “>”)
  }
  else {
    New-Object DirectoryServices.DirectoryEntry
  }
}

function get-UserDN {
  param ($samAccount = “”, $SmtpAddress = “”)
  $local:Filter = “”
  if ($samAccount -ne “”) {
    $Filter = “(&(objectCategory=person)(objectClass=user)(samAccountName=” + $samAccount + “))”
  }
  elseif ($SmtpAddress -ne “”) {
    $Filter = “(&(objectCategory=person)(objectClass=user)(mailnickname=*)(proxyaddresses=smtp:” + $SmtpAddress + “))”
  }
  $local:Searcher = new-ADSearcher -filter $Filter
  $local:SearchResults = $Searcher.FindOne()
  $SearchResults.properties.distinguishedname
}

function get-NativeGuid {
  param ($GuidString)
  $local:Guid = new-object system.guid ($GuidString)
  $local:NativeGuid = “”
  $Guid.ToByteArray() | foreach { $NativeGuid +=  $_.tostring(“x2”) }
  $NativeGuid
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s