Searching the Active Directory with PowerShell

Hello world

It’s time for my second post and I thought I would talk about searching the active directory. I ran a PowerShell course yesterday and the delegates were itching to find out a bit more about searching an AD. So I said I would make sure I posted something on the blog.

 

So let’s get going! To start with I`m going to introduce a script that I would be lost without: “get-dn.ps1”. This script takes a SAM account name as input and returns the objects full CN as output. We can then use this output to then connect directly to the object. Here’s the code:

 

function get-dn ($SAMName)

{

      $root = [ADSI]''

      $searcher = new-object System.DirectoryServices.DirectorySearcher($root)

$searcher.filter = "(&(objectClass=user)(sAMAccountName= $SAMName))"

$user = $searcher.findall()

     

if ($user.count -gt 1)

      {

            $count = 0

            foreach($i in $user)

            {

                  write-host $count ": " $i.path

                  $count = $count + 1

            }

            $selection = Read-Host "Please select item: "

return $user[$selection].path

      }

      else

      {

            return $user[0].path

      }

}

$Name = $args[0]

$path = get-dn $Name

"'" + $path + "'" 

 

 

So now let’s look at this code in a bit more detail.

 

The first bit of the code simply creates a function to do most of the work. We take an argument in $SAMName that will hold the name of the account we wish to search for

 

function get-dn ($SAMName)

{

 

The next bit of code creates 2 objects. $root is a standard ADSI object that connects to the domain we are in. $searcher is a DirectorySearcher object, and we pass the ADSI object $root in as a constructor. Effectively we’re saying search the domain we’re in.

 

$root = [ADSI]''

$searcher = new-object System.DirectoryServices.DirectorySearcher($root)

 

 

Now we have created a DirectorySearcher object we need to set the search criteria. To do his we use the filter property of $searcher. See the LDAP Search Strings section below for more information. Once we have the criteria, we simply use the findall() method to find all instances that match the filter in the domain and return the results to $user

 

$searcher.filter = "(&(objectClass=user)(sAMAccountName= $SAMName))"

$user = $searcher.findall()

 

$user actually contains a collection of objects that match the search criteria. If we have more than one match, the collection has more than one element. This bit of code says “If we have more than 1 result, write all the results to screen and allow the user to select which object they mean”. The shrewd among you may think, “SAMAccountName is unique, we can’t have 2 of them”. You’re right however, we could implement wildcard searching, or searching by surname which might result in multiple matches making this really useful. Finally we return the path to the object. We return the object path because it includes the “LDAP://” which we would need to connect to the object directly.

 

 

if ($user.count -gt 1)

{

      $count = 0

      foreach($i in $user)

      {

            write-host $count ": " $i.path

            $count = $count + 1

      }

      $selection = Read-Host "Please select item: "

      return $user[$selection].path

}

 

 

The last bit of the if statement simply returns the path of the 1st element, if there is only 1 element in the collection. Then we finish of the function with a }.

 

else

      {

            return $user[0].path

      }

}

 

 

 

The final section simply assigns the passed in argument to the variable $Name. We then call the get-dn function passing in $Name, and put the result in $path. At the very end we wrap the path in a ‘ and ‘ so that you can then copy and paste the returned line straight into an [ADSI] constructor. (see the previous post)

 

$Name = $args[0]

$path = get-dn $Name

"'" + $path + "'" 

 

 

This function is really useful. Once I have got a hit I can use the output to quickly connect to an object in the Active Directory. I could for example type the following in PowerShell:

 

 

PS C:\store\ps scripts> .\get-dn.ps1 administrator

'LDAP://CN=Administrator,CN=Users,DC=umpadom,DC=com'

PS C:\store\ps scripts> $user = [ADSI] 'LDAP://CN=Administrator,CN=Users,DC=umpadom,DC=com'

PS C:\store\ps scripts> $user

distinguishedName

-----------------

{CN=Administrator,CN=Users,DC=umpadom,DC=com}

 

 

 

DirectorySearcher Object

 

For more information on the DirectorySearcher object check out MSDN here:

 

https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemDirectoryServicesDirectorySearcherMembersTopic.asp

 

Some members of DirectorySearcher that you might want to look at in more detail are:

 

PageSize – this limits the amount of results that get returned, and can be really handy when you are searching big domains.

Filter – This is the search criteria that is used to search the Active Directory. It uses LDAP search strings. See the below section for more information

 

LDAP Search String’s

 

The DirectorySearcher filter property takes LDAP search strings. These strings use their own language. More information can be found here.

 

https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemdirectoryservicesdirectorysearcherclassfiltertopic.asp

 

Basically, these are the four things to bear in mind when creating LDAP search strings.

1. The string must be enclosed in parentheses.

2. Expressions can use the relational operators: <, <=, =, >=, and >. An example is "(objectClass=user)". Another example is "(lastName>=Davis)".

3. Compound expressions are formed with the prefix operators & (and) and | (or). An example is"(&(objectClass=user)(lastName= Davis))". Another example is "(&(objectClass=printer)(|(building=42)(building=43)))".

4. Wildcards can be used. Use * operator

 

 

As ever, here are some examples. Below are some LDAP search strings that could be assigned to the DirectorySearcher.Filter property.

 

Find all users by explicit SAMName

 

"(&(objectClass=user)(sAMAccountName= $SAMName))"

 

 

 

Find all users where SAMName begins with xyz

 

"(&(objectClass=user)(sAMAccountName= $SAMName*))"

 

 

 

Find all users where Surname begins with xyz

 

 

"(&(objectClass=user)(sn= $Name*))"

 

 

Find all computers where computer name starts with xyz

 

 

"(&(objectClass=computer)(sAMAccountName= $ComputerName*))"

 

 

 

Well ladies and gentleman, here endeth the lesson.

 

That is all

 

BenP