Now where did I put that user?

Working with Active Directory in PowerShell will require a bit of a paradigm shift for scripters used to working with ADSI in VBScript. But it’s not necessarily a bad thing.  For example, in PowerShell it is very easy to find objects in Active Directory with a searcher object. Once you have the object reference, you can connect to it and work with its properties pretty much as you did in VBScript. Let me show you a PowerShell script that finds a user in Active Directory given its sAMAccountname and then lists the available properties.

Let’s look at the script in its entirety first.

#GetUserInfo.ps1
#http://www.scriptinganswers.com

function Find-User
{
Param ($sam=$(throw “you must enter a sAMAccountname”))
$searcher=New-Object DirectoryServices.DirectorySearcher
$searcher.Filter=”(&(objectcategory=person)(objectclass=user)(sAMAccountname=”+$sam+”))”
$results=$searcher.FindOne()
if ($results.path.length -gt 1)
     {
     return $results
     }
    else
     {
     return “Not Found”
     }
 }
 #main body of the script
 $sam=Read-Host “Enter a sAMAccountname”
 $User=Find-User $sam
 if ($User -eq “Not Found”)
    {
     Write-Host -foregroundcolor RED $sam.ToUpper() “was not found in the directory.”
    }
    else
    {
     $objUser=$User.GetDirectoryEntry()
#    Show all available user properties
     Write-Host `n
     Write-host “DN is”$objUser.DistinguishedName
     write-host “UPN is”$objUser.UserPrincipalName
     write-host `n
     write-host “Other available properties:”
     $objUser|Get-Member
#    Use code like this if you wanted to update a property
#    $objUser.Description=”Updated by PowerShell”
#    $objUser.SetInfo()
    }

Jump down to the main body of the script. It begins by prompting the administrator for a sAMAccountname. Then it takes that name and passes it as a parameter to the Find-User function defined at the beginning of the script. The function defines a DirectorySearcher object including a filter that basically says, find me a user object where the sAMAccountname equals the value of $sam.  I then create an object, $results, to hold the results of the search. The actual search is invoked with the FindOne method. There is also a FindAll method, but since I’m assuming the sAMAccountname will be unique I can stop searching at the first match.

The search returns an directory searcher result object. I’ve put in some logic to handle situations where the account is not found by checking for the length of the returned object’s path.

if ($results.path.length -gt 1)
     {
     return $results
     }
    else
     {
     return “Not Found”
     }

If the search was successful, $results.path will have some value and length, at which point I can use the object as the return value of the function. If there is no path, then I want to return some sort of error message.

Assuming my search was successful, I now have a search result object. But this isn’t the actual Active Directory object . To work with all the object’s properties, I need the object. Fortunately, the search result object has a method called GetDirectoryEntry() which will return the Active Directory object.

 if ($User -eq “Not Found”)
    {
     Write-Host -foregroundcolor RED $sam.ToUpper() “was not found in the directory.”
    }
    else
    {
     $objUser=$User.GetDirectoryEntry()

(You can also see that I have some code to gracefully handle the situation if the user is not found.) Now I can access properties directly like this:

Write-Host “DN is”$objUser.DistinguishedName
Write-host “UPN is”$objUser.UserPrincipalName

I can pipe the object to Get-Member which will show me all the properties that are defined.

$objUser|Get-Member

You have to remember that this list is not all the properties, only the ones with values. You can still set a property if you know the name like this:

$objUser.Description=”Updated by PowerShell”
$objUser.SetInfo()

Adapting your ADSI VBScripts to PowerShell will take some work, and in some cases it may  be better off to start from scratch. But once you get the hang of working with the .NET directory service classes, you’ll be pretty amazed at the results.