Hey, Scripting Guy! I often need to search Active Directory Domain Services (AD DS) to find information about various computers. I may need to identify all of the computers in a particular organizational unit or all the computers who happen to reside in a particular office. Whatever the reason, using Active X Data Objects (ADO) like I did in the old VBScript days is a major pain. When I learned how to use the Directory Searcher Object, it was a little better—in fact quite a bit better, but I am curious if the new Active Directory cmdlets have anything to make it easier to retrieve users?
— NN
Hello NN,
Microsoft Scripting Guy Ed Wilson here. Today is a special day because I finally received my copies of the Windows PowerShell 2.0 Best Practices book that I spent 18 months of my life writing. For me, the big thing about writing books is the enjoyment I receive when people tell me they have read my book and it helped them. On Facebook this morning, I had two notes from people who stated they had enjoyed my books. Speaking of Facebook, send me a friend request. I enjoy the interaction. In addition to the Best Practices book, the morning mail also showed up with a tin of Genmaicha tea. This delicate green tea is best brewed for 3–5 minutes, and tastes great with a cinnamon stick in it. The beautiful blue sky, cool temperature, a special pot of green tea, and an excellent Windows PowerShell book make a wonderful way to spend the day. But I also need to check the e-mail sent to scripter@microsoft.com.
It is a bit damp outside today, but the sky is clear. It reminds me of Lima, Peru, when I was down there teaching a VBScript class a few years ago. My friend Omar took me around, and I was able to take some great pictures such as the following one.
NN, I agree with you completely. Using the Directory Searcher .NET Framework classes is easier to use than the old fashioned ADO or even new fangled ADO.NET scripts. In the end I feel it is a best practice to use what you are comfortable with, and to use what will be easiest for you to modify, to troubleshoot, and to maintain.
An example of using ADO to query AD DS is the QueryAD.Ps1 script I wrote several years ago.
QueryAD.ps1
param(
$ou,
$domain,
$query,
[switch]$help
)
function funHelp()
{
$helpText=@”
DESCRIPTION:
NAME: QueryAD.ps1
Queries Active Directory on a local or remote machine.
PARAMETERS:
-ou the organizational unit to query
-domain the domain to query
-query the query to use. Queries for objects such as:
< User, Group, Computer, OrganizationalUnit,
printqueue, grouppolicycontainer, ipsecpolicy,
pkicertificatetemplate, sitelink, subnet, site >
-help prints help file
SYNTAX:
QueryAD.ps1
Generates message of missing parameter and displays help
QueryAD.ps1 -domain “nwtraders.com” -ou “mytestou” -query computer
Displays a listing of every computer object in the mytestou organizational
unit of the nwtraders.com domain
QueryAD.ps1 -help
Prints the help topic for the script
“@
$helpText
exit
} #end funHelp
Function funQueryAD()
{
$domain = $domain -replace(“^”,”dc=”) #replace first character
$domain = $domain -replace(“.”,”,dc=”) #replace the period
if(!$ou)
{
if(!$query)
{
$strQuery = “<LDAP://$domain>;;name;subtree”
}
ELSE
{
$strQuery = “<LDAP://$domain>;(objectcategory=$query);name;subtree”
}
}
ELSE
{
$ou = $ou -replace(“^”,”ou=”) #replace first character
$ou = $ou -replace(“,”,”,ou=”) #replace a comma
if(!$query)
{
$strQuery = “<LDAP://$ou,$domain>;;name;subtree”
}
ELSE
{
$strQuery = “<LDAP://$ou,$domain>;(objectcategory=$query);name;subtree”
}
}
$objConnection = New-Object -comObject “ADODB.Connection”
$objCommand = New-Object -comObject “ADODB.Command”
$objConnection.Open(“Provider=ADsDSOObject;”)
$objCommand.ActiveConnection = $objConnection
$objCommand.CommandText = $strQuery
$objRecordSet = $objCommand.Execute()
Do
{
$objRecordSet.Fields.item(“name”) |Select-Object name,Value
$objRecordSet.MoveNext()
}
Until ($objRecordSet.eof)
$objConnection.Close()
} #end funQueryAD
if($help) { “calling help …” ; funhelp }
if(!$domain) { “missing the domain name” ; funhelp }
if(!$domain -or !$ou -or !$query) { “a parameter is required” ; funhelp }
funqueryAD
By using the Directory Searcher object, you can reduce significantly the amount of work that is involved in querying Active Directory. The SearchAllComputersInDomain.ps1 script was used for a Hey, Scripting Guy! Blog post in March 2009 when we spent a week talking about searching Active Directory.
SearchAllComputersInDomain.ps1
$Filter = “ObjectCategory=computer”
$Searcher = New-Object System.DirectoryServices.DirectorySearcher($Filter)
$Searcher.Findall() |
Foreach-Object `
-Begin { “Results of $Filter query: ” } `
-Process { $_.properties ; “`r”} `
-End { [string]$Searcher.FindAll().Count + ” $Filter results were found”
In Windows PowerShell 2.0, you can shorten the script a bit by using the [adsisearcher] type accelerator. The [adsisearcher] type accelerator saves you the trouble of creating an instance of the DirectoryServices.DirectorySearcher .NET Framework class. This is seen here.
SearchComputersUseAdsiSearcher.ps1
$Filter = “ObjectCategory=computer”
$Searcher = [adsiSearcher]($Filter)
$Searcher.Findall() |
Foreach-Object `
-Begin { “Results of $Filter query: ” } `
-Process { $_.properties ; “`r”} `
-End { [string]$Searcher.FindAll().Count + ” $Filter results were found” }
If you have at least one Windows Server 2008 R2 domain controller and the Remote Server Administration Tools for Windows 7 (RSAT) tools installed, you can use the Get-ADComputer cmdlet to retrieve information about a computer account in AD DS. The –identity parameter will accept the samAccountName, the DistinguishedName, the security identifier (SID), or the object GUID:
PS C:> Get-ADComputer -Identity hyperv
DistinguishedName : CN=HYPERV,OU=Domain Controllers,DC=NWTraders,DC=Com
DNSHostName : HyperV.NWTraders.Com
Enabled : True
Name : HYPERV
ObjectClass : computer
ObjectGUID : 2a76b1bd-80cb-4546-a8f2-ea46d474e06a
SamAccountName : HYPERV$
SID : S-1-5-21-3746122405-834892460-3960030898-1000
UserPrincipalName :
PS C:> Get-ADComputer -Identity ‘CN=HYPERV,OU=Domain Controllers,DC=NWTraders,DC=Com’
DistinguishedName : CN=HYPERV,OU=Domain Controllers,DC=NWTraders,DC=Com
DNSHostName : HyperV.NWTraders.Com
Enabled : True
Name : HYPERV
ObjectClass : computer
ObjectGUID : 2a76b1bd-80cb-4546-a8f2-ea46d474e06a
SamAccountName&nbs
p; : HYPERV$
SID : S-1-5-21-3746122405-834892460-3960030898-1000
UserPrincipalName :
PS C:> Get-ADComputer -Identity S-1-5-21-3746122405-834892460-3960030898-1000
DistinguishedName : CN=HYPERV,OU=Domain Controllers,DC=NWTraders,DC=Com
DNSHostName : HyperV.NWTraders.Com
Enabled : True
Name : HYPERV
ObjectClass : computer
ObjectGUID : 2a76b1bd-80cb-4546-a8f2-ea46d474e06a
SamAccountName : HYPERV$
SID : S-1-5-21-3746122405-834892460-3960030898-1000
UserPrincipalName :
PS C:> Get-ADComputer -Identity 2a76b1bd-80cb-4546-a8f2-ea46d474e06a
DistinguishedName : CN=HYPERV,OU=Domain Controllers,DC=NWTraders,DC=Com
DNSHostName : HyperV.NWTraders.Com
Enabled : True
Name : HYPERV
ObjectClass : computer
ObjectGUID : 2a76b1bd-80cb-4546-a8f2-ea46d474e06a
SamAccountName : HYPERV$
SID : S-1-5-21-3746122405-834892460-3960030898-1000
UserPrincipalName :
Because the identity parameter is the default parameter for Get-ADComputer, you can leave it out and just supply the name of the computer you wish to query. This is seen here:
PS C:> Get-ADComputer win7-pc
DistinguishedName : CN=WIN7-PC,CN=Computers,DC=NWTraders,DC=Com
DNSHostName : WIN7-PC.NWTraders.Com
Enabled : True
Name : WIN7-PC
ObjectClass : computer
ObjectGUID : 3e802bb2-702a-4039-90dd-d7b624c97440
SamAccountName : WIN7-PC$
SID : S-1-5-21-3746122405-834892460-3960030898-1103
UserPrincipalName :
One strange thing is the use of the property parameter from the Get-ADComputer cmdlet. You would expect that piping the computer object that is returned by the cmdlet to the Format-List cmdlet would provide you the opportunity to work with computer object properties. When working with other objects, you can use the wildcard character “*” and the force switch with the Format-List cmdlet and retrieve all properties and values of an object. As seen here, when working with the Get-ADComputer cmdlet, that is not the case:
PS C:> Get-ADComputer win7-pc | format-list * -Force
DistinguishedName : CN=WIN7-PC,CN=Computers,DC=NWTraders,DC=Com
DNSHostName : WIN7-PC.NWTraders.Com
Enabled : True
Name : WIN7-PC
ObjectClass : computer
ObjectGUID : 3e802bb2-702a-4039-90dd-d7b624c97440
SamAccountName : WIN7-PC$
SID : S-1-5-21-3746122405-834892460-3960030898-1103
UserPrincipalName :
PropertyNames : {DistinguishedName, DNSHostName, Enabled, Name…}
PropertyCount : 9
PS C:>
To obtain all of the information available from a computer object, you must use the property parameter from the Get-ADComputer cmdlet, as seen here:
PS C:> Get-ADComputer -Identity win7-pc -Properties *
AccountExpirationDate :
accountExpires : 9223372036854775807
AccountLockoutTime :
AccountNotDelegated : False
AllowReversiblePasswordEncryption : False
BadLogonCount : 0
badPasswordTime : 0
badPwdCount : 0
CannotChangePassword &nb
sp; : False
CanonicalName : NWTraders.Com/Computers/WIN7-PC
Certificates : {}
CN : WIN7-PC
codePage : 0
countryCode : 0
Created : 9/8/2009 9:48:38 PM
createTimeStamp : 9/8/2009 9:48:38 PM
Deleted :
Description :
DisplayName :
DistinguishedName : CN=WIN7-PC,CN=Computers,DC=NWTraders,DC=Com
DNSHostName : WIN7-PC.NWTraders.Com
DoesNotRequirePreAuth : False
dSCorePropagationData : {12/3/2009 6:32:30 PM, 12/3/2009 6:32:29 PM, 12/2/2009 7:18:22 AM, 12/2/2009 7:18:
22 AM…}
Enabled : True
HomedirRequired : False
HomePage :
instanceType : 4
IPv4Address : 192.168.1.110
IPv6Address :
isCriticalSystemObject : False
isDeleted :
LastBadPasswordAttempt :
LastKnownParent :
lastLogoff : 0
lastLogon : 129084954052650603
LastLogonDate : 1/15/2010 12:28:29 PM
lastLogonTimestamp : 129080501096745399
localPolicyFlags : 0
Location :
LockedOut : False
logonCount : 255
ManagedBy :
MemberOf : {}
MNSLogonAccount
0 comments