Getting usernames from active directory with powershell

From Svendsen Tech PowerShell Wiki
Jump to: navigation, search

Often as a Windows system administrator, you will need to retrieve lists of users from (an OU in) Active Directory. Here I demonstrate a few ways of doing it with PowerShell, using Get-ADUser from the Microsoft AD cmdlets, Get-QADUser from the Quest ActiveRoles cmdlets and also with LDAP/ADSI and DirectoryServices.DirectorySearcher.

These MS AD cmdlets that Get-ADUser 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 computer names.



Using Get-ADUser

First, you need to import the Active Directory module from Microsoft (this will be done automatically from PowerShell version 3 and up, when you use a cmdlet in the module).

PS C:\> Import-Module ActiveDirectory
PS C:\>

Then you can simply use the filter "*" to target any user. Here I get the names of the last five users, using Select-Object to limit the results.

PS C:\> Get-ADUser -Filter '*' | Select -Exp Name -Last 5
hoppla
testadmin
deploymentuser
SharePoint
SharePointServices

Targeting A Specific OU

Here I target the OU svendsen.local/Bruker, using the SearchBase parameter and the OU's LDAP distinguished name:

PS C:\> Get-ADUser -SearchBase 'OU=Bruker,DC=svendsen,DC=local' -Filter '*' | Select -Exp Name
pwdnotusr1
pwdnotusr2
pwdnotusr3

Get-ADUser Example With LastLogonTimestamp

With the Quest cmdlets described below, the LastLogonTimestamp attribute is automatically converted to a human-readable date for you. You will have to use something like this with Get-ADUser from the Microsoft cmdlets:

PS C:\> Get-ADUser -Filter '*' -Properties LastLogonTimestamp |
Sort LastLogonTimestamp |
Select Name,@{n='LastLogonTimestamp';e={if ($_.LastLogonTimestamp) { [datetime]::FromFileTime($_.LastLogonTimestamp)} } }

Name                                                        LastLogonTimestamp
----                                                        ------------------
pwdnotusr3
pwdnotusr1
tullebruker
SharePointServices
deploymentuser
hoppla
krbtgt
Guest
SCCMuser                                                    3/26/2011 2:04:12 PM
pwdnotusr2                                                  9/25/2011 4:25:12 AM
testadmin                                                   12/16/2011 3:10:29 PM
Administrator                                               3/3/2012 12:00:00 AM
SCOMuser                                                    3/7/2012 1:15:40 AM
scomnotify                                                  3/13/2012 3:25:16 AM
SharePoint                                                  3/14/2012 1:15:34 AM
joakimbs                                                    3/17/2012 7:14:01 AM

Using Get-ADObject And An LDAP Query

I describe this in more detail in the DirectorySearcher section, but basically this LDAP query filters out contacts and gets only "regular" user accounts.

PS C:\> Get-ADObject -LDAPFilter '(&(objectCategory=Person)(objectClass=User))' | Select -Exp Name -First 5
Guest
krbtgt
Administrator
scomnotify
SCOMuser

Using ADSI and DirectorySearcher

Here's a way of getting usernames that start with "scom". I filter after the query, using PowerShell's Where-Object cmdlet. To dump every single user, just leave out the last part (" | ? { $_ -imatch '^scom' }"). "?" is an alias for Where-Object/Where.

Using DirectoryServices.DirectorySearcher, you can have some logic in the LDAP query. To get users, you can use something like "objectCategory=User", but this will also get contacts. To get only "regular" user accounts, you can normally use "(&(objectCategory=Person)(objectClass=User))".

Also be aware that the properties you index from the returned System.DirectoryServices.ResultPropertyCollection object are case-sensitive. This almost tripped me up. All the properties appear to be all lowercase when you look at the object.

Here's the first, simple example:

PS C:\> $DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'')
PS C:\> $DirSearcher.Filter = '(&(objectCategory=Person)(objectClass=User))'
PS C:\> $DirSearcher.FindAll().GetEnumerator() | %{ $_.Properties.name } | ? { $_ -imatch '^scom' }
scomnotify
SCOMuser

I should also mention that there's a type accelerator in PowerShell (starting with v1, apparently), which allows you to skip a few steps like this (notice the two quotes after the type accelerator):

PS C:\> $DirSearcher = [adsisearcher]''
PS C:\>

You can also specify the filter directly, like this:

$Searcher = [ADSISearcher] "(SamAccountName=$something)"
if ($Searcher.FindOne().Count -eq 1) { "Found in AD" } else { "Not found in AD" }

Here's what the returned System.DirectoryServices.ResultPropertyCollection object looks like:

PS C:\> $DirSearcher.FindAll().GetEnumerator() | select -first 1 | %{ $_.Properties | gm }


   TypeName: System.DirectoryServices.ResultPropertyCollection

