Summary: Microsoft Scripting Guy, Ed Wilson, talks about using DSQuery to return results for use in Windows PowerShell.

Hey, Scripting Guy! Question Hey, Scripting Guy!  I like using the DSQuery tool to search Active Directory Domain Services (AD DS). Can I use that tool with Windows PowerShell?

—WS

Hey, Scripting Guy! Answer Hello WS,

Microsoft Scripting Guy, Ed Wilson, is here. Yes, it is possible, but I think that there are problems with using the DSQuery tool from within Windows PowerShell. The problems come from the nature of the DSQuery tool itself, and not from within Windows PowerShell. If you are good at using DSQuery and DSGet, you might not have any problems, but personally, I think there are easier methods. I wrote a Hey, Scripting Guy! Blog called Query Active Directory Without Writing a Script; and in that blog, I discuss different methods of querying AD DS. You can refer to that blog for additional information about the tools.

The bad thing about DSQuery

The bad thing about it is not so much a limitation of DSQuery, as it is a limitation of all such command-line utilities. It returns strings; therefore, if the output is not exactly to my liking, I have to do string manipulation—and personally, I hate string manipulation. I have always hated string manipulation—from the VBScript days, and even back into the days of CPM. String manipulation simply is not “my thing.”

Another bad thing about DSQuery is that it is not installed by default, and the only way to get it on my laptop running Windows 8 is to download and to install the Remote Server Administration Tools (RSAT), which is yet to be released. A bad thing about the RSAT is that it is version specific, and even service pack specific. In Windows 7, I had to uninstall the RSAT, install Service Pack 1, then reinstall the RSAT. Of course, I did not find that out until after the service pack installation failed. So, I am always a little leery of installing extra stuff that I really do not need on my computers.

Of course, by using Windows PowerShell remoting, I do not need to install the RSAT on my computer only to use DSQuery. I can easily use the Invoke-Command cmdlet to perform the remote query on a server (by default all domain controllers will have DSQuery installed with their admin tools). I first store the credentials that I need in a variable I call $cred. I use the Get-Credential cmdlet to obtain the credential object. Next, I use the Invoke-Command cmdlet to specify the remote server from which to process the query, and I pass the credentials. I store the returned array of strings in the $computers variable, and I then display the strings. The commands are shown here.

$cred = get-credential iammred\administrator

$computers = invoke-command -cn dc3 {dsquery computer} -cred $cred

$computers

The commands and the associated output are shown in the image that follows.

Image of command output

The strings are included in the output. To obtain only the computer name itself requires further processing. One way to get the computer name would be to use a regular expression and pick out the stuff following the first CN= that occurs before a comma. That would work, but I like regular expressions even less than I like string manipulation.

Therefore, I can turn the returned strings into ADSPath and supply that to the [adsi] type accelerator. To do that is not to horribly complicated. First, I need to get the output into a fashion I can pass to the [adsi] type accelerator. This is a two-step operation. First I replace the first CN= with LDAP://CN= and store the results back into a variable. This command is shown here.

$ads = $computers -replace '^"CN=', '"LDAP://CN='

For some reason, it does not seem to like the quotation marks when I pass it to [adsi], so I need to remove them. Here is the command that I use for that.

$ads = $ads | % {$_ -replace '"', ""}

Now, I can use ADSPath to create a DirectoryEntry object and retrieve the CN property (the basic computer name). This command is shown here.

$ads | Foreach-Object  {([adsi]$_).cn}

The nice thing about objects

The nice thing about objects is that they make it easy to access different parts of information. For example, when I use the [adsisearcher] type accelerator to find computers from inside AD DS, it returns a SearchResult object. This object contains a number of methods, but it also contains two properties. The first property is the Path property, which is a string. The second property, the Properties property contains an additional object. The output from the Get-Member cmdlet displays this information.

[dc3]: PS C:\> ([adsisearcher]"objectcategory=computer").findall() | get-member

 

   TypeName: System.DirectoryServices.SearchResult

 

Name              MemberType Definition

----              ---------- ----------

Equals            Method     bool Equals(System.Object obj)

GetDirectoryEntry Method     adsi GetDirectoryEntry()

GetHashCode       Method     int GetHashCode()

GetType           Method     type GetType()

ToString          Method     string ToString()

Path              Property   System.String Path {get;}

Properties        Property   System.DirectoryServices.ResultPropertyCollection Pr...

The cool thing about the Properties property is that it contains a collection of default properties and their associated values. The following command stores the Properties collection into a variable.

$a = ([adsisearcher]"objectcategory=computer").findall() | ForEach-Object {$_.properties}

To obtain only the computer names in Windows PowerShell 2.0, I can use the GetEnumerator method and then select only the CN property. In addition, I can create a custom object that contains only the properties I want. First, here is the code to select only the computer names.

$a.GetEnumerator() | select { $_.cn}

Note   I talked about using the GetEnumerator method when working with hash tables in a blog called Dealing with PowerShell Hash Table Quirks.

I can sort the information, and return a custom object. This command is shown here.

$a.GetEnumerator() | sort {$_.operatingsystem} | select {$_.cn, $_.operatingsystem}

Because I am working with Windows PowerShell objects, I can do anything I want to do to them. For example, I can sort and group the output as shown here.

PS C:\> $a.GetEnumerator() | sort {$_.operatingsystem} |

group {$_.operatingsystem} -NoElement | sort count

 

Count Name

----- ----

    1 OnTap

    1 Windows 7 Enterprise

    1 Windows 8 Consumer Pre...

    1 Windows 8 Pro N

    1 Windows 8 Release Preview

    1 Windows Server 2012 Da...

    1 Windows Server 2012 Re...

    1 Windows Vista™ Enterprise

    2 Windows 8 Enterprise E...

    2 Windows 8 Pro

    2 Windows Server 8 Beta ...

    3 Windows Server® 2008 E...

    8 Windows 7 Ultimate

   11 Windows Server 2008 R2...

WS, that is all there is to using DSQuery to search Active Directory Domain Services. Join me tomorrow for more cool Windows PowerShell stuff.

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