Training
Get a free hour of SANS training

Experience SANS training through course previews.

Learn More
Learning Paths
Can't find what you are looking for?

Let us help.

Contact us
Resources
Join the SANS Community

Become a member for instant access to our free resources.

Sign Up
For Organizations
Interested in developing a training plan to fit your organization’s needs?

We're here to help.

Contact Us
Talk with an expert

Month of PowerShell - The Curious Case of AD User Properties

Join me as we answer the question: Where are all of the user properties for Active Directory users for Get-ADUSer?

Authored byJoshua Wright
Joshua Wright

#monthofpowershell

In my first Month of PowerShell getting started article I talked about a common PowerShell process: running a cmdlet and piping the results to [code]Get-Member[/code] or [code]Select-Object -Property *[/code] to get a list of the object properties.

It's standard PowerShell practice, and I've done it hundreds of times throughout the Month of PowerShell. That is, until I started working with Active Directory user properties:

PS C:\Users\jwright> Get-ADUser -Identity jwright | Select-Object -Property *


DistinguishedName  : CN=jwright,CN=Users,DC=falsimentis,DC=local
Enabled            : True
GivenName          :
Name               : jwright
ObjectClass        : user
ObjectGUID         : f69b19e6-61ac-4cae-a7ac-ec88ec3bb564
SamAccountName     : jwright
SID                : S-1-5-21-1850091285-130397106-3068105436-500
Surname            :
UserPrincipalName  :
PropertyNames      : {DistinguishedName, Enabled, GivenName, Name...}
AddedProperties    : {}
RemovedProperties  : {}
ModifiedProperties : {}
PropertyCount      : 10
PS C:\Users\jwright>

Normally, I'd expect to see all of the properties for the AD User object, but lots of properties are missing. This is not consistent with other PowerShell cmdlet behavior.

Looking at the [code]Get-Help Get-ADUser[/code] output, there is an option [code]-Properties[/code] that accepts a string or list or strings, similar to what we see in the help for [code]Select-Object[/code]. When we use that option with a wildcard, we get all the AD user properties:

PS C:\Users\jwright> Get-ADUser -Identity jwright -Properties * | Select-Object -Property *


AccountExpirationDate                :
accountExpires                       : 0
AccountLockoutTime                   :
AccountNotDelegated                  : False
AllowReversiblePasswordEncryption    : False
AuthenticationPolicy                 : {}
AuthenticationPolicySilo             : {}
BadLogonCount                        : 0
badPasswordTime                      : 0
badPwdCount                          : 0
CannotChangePassword                 : False
CanonicalName                        : falsimentis.local/Users/jwright
Certificates                         : {}
City                                 :
CN                                   : jwright
codePage                             : 0
Company                              :
CompoundIdentitySupported            : {}
Country                              :
countryCode                          : 0
Created                              : 7/16/2022 7:08:49 PM
createTimeStamp                      : 7/16/2022 7:08:49 PM
Deleted                              :
Department                           :
Description                          : Built-in account for administering the computer/domain
DisplayName                          :
DistinguishedName                    : CN=jwright,CN=Users,DC=falsimentis,DC=local
Division                             :
DoesNotRequirePreAuth                : False
dSCorePropagationData                : {7/16/2022 7:09:34 PM, 1/1/1601 12:00:01 AM}
EmailAddress                         :
EmployeeID                           :
EmployeeNumber                       :
Enabled                              : True
Fax                                  :
GivenName                            :
HomeDirectory                        :
HomedirRequired                      : False
HomeDrive                            :
HomePage                             :
HomePhone                            :
Initials                             :
instanceType                         : 4
isCriticalSystemObject               : True
isDeleted                            :
KerberosEncryptionType               : {}
LastBadPasswordAttempt               :
LastKnownParent                      :
lastLogoff                           : 0
lastLogon                            : 133024722383629408
LastLogonDate                        : 7/16/2022 7:10:23 PM
lastLogonTimestamp                   : 133024722231721433
LockedOut                            : False
logonCount                           : 25
logonHours                           : {255, 255, 255, 255...}
LogonWorkstations                    :
Manager                              :
MemberOf                             : {CN=Group Policy Creator Owners,CN=Users,DC=falsimentis,DC=local, CN=Domain
                                       Admins,CN=Users,DC=falsimentis,DC=local, CN=Enterprise
                                       Admins,CN=Users,DC=falsimentis,DC=local, CN=Schema
                                       Admins,CN=Users,DC=falsimentis,DC=local...}
MNSLogonAccount                      : False
MobilePhone                          :
Modified                             : 7/16/2022 7:10:23 PM
modifyTimeStamp                      : 7/16/2022 7:10:23 PM
msDS-User-Account-Control-Computed   : 0
Name                                 : jwright
nTSecurityDescriptor                 : System.DirectoryServices.ActiveDirectorySecurity
ObjectCategory                       : CN=Person,CN=Schema,CN=Configuration,DC=falsimentis,DC=local
ObjectClass                          : user
ObjectGUID                           : f69b19e6-61ac-4cae-a7ac-ec88ec3bb564
objectSid                            : S-1-5-21-1850091285-130397106-3068105436-500
Office                               :
OfficePhone                          :
Organization                         :
OtherName                            :
PasswordExpired                      : False
PasswordLastSet                      : 7/16/2022 6:42:54 PM
PasswordNeverExpires                 : False
PasswordNotRequired                  : False
POBox                                :
PostalCode                           :
PrimaryGroup                         : CN=Domain Users,CN=Users,DC=falsimentis,DC=local
primaryGroupID                       : 513
PrincipalsAllowedToDelegateToAccount : {}
ProfilePath                          :
ProtectedFromAccidentalDeletion      : False
pwdLastSet                           : 133024705746844315
SamAccountName                       : jwright
sAMAccountType                       : 805306368
ScriptPath                           :
sDRightsEffective                    : 15
ServicePrincipalNames                : {}
SID                                  : S-1-5-21-1850091285-130397106-3068105436-500
SIDHistory                           : {}
SmartcardLogonRequired               : False
State                                :
StreetAddress                        :
Surname                              :
Title                                :
TrustedForDelegation                 : False
TrustedToAuthForDelegation           : False
UseDESKeyOnly                        : False
userAccountControl                   : 512
userCertificate                      : {}
UserPrincipalName                    :
uSNChanged                           : 12579
uSNCreated                           : 8196
whenChanged                          : 7/16/2022 7:10:23 PM
whenCreated                          : 7/16/2022 7:08:49 PM
PropertyNames                        : {AccountExpirationDate, accountExpires, AccountLockoutTime,
                                       AccountNotDelegated...}
AddedProperties                      : {}
RemovedProperties                    : {}
ModifiedProperties                   : {}
PropertyCount                        : 107

The question is, why? Why does [code]Get-ADUser[/code] break from convention like other PowerShell cmdlets and not send all of the available properties to the next command in the pipeline? I think I found the answer in Mike Robbins's PowerShell 101:

This seems like a reasonable assertion for why, and it's an important precedent for PowerShell users to keep in mind: PowerShell cmdlets may not include all available properties by default.

How do you know if the absence of a property you want to access (e.g., the parent process ID in [code]Get-Process[/code]) is available but omitted by default, or if it's not available at all? The only reasonable way to know is to look at the [code]Get-Help[/code] output for a given cmdlet, and see if there is an option for [code]-Properties[/code], and experiment with [code]CMDLETNAME -Properties * | Select-Object -Property *[/code].

In practice, you will rarely need all of the properties from any cmdlet in the pipeline. This brings us to the lesson Blake Regan @crash0ver1d3 tried to tell me a few weeks ago but I wasn't ready to listen yet:

Tweet from Blake Regan reads

For example, if I want to build a CSV file of all domain users that includes the name, SID, password expired (Boolean), and password last set (date) elements, I can run this command:

PS C:\Users\jwright> Get-ADUser -Filter * -Properties * | Select-Object -Property Name, SID, PasswordExpired, PasswordLastSet | ConvertTo-Csv | Out-File userpassset.csv
PS C:\Users\jwright>

However, this creates an unnecessarily large collection of user objects. It might not be noticeable with tens or hundreds of users, but on a domain with hundreds of thousands of users this command will create a lot of unnecessary overhead. Here's a better solution:

PS C:\Users\jwright> Get-ADUser -Filter * -Properties Name, SID, PasswordExpired, PasswordLastSet | Select-Object -Property Name, SID, PasswordExpired, PasswordLastSet | ConvertTo-Csv | Out-File userpassset.csv
PS C:\Users\jwright> Get-Content -first 3 .\userpassset.csv
#TYPE Selected.Microsoft.ActiveDirectory.Management.ADUser
"Name","SID","PasswordExpired","PasswordLastSet"
"jwright","S-1-5-21-1850091285-130397106-3068105436-500","False","7/16/2022 6:42:54 PM"
PS C:\Users\jwright>

It's a little redundant to specify the object properties twice (and don't get me started on the inconsistent use of [code]Get-ADUSer -Properties[/code] and [code]Select-Object -Property[/code]), but it improves performance without a lot of added effort.

If you have other questions about PowerShell things, let me know! Reach out on Twitter (my DMs are open), or email josh@willhackforsushi.com.

Thank you for reading!

-Joshua Wright

Return to Getting Started With PowerShell


Joshua Wright is the author of SANS SEC504: Hacker Tools, Techniques, and Incident Handling, a faculty fellow for the SANS Institute, and a senior technical director at Counter Hack.

Month of PowerShell - The Curious Case of AD User Properties | SANS Institute