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.
I really like the powershell code and sample. There isn’t a lot of powershell code out there yet for us new-to-powershell users to go off of. However I am having a problem after slightly modifying this code example. I want to read in a list of samaccounts and output the results to a file. Outputing to any file is working ok, I want to be able to output in csv format. When export-csv is done, the data isn’t right. Here is the code:
foreach($sam in get-content "users.txt")
{
$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()
$objUser |select displayname, samaccountname, employeeid, employeetype, mail, department, departmentnumber, homedrive, homedirectory |export-csv users_info.csv
}
}
If you could, please post this in the PowerShell discussion forum at ScriptingAnswers.com. One of the first questions I would ask is, what is not right about the output? I don’t see anything glaringly wrong with your code. When you post in the forum, it would also be helpful if you could attach your script.
Jeff