Name          MemberType            Definition
----          ----------            ----------
Clear         Method                System.Void Clear()
Contains      Method                bool Contains(string propertyName)
CopyTo        Method                System.Void CopyTo(System.DirectoryServices.ResultPropertyValueCollection[] arra...
Equals        Method                bool Equals(System.Object obj)
GetEnumerator Method                System.Collections.IDictionaryEnumerator GetEnumerator()
GetHashCode   Method                int GetHashCode()
GetType       Method                type GetType()
ToString      Method                string ToString()
Item          ParameterizedProperty System.DirectoryServices.ResultPropertyValueCollection Item(string name) {get;}
Count         Property              System.Int32 Count {get;}
PropertyNames Property              System.Collections.ICollection PropertyNames {get;}
Values        Property              System.Collections.ICollection Values {get;}

And these are the properties:

PS C:\> $DirSearcher.FindAll().GetEnumerator() | select -first 1 | %{ $_.Properties.PropertyNames }
iscriticalsystemobject
samaccountname
useraccountcontrol
primarygroupid
instancetype
objectclass
pwdlastset
memberof
samaccounttype
usnchanged
accountexpires
adspath
distinguishedname
codepage
name
whenchanged
dscorepropagationdata
description
countrycode
cn
whencreated
objectsid
objectguid
objectcategory
usncreated

Code Example To Dump Every User In AD

Here is a script to dump every single user in AD (not including contacts), using DirectorySearcher.

$DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'')
$DirSearcher.Filter = '(&(objectCategory=Person)(objectClass=User))'
$DirSearcher.FindAll().GetEnumerator() | ForEach-Object {
    
    # These properties are part of a DirectoryServices.ResultPropertyCollection
    # NB! These properties need to be all lowercase!
    $_.Properties.name
    
}

Targeting A Specific OU With ADSI/LDAP/DirectorySearcher

Change this line:

$DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'LDAP://OU=Bruker,dc=svendsen,dc=local')

The relevant part is "[adsi]'LDAP://OU=Bruker,dc=svendsen,dc=local'". Here I target the OU svendsen.local/Bruker.

If you were to use the [adsisearcher] type accelerator, it would look like this:

$DirSearcher = [adsisearcher][adsi]'LDAP://OU=Bruker,dc=svendsen,dc=local'

Getting Accounts With An LDAP Query

Here I describe how to use DirectoryServices.DirectoryServices and an LDAP query for getting disabled and enabled AD accounts. There's some more information here at this external technet.com link.

Getting Disabled AD Accounts

During earlier research, I found that you can use the following LDAP query for getting disabled AD accounts:

(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))

Putting it to use, we get:

PS C:\> $DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'')
PS C:\> $DirSearcher.Filter = '(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))'
PS C:\> $DirSearcher.FindAll().GetEnumerator() | %{ $_.Properties.name }
Guest
krbtgt
PS C:\>

Getting Enabled AD Accounts

For getting enabled AD accounts, you can use the following LDAP query:

(&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))

This basically means "not disabled". The exclamation point, enclosed in parentheses in the LDAP query, negates the logic from the disabled user query - effectively retrieving users that are not disabled.

Putting it to use, we get:

PS C:\> $DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'')
PS C:\> $DirSearcher.Filter = '(&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))'
PS C:\> $DirSearcher.FindAll().GetEnumerator() | %{ $_.Properties.name }
Administrator
scomnotify
SCOMuser
joakimbs
SCCMuser
tullebruker
pwdnotusr1
pwdnotusr2
pwdnotusr3
hoppla
testadmin
deploymentuser
SharePoint
SharePointServices
PS C:\>

Using Get-QADUser

Using the seemingly mature cmdlets found in Quest ActiveRoles, you can retrieve users easily. This also works against Windows Server 2003 Active Directories without Active Directory Web Services running.

First, you need to add the snap-in, unless you start Quest's separate shell:

PS C:\> Add-PSSnapin Quest.ActiveRoles.ADManagement
PS C:\>

Getting Every Single User From AD

This isn't difficult using Quest ActiveRoles. By default the number of retrieved results is limited to 1000, but you can set a higher limit using the -SizeLimit parameter, or set it to 0, which disables the limit.

PS C:\> Get-QADUser -SizeLimit 0 | Select -Exp Name
Guest
krbtgt
Administrator
scomnotify
SCOMuser
joakimbs
SCCMuser
tullebruker
pwdnotusr1
pwdnotusr2
pwdnotusr3
hoppla
testadmin
deploymentuser
SharePoint
SharePointServices
PS C:\>

Getting Disabled AD Users

This is a breeze with the -Disabled parameter for Get-QADUser:

PS C:\> Get-QADUser -SizeLimit 0 -Disabled | Select -Exp Name
Guest
krbtgt
PS C:\>

Targeting A Specific OU With Get-QADUser

Use the -SearchRoot parameter that accepts canonical names:

PS C:\> Get-QADUser -SizeLimit 0 -SearchRoot svendsen.local/Bruker

Name                           Type            DN
----                           ----            --
pwdnotusr1                     user            CN=pwdnotusr1,OU=Bruker,DC=svendsen,DC=local
pwdnotusr2                     user            CN=pwdnotusr2,OU=Bruker,DC=svendsen,DC=local
pwdnotusr3                     user            CN=pwdnotusr3,OU=Bruker,DC=svendsen,DC=local

Get-QADUser Example With LastLogonTimestamp

Here's an example where I include the LastLogonTimestamp property. Unlike with Get-ADUser from Microsoft, it's automatically converted to a human-readable date for you.

PS C:\> Get-QADUser -SizeLimit 0 -IncludedProperties LastLogonTimestamp | Select Name,LastLogonTimestamp

Name                                                        LastLogonTimestamp
----                                                        ------------------
Guest
krbtgt
Administrator                                               3/3/2012 12:00:00 AM
scomnotify                                                  3/13/2012 3:25:16 AM
SCOMuser                                                    3/7/2012 1:15:40 AM
joakimbs                                                    3/17/2012 7:14:01 AM
SCCMuser                                                    3/26/2011 2:04:12 PM
tullebruker
pwdnotusr1
pwdnotusr2                                                  9/25/2011 4:25:12 AM
pwdnotusr3
hoppla
testadmin                                                   12/16/2011 3:10:29 PM
deploymentuser
SharePoint                                                  3/14/2012 1:15:34 AM
SharePointServices