Summary: Don’t translate old VBScript scripts that search Active Directory—instead use the Active Directory cmdlets from the RSAT.
Hey, Scripting Guy! I have this script that I use for auditing Active Directory. Basically, it queries to see what new user accounts have been created in the last month. I started translating it to Windows PowerShell (because I know that Windows PowerShell has the ability to create COM objects), but I fail to see the Windows PowerShell advantage. I mean, the script is as long as the original VBScript script. What gives?
—BB
Hello BB,
Microsoft Scripting Guy, Ed Wilson, is here. This morning I had to jump right into work, with little time even for a nice cup of tea. With the Atlanta TechStravaganza and TechEd Europe coming up back-to-back, there have been literally dozens of emails flying across the pond. The Scripting Guys will have a booth at TechEd Europe, and I will be conducting a couple of instructor-led labs about the cool new Windows PowerShell 4.0 Desired State Configuration feature. This lab, which was completely full the last day of TechEd North America, is absolutely awesome. Anyway, with temperatures in the mid-90s (Fahrenheit, 34 degrees Celsius), it is advisable to not get too terribly excited.
Good old COM-based ADO
In the VBScript days, it was not uncommon to use COM-based ADO to query Active Directory to find various pieces of information about users. In fact, this is a technique that I used all the way back in the Windows 2000 days (and the infamous millennium bug). Following is a 4.5 star script from the Script Center Repository: Search for All Users by the Date Their Account was Created.
On Error Resume Next
Const ADS_SCOPE_SUBTREE = 2
dtmCreationDate = "20071001000000.0Z"
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
objCommand.CommandText = _
"SELECT Name FROM 'LDAP://dc=fabrikam,dc=com' WHERE objectClass='user' " & _
"AND whenCreated>='" & dtmCreationDate & "'"
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
Wscript.Echo objRecordSet.Fields("Name").Value
objRecordSet.MoveNext
Loop
Hey, you know what, it is not too bad—only 26 lines long. It especially was not too bad if you had a great VBScript template with which to begin your work (you can find templates at Script Resources for IT Professionals). If one were to translate this script into Windows PowerShell, using the same COM-based ADO, the script would be essentially the same, and it would be just as long. Luckily, we do not have to do that.
The Windows PowerShell way
In Windows PowerShell 1.0, about the best one could do was to use the .NET Framework classes. This translated into using two classes. The resultant code is shown here:
$strFilter = "(&(objectCategory=User)(whenChanged=20071001000000.0Z))"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$colProplist = "name"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{$objItem = $objResult.Properties; $objItem.name}
Groovy. This is only 17 lines of code, and we have the added bonus of avoiding the use of COM-based classes.
In Windows PowerShell 2.0, the [adsisearcher] type accelerator is added, and that shortens the code by a few lines. But the greatest addition comes with the installation of the Remote Server Administration Tools (RSAT) because these introduce the Active Directory module. (For more information, see Hey, Scripting Guy! What's Up with Active Directory Domain Services Cmdlets?)
The Active Directory module and a one-liner
Upon installing the RSAT tools (for your specific version of client and server), you gain access to the Get-ADUser cmdlet. This makes finding information about newly created users the one-liner shown here:
Get-ADUser -Filter * -Properties whencreated | where whencreated -ge ((get-date).adddays(-30))
BB, that is all there is to converting an Active Directory script to Windows PowerShell. Join me tomorrow when we are joined by Honorary Scripting Guy and Windows PowerShell MVP, Sean Kearney, for Part 1 of his series, Create a New Virtual Machine with PowerShell.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy