Getting computer names from AD using Powershell
From Svendsen Tech Powershell Wiki
General Information
Often as a Windows system administrator, you will want to get a list of computer/host names from (an OU in) Active Directory. Here are a few ways of doing it with PowerShell, using System.DirectoryServices.DirectorySearcher ([adsisearcher]) with an LDAP query, Get-ADComputer from the Microsoft ActiveDirectory module cmdlets and Get-QADComputer from Quest ActiveRoles.
These MS AD cmdlets that Get-ADComputer and Get-ADObject are part of are installed as a feature under the category "Remote Server Administration Tools" (RSAT) from Server Manager on Windows Server 2008 R2 and Windows 7. There's more information about this here and here.
See this article for getting usernames.
Contents |
Using Get-ADComputer
First you need to import the ActiveDirectory module after having installed it as a feature (under RSAT in Server Manager -> Features -> Add feature -> Remote Server Administration Tools):
PS C:\prog\PowerShell> Import-Module ActiveDirectory PS C:\prog\PowerShell>
To just dump every single computer in a domain, and possibly redirect to a file by adding " > computers.txt", you can do it like this:
PS C:\prog\PowerShell> Get-ADComputer -Filter 'ObjectClass -eq "Computer"' | Select -Expand DNSHostName 2008R2ESXI2.svendsen.local 2008r2esxi.svendsen.local srv2003r2esxi.svendsen.local siemens.svendsen.local WIN7ESXI.svendsen.local winxpesxi.svendsen.local win2k.svendsen.local vista64esxi.svendsen.local server2003.svendsen.local xptanket.svendsen.local SERVER2008.svendsen.local esxi.svendsen.local winxpssd.svendsen.local
Technically, that filter is (bloody well should be) redundant. You can also use -like instead of -eq. I'm having some trouble with wildcards in combination with text, though (such as in 'ObjectClass -like "*ompute*"').
You can also redirect to a file, and specify encoding, by piping to Set-Content rather than using the redirection operator ">", which does the same thing as Out-File. When working with text/strings, they will work equivalently, and since we're using Select-Object with the parameter -ExpandProperty ("-Exp" in the examples), we get strings. There's a lot more to be said about this, but it does not belong in this article.
Getting Just The Host Name
Above I selected the property "DNSHostName". If you use the property "Name" instead, you will get just the host name:
PS C:\prog\PowerShell> Get-ADComputer -Filter '*' | Select -Expand Name 2008R2ESXI2 2008R2ESXI SRV2003R2ESXI SIEMENS WIN7ESXI WINXPESXI WIN2K VISTA64ESXI SERVER2003 XPTANKET SERVER2008 esxi WINXPSSD
I also used a different filter here. Basically, when you use the Get-ADComputer cmdlet, there should be built-in filtering that targets computer objects, so you can use any property and a wildcard match with "-like '*'" or similar. I experimented with just a wildcard ("*") to target anything, and it seems to work as intended.
Getting Server Or Client Operating Systems Only
To get server operating systems only, I currently don't know of any (much) better way than filtering on the "OperatingSystem" text containing "Windows Server". You can also use a script block for the filter, which helps avoid nested quoting, and can be done like this:
PS C:\> Get-ADComputer -Filter { OperatingSystem -Like '*Windows Server*' } -Properties OperatingSystem |
>> Select Name, OperatingSystem | Format-Table -AutoSize
>>
Name OperatingSystem
---- ---------------
2008R2ESXI2 Windows Server 2008 R2 Standard
2008R2ESXI Windows Server 2008 R2 Standard
SRV2003R2ESXI Windows Server 2003
SERVER2003 Windows Server 2003
SERVER2008 Windows Serverr 2008 Standard
SERVER2012RC Windows Server 2012 Release Candidate Datacenter
PS C:\>
As we can see, this works for Server 2003 through Server 2012 versions of Windows Server operating systems.
To do the opposite, and only get client operating systems, you can use -NotLike instead of -Like:
PS C:\> Get-ADComputer -Filter { OperatingSystem -NotLike '*Windows Server*' } -Properties OperatingSystem |
>> Select Name, OperatingSystem | Format-Table -AutoSize
>>
Name OperatingSystem
---- ---------------
SIEMENS Windows XP Professional
WIN7ESXI Windows 7 Professional
WINXPESXI Windows XP Professional
WIN2K Windows 2000 Professional
VISTA64ESXI Windows VistaT Ultimate
XPTANKET Windows XP Professional
esxi unknown
WINXPSSD Windows XP Professional
VMWAREWIN7 Windows 7 Professional
SS-WIN7 Windows 7 Professional
WIN8VM Windows 8 Pro
PS C:\>
Targeting A Specific OU
Here I target the OU "svendsen.local/Hjemme/Clients" using the -SearchBase parameter and the LDAP distinguished name for this OU.
PS C:\> Get-ADComputer -SearchBase 'OU=Clients,OU=Hjemme,dc=svendsen,dc=local' -Filter '*' | Select-Object -ExpandProperty Name XPTANKET WINXPSSD SIEMENS WIN7ESXI WINXPESXI WIN2K VISTA64ESXI
This OU:
Using An LDAP Query
Using an LDAP query effectively similar to the filter in the first example, you can do something like this:
PS C:\prog\PowerShell> Get-ADComputer -LDAPFilter '(objectClass=Computer)' | Select -Expand Name 2008R2ESXI2 2008R2ESXI SRV2003R2ESXI SIEMENS WIN7ESXI WINXPESXI WIN2K VISTA64ESXI SERVER2003 XPTANKET SERVER2008 esxi WINXPSSD
Using An LDAP Query And Get-ADObject
You can use the same filter with Get-ADObject:
PS C:\prog\PowerShell> Get-ADObject -LDAPFilter '(objectClass=Computer)' | Select -Expand Name 2008R2ESXI2 2008R2ESXI SRV2003R2ESXI SIEMENS WIN7ESXI WINXPESXI WIN2K VISTA64ESXI SERVER2003 XPTANKET SERVER2008 esxi WINXPSSD
Filtering Using Wildcards And Where-Object
Here I filter on computer names that start with "2008":
PS C:\prog\PowerShell> Get-ADComputer -Filter 'SamAccountName -like "2008*"' | Select -Exp Name 2008R2ESXI 2008R2ESXI2
And here I filter on computer names that contain "2008":
PS C:\prog\PowerShell> Get-ADComputer -Filter 'SamAccountName -like "*2008*"' | Select -Exp Name 2008R2ESXI2 2008R2ESXI SERVER2008
Of course you can also filter in the pipeline using PowerShell's Where-Object/Where, although it'll probably be less efficient on large queries (I haven't benchmarked):
PS C:\prog\PowerShell> Get-ADComputer -Filter '*' | Where { $_.Name -imatch '2008' } | Select -Exp Name
2008R2ESXI2
2008R2ESXI
SERVER2008
Using DirectorySearcher/AdsiSearcher
If this is the absolute best way of doing this, I do not know, but it seems quite likely that it's no crime against humanity given my experimentation and inspection of the (computer) objects returned by DirectoryServices.DirectorySearcher.
Here's the output from my home lab's AD (these indeed are all the computers in the Active Directory):
PS C:\prog\PowerShell> .\Get-Computers-DS.ps1 2008R2ESXI2 2008R2ESXI SRV2003R2ESXI SIEMENS WIN7ESXI WINXPESXI WIN2K VISTA64ESXI SERVER2003 XPTANKET SERVER2008 esxi WINXPSSD
Basically with DirectoryServices.DirectorySearcher, the real magic is in the LDAP query, and you might have to inspect returned objects to see what their properties are. The LDAP query is specified via the Filter property of the directory searcher object, and in this case it is "(objectClass=Computer)".
Also be aware that the property you index is case-sensitive, and that they're all listed as lower-case when you look at the returned System.DirectoryServices.ResultPropertyCollection object.
For your convenience, here is a ready-made script that'll just dump every single computer from the AD of the first available domain controller, using Windows' method for detecting domain controllers:
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'')
$DirSearcher.Filter = '(objectClass=Computer)'
$DirSearcher.FindAll().GetEnumerator() | ForEach-Object {
# These properties are part of a DirectoryServices.ResultPropertyCollection
# NB! These properties need to be all lowercase!
$_.Properties.name
}
I should also mention that there's a type accelerator in PowerShell v2 (I don't know about v1.x), which allows you to skip a few steps like this (notice the two quotes after the type accelerator):
PS C:\> $DirSearcher = [adsisearcher]'' PS C:\>
Targeting A Specific OU With ADSI/LDAP/DirectorySearcher
To target a specific OU/container, change the following line in the script above (this example is valid in my home lab):
$DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'LDAP://OU=Clients,OU=Hjemme,DC=svendsen,DC=local')
So here I prepended "LDAP://" to the distinguished name of the OU, enclosed it in a string and cast it to an ADSI object, which was then used to to create a System.DirectoryServices.DirectorySearcher object. This targets the OU svendsen.local/Hjemme/Clients.
If you were to use the [adsisearcher] type accelerator, it would look like this:
$DirSearcher = [adsisearcher][adsi]'LDAP://OU=Clients,OU=Hjemme,DC=svendsen,DC=local'
Using Quest ActiveRoles Get-QADComputer
This example, and the script below, uses Get-QADComputer from Quest ActiveRoles - a very handy and seemingly mature set of cmdlets for working with Active Directory. They are free - and also work against ADs running on Server 2003 without Active Directory Web Services.
PS C:\powershell> Get-QADComputer -SearchRoot internal.domain.com/someOU/someSubOU -SizeLimit 0 | %{ $_.Name }
comp1
comp2
comp3
comp4
comp5
PS C:\powershell> Get-QADComputer -SearchRoot internal.domain.com/someOU/someSubOU -SizeLimit 0 | %{ $_.Name } > foo.txt
PS C:\powershell> (Get-Content .\foo.txt).Count
5
PS C:\powershell> (Get-Content .\foo.txt)[1,-1]
comp1
comp5
Rather than " | %{ $_.Name }", you can probably more conventionally use " | Select-Object -ExpandProperty Name". You can also use " | Out-File foo.txt" instead of " > foo.txt" - or Add/Set-Content. (Do we love or hate choices? They sort of suck when documenting.)
Random Get-QADComputer Sample
This script will get some data from AD and redirect it to a file. Easily adapted to other needs. This will retrieve the fields Name, OSName, OSVersion, OSServicePack and LastLogonTimeStamp. See the sample output below for what it looks like. I find sorting on LastLogonTimeStamp useful (read about it here and here). I use this script to manually inspect and just remove "old" computers if I'm going to run a command against multiple online computers, for instance. Be aware, however, that I have seen computers with several years old LastLogonTimeStamps that are actually online and available. The reason for this, I do not know.
Download
- Download Get-all-ad-computers.ps1.txt here (right-click, "save as" and rename to .ps1).
Sample Output
PS C:\powershell> .\get-all-ad-computers.ps1 cmdlet get-all-ad-computers.ps1 at command pipeline position 1 Supply values for the following parameters: OutputFile: test.txt Running Get-QADComputer... Start time: 05/19/2011 23:36:14 End time: 05/19/2011 23:36:28 Output file: test.txt PS C:\powershell> notepad .\test.txt PS C:\powershell> type .\test.txt | Select-Object -first 10 Name OSName OSVersion OSServicePack lastLogonTimestamp ---- ------ --------- ------------- ------------------ comp1 Windows XP Professional 5.1 (2600) Service Pack 2 17.03.2010 03:07:14 comp2 Windows XP Professional 5.1 (2600) Service Pack 2 18.03.2010 08:04:52 comp3 Windows XP Professional 5.1 (2600) Service Pack 3 18.03.2010 12:27:59 comp4 Windows XP Professional 5.1 (2600) Service Pack 3 18.03.2010 12:35:31 comp5 Windows XP Professional 5.1 (2600) Service Pack 3 18.03.2010 14:07:31 comp6 Windows XP Professional 5.1 (2600) Service Pack 3 19.03.2010 11:46:23 comp7 Windows XP Professional 5.1 (2600) Service Pack 3 20.03.2010 19:50:29
Getting Just The Computer Names From That Output
I figure you might want to get just the computer names from that output, and of course you can just run a query where you pipe Get-QADComputer to Select-Object -ExpandProperty Name, but I'll throw in a little example of getting the first "word" (non-whitespace characters in sequence) on a line. In this case you will have to remove the headers manually with notepad or another editor (or Get-Content and Select-Object -First/-Last/-Skip if you like).
Using Split
Read more about the PowerShell split operator here.
PS E:\temp> (gc .\computers.txt)[0,-1]
comp1 Windows XP Professional 5.1 (2600) Service Pack 2 17.03.2010 03:07:14
comp7 Windows XP Professional 5.1 (2600) Service Pack 3 20.03.2010 19:50:29
PS E:\temp> gc .\computers.txt | %{ ($_ -split '\s+')[0] }
comp1
comp2
comp3
comp4
comp5
comp6
comp7
Using A Regular Expression
Read more about PowerShell regular expressions here.
PS E:\temp> (gc .\computers.txt)[0,-1]
comp1 Windows XP Professional 5.1 (2600) Service Pack 2 17.03.2010 03:07:14
comp7 Windows XP Professional 5.1 (2600) Service Pack 3 20.03.2010 19:50:29
PS E:\temp> gc .\computers.txt | %{ if ($_ -match '^(\S+)') { $matches[1] } }
comp1
comp2
comp3
comp4
comp5
comp6
comp7
Script Code
param([Parameter(Mandatory=$true)][string] $OutputFile)
$StartTime = Get-Date
# Check that the Quest.ActiveRoles.ADManagement snapin is available
if (!(Get-PSSnapin Quest.ActiveRoles.ADManagement -registered -ErrorAction SilentlyContinue)) {
'You need the Quest ActiveRoles AD Management Powershell snapin to use this script'
"www.quest.com`n"
'Please install and register this snapin. Exiting...'
exit 0
}
# Add the snapin and don't display an error if it's already added.
# If it's not registered, this will be handled above, so this should succeed.
Add-PSSnapin Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue
'Running Get-QADComputer...'
Get-QADComputer -SizeLimit 0 -IncludedProperties LastLogonTimeStamp |
Select-Object Name, OSName, OSVersion, OSServicePack, LastLogonTimeStamp |
#Where-Object { ($_.OSVersion -match '^5\.1') } | # Filter on XP/2003
Sort-Object @{Expression={$_.LastLogonTimeStamp};Ascending=$true} |
Format-Table -AutoSize -Property Name, OSName, OSVersion, OSServicePack, LastLogonTimeStamp |
Out-File $OutputFile
@"
Start time: $StartTime
End time: $(Get-Date)
Output file: $OutputFile
"@
Keywords: Active Directory, AD, Powershell, Exporting, CSV, LastLogonTimeStamp, LastLogon, Quest ActiveRoles cmdlets, Get-ADComputer, DirectorySearcher, LDAP query for computers

