Hey, Scripting Guy! How Can I Use Windows PowerShell to Search Active Directory?

Hey, Scripting Guy! How Can I Use Windows PowerShell to Search Active Directory?

  • Comments 1
  • Likes

 Bookmark and Share

 

Hey, Scripting Guy! Question

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

 

Hey, Scripting Guy! AnswerHello 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 35 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.

Image of Lima, Peru

 

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    : 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               : 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                    : False
Modified                           : 1/18/2010 8:41:55 AM
modifyTimeStamp                    : 1/18/2010 8:41:55 AM
msDS-SupportedEncryptionTypes      : 28
msDS-User-Account-Control-Computed : 0
Name                               : WIN7-PC
nTSecurityDescriptor               : System.DirectoryServices.ActiveDirectorySecurity
ObjectCategory                     : CN=Computer,CN=Schema,CN=Configuration,DC=NWTraders,DC=Com
ObjectClass                        : computer
ObjectGUID                         : 3e802bb2-702a-4039-90dd-d7b624c97440
objectSid                          : S-1-5-21-3746122405-834892460-3960030898-1103
OperatingSystem                    : Windows 7 Enterprise
OperatingSystemHotfix              :
OperatingSystemServicePack         :
OperatingSystemVersion             : 6.1 (7600)
PasswordExpired                    : False
PasswordLastSet                    : 1/18/2010 8:41:55 AM
PasswordNeverExpires               : False
PasswordNotRequired                : False
PrimaryGroup                       : CN=Domain Computers,CN=Users,DC=NWTraders,DC=Com
primaryGroupID                     : 515
ProtectedFromAccidentalDeletion    : False
pwdLastSet                         : 129082957152111233
SamAccountName                     : WIN7-PC$
sAMAccountType                     : 805306369
sDRightsEffective                  : 15
ServiceAccount                     : {}
servicePrincipalName               : {WSMAN/win7-PC, WSMAN/win7-PC.NWTraders.Com, TERMSRV/WIN7-PC, TERMSRV/win7-PC.NWTr
                                     aders.Com...}
ServicePrincipalNames              : {WSMAN/win7-PC, WSMAN/win7-PC.NWTraders.Com, TERMSRV/WIN7-PC, TERMSRV/win7-PC.NWTr
                                     aders.Com...}
SID                                : S-1-5-21-3746122405-834892460-3960030898-1103
SIDHistory                         : {}
TrustedForDelegation               : False
TrustedToAuthForDelegation         : False
UseDESKeyOnly                      : False
userAccountControl                 : 4096
userCertificate                    : {}
UserPrincipalName                  :
uSNChanged                         : 271739
uSNCreated                         : 12748
whenChanged                        : 1/18/2010 8:41:55 AM
whenCreated                        : 9/8/2009 9:48:38 PM



PS C:\>

NN, that is all there is to using Windows PowerShell to search Active Directory. Searching Active Directory Week will continue tomorrow.

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment