Being quite the lazy admin that I am, whenever I’m scripting for AD I like to use short names when referring to objects. As an example, if I want to add the user BellA into the Domain Admins group I don’t want to provide the distinguishedName for both objects .
The easy solution to this is to have enough information to hand, to allow a quick rummage through the Directory, and let the script
retrieve the details it needs. In fact being able to extract information from an AD search is pretty much the corner stone of any AD scripting tool box, as you’ll see over the next couple of posts.
I’ll show you a couple of ways of searching and then mention a few points to be aware of regarding performance, and your impact on the servers whose workload you’re adding to.
# —————————————————————————————————
function Find-DN
# —————————————————————————————————
{
Param (
$sADobjectName,
$sADobjectType
)
$query = new-object system.directoryservices.directorysearcher
$root = [adsi]“”
$query.SearchRoot = $root
$query.filter = “(&(ObjectClass=$sADobjectType)(cn=$sADobjectName))”
$query.SearchScope = “subtree”
$result = $query.findOne()
if ($result -eq $null)
{
return $null
}
else
{
$ADobject = $result.GetDirectoryEntry()
return $ADobject.distinguishedName
}
}
There isn’t a lot of specific PowerShell code in the function above. Its pretty LDAP orientated. We have a simple function that returns you the distinguishedName of an object when you provide the objectClass and cn.
So to find the DN of my test user account:
Find-DN “BellA” “user”
The $result variable is a System.DirectoryServices.SearchResult which we cast into System.DirectoryServices.DirectoryEntry with the GetDirectoryEntry() method. I like this as it gives us a much nicer way of retrieving the objects properties.
The other method of searching AD I have seen, is similar, but with a PS slant to it:
# —————————————————————————————————
function Find-DN2
# —————————————————————————————————
{
Param (
$sADobjectName,
$sADobjectType
)
$query = new-object system.directoryservices.directorysearcher
$root = [adsi]“”
$query.SearchRoot = $root
$query.SearchScope = “subtree”
$ADobject = $query.findAll() | where-object {$_.properties.objectclass -eq $sADobjectType `
-and $_.properties.cn -eq $sADobjectName}
$props = $ADobject.Properties
if ($ADobject -eq $null)
{
return $null
}
else
{
foreach ($prop in $props)
{
return $prop.distinguishedname
}
}
}
Straight away you can see some PowerShell in the function above. Rather then use the $query.filter, we pipe the results into a where-object and then filter for our search criteria. We also handle the properties returned differently.
This function would be called exactly the same as our previous example:
Find-DN2 “BellA” “user”
Now I’ve had problems with this function. I’ve found it worked fine for “some” objects, but I have had trouble retrieving others. Despite the SearchScope being set to “SubTree” I’ve had it fail to retrieve objects that are a few OU’s deep. I suspect this is a flaw with my function as apposed to anything flawed in PS ;)
Search Tips
So now we’ve seen the basics, I thought it worth mentioning a couple of ways to improve on performance, and speed:
[1] Scope: If you can, narrow your SearchScope. There’s three options: “Base”, “OneLevel”, and “SubTree”. If you’re not sure, there’s a good explanation on MSDN here.
[2] Filter: Always try and provide a filter to reduce how much data you’re trying to retrieve. There’s obviously not much point retrieving every user account in your domain and enumerating through them all just for the one you want. Think about the Filter() method, and use the relevant FindOne() FindAll() methods.
I’m not sure how our second examples works with this. My hunch is that it retrieves ALL the objects and trawls through each with the where-object. I could be wrong here of course ;)
[3] Properties: If you’re only after say, the distinguishedName it would be a good idea to reduce the properties returned by using the PropertiesToLoad method.
The Microsoft Scripting Guy’s, have an example here