PowerShell How To: Building Effective Lists with Active Directory and DNS

In an earlier article I demonstrated some techniques for creating and using lists of computer names. I hope you found that article helpful. Today, I want to show you another way to handle property name problems, as well as other ways for building lists dynamically from Active Directory or DNS.

Alternate Property Names

In the last article I explained the importance of aligning the property name from any imported list, such as a CSV file, with the parameter name of cmdlets that you intend to use. For most cmdlets, this means ensuring that any object has a property name of Computername. But suppose you have a CSV file that uses something else? I have an alternate version of the CSV file I used last time that does just that.

$computers = Import-CSV C:\scripts\computers-alternate.csv
$computers[0..3]

Importing a list with an incompatible property name (Image Credit: Jeff Hicks)
Importing a list with an incompatible property name (Image Credit: Jeff Hicks)

As you can see in the figure, my imported objects have a property of ‘Server’. Let’s say I didn’t want to manually edit the CSV file first. How might I fix this so that the property is Computername? One way would be to use Select-Object and define a custom property.

$computers[0..3] |
Select @{Name="Computername";Expression={$_.Server}} |
Get-Service bits |
Format-Table Machinename,Name,Status -AutoSize

Using a custom property to rename (Image Credit: Jeff Hicks)
Using a custom property to rename (Image Credit: Jeff Hicks)

The downside is that you need to use this technique every time you want to use the computer data. As an alternative, you could import the CSV file with an alternate header. Although this requires a few more steps, you only have to do it once.

$computers = Get-Content C:\scripts\computers-alternate.csv | Select-Object -Skip 1 | ConvertFrom-Csv -Header "Computername","IP","Notes"

Instead of directly importing the CSV file, I am getting the file contents using Get-Content. I am then skipping the first line, which in my file is the header line. You have to know in advance what your file looks like. This leaves me with a bunch of CSV lines without a header, which I can now add back with ConvertFrom-Csv. But now I have a collection of computer objects with the right property name.

Converted CSV data (Image Credit: Jeff Hicks)
Converted CSV data (Image Credit: Jeff Hicks)

Now, you can use the data using the techniques I demonstrated in the previous article.

Building a List with Active Directory

Another option and one I see come up quite often in forums, is building a list from Active Directory. The easiest way is to use the Microsoft Active Directory module, which you can get when you install the latest version of Remote Server Administration Tools (RSAT) on your desktop. I don’t want this to become a tutorial on using Get-ADComputer so take a few minutes to read the help and examples, especially if you want to limit your search to a particular OU. What is important for us is what type of object we get.

Sample AD Computer object (Image Credit: Jeff Hicks)
Sample AD Computer object (Image Credit: Jeff Hicks)

All of the servers I might want to query in my domain all start with CHI-, so I am filtering on the name property. As you can see in the figure, the computername has a property of Name,  which doesn’t line up if I want to take advantage of parameter binding. One option is to add a new property using Add-Member.

Get-ADComputer -filter "name -like 'CHI-*'" -ResultSetSize 3 |
Add-Member -MemberType AliasProperty -Name Computername -Value Name -force -PassThru

I’m only selecting a small number of computer accounts for the sake of my demonstration. Be sure to include the –Passthru parameter, otherwise PowerShell won’t write anything to the pipeline.

Inserting an alias property with Add-Member (Image Credit: Jeff Hicks)
Inserting an alias property with Add-Member (Image Credit: Jeff Hicks)

This is a good technique if you want to retain the rest of the original object. But if you just want an object with a single property, you can use Select-Object.

$computers = Get-ADComputer -filter "name -like 'CHI-*'" -ResultSetSize 5 | Select @{Name="Computername";Expression={$_.name}}

Renamed single property list (Image Credit: Jeff Hicks)
Renamed single property list (Image Credit: Jeff Hicks)

Or, perhaps you simply want a list of names.

$computers = (Get-ADComputer -filter "name -like 'CHI-*'" -ResultSetSize 5).name

Creating a simple list from Active Directory (Image Credit: Jeff Hicks)
Creating a simple list from Active Directory (Image Credit: Jeff Hicks)

You can use the Filter and SearchBase parameters with Get-ADComputer to fine-tune your list.

Using DNS

The last option, again assuming you have RSAT installed is to use the DNSServer module and Get-DnsServerResourceRecord. It is always helpful to see the results first.

Get-DnsServerResourceRecord -ComputerName chi-dc04 -ZoneName globomantics.local -RRType A

Using Get-DnsServerResourceRecord (Image Credit: Jeff Hicks)
Using Get-DnsServerResourceRecord (Image Credit: Jeff Hicks)

The HostName property appears to be what I want. Unfortunately, the Name parameter doesn’t accept wildcards, so if I want to limit my results, then I’ll have to use Where-Object or the Where() method because I am running PowerShell v4. The latter performs much faster.

(Get-DnsServerResourceRecord -ComputerName chi-dc04 -ZoneName globomantics.local -RRType A).Where({$_.hostname -match "^chi-"})

Filtering DNS records with the Where() method (Image Credit: Jeff Hicks)
Filtering DNS records with the Where() method (Image Credit: Jeff Hicks)

Again, because the property name doesn’t match up, I can rename:

$computers = (Get-DnsServerResourceRecord -ComputerName chi-dc04 -ZoneName globomantics.local -RRType A).Where({$_.hostname -match "^chi-"}) |
Select-Object @{Name="Computername";Expression={$_.Hostname}}

Creating a DNS list with a renamed property (Image Credit: Jeff Hicks)
Creating a DNS list with a renamed property (Image Credit: Jeff Hicks)

Or I can expand the property name:

$computers = (Get-DnsServerResourceRecord -ComputerName chi-dc04 -ZoneName globomantics.local -RRType A).Where({$_.hostname -match "^chi-"}).Hostname

Creating a DNS name list (Image Credit: Jeff Hicks)
Creating a DNS name list (Image Credit: Jeff Hicks)

Naturally you will create a filter that meets your needs.

Now that we have a list of computers we’re good to use it, right? Well unless you maintain a perfect environment, most likely not. There’s no guarantee all of the computers in the list are still active, especially when querying Active Directory or DNS, or that they are up and running. In the next article, we’ll look at some techniques for validating the names in the list.