Active Directory: Document all Attributes of Specified Active Directory Object
Introduction
This article describes a PowerShell script to document all attributes of a specified Active Directory object. The script documents each attribute lDAPDisplayName, the syntax, if it is multi-valued, if it is operational (also called constructed), and the value or values assigned. If the attribute has no value assigned for the object, this is indicated. The script is linked here.
Document all Attributes of Specified Active Directory Object
Issues Retrieving Attributes
Several people have requested scripts that document the attributes assigned to Active Directory objects. The objects could be users, computers, groups, site links, etc. This is not a common request, but when someone wants to document all attributes, whether or not they have values, it is hard to find a solution. Most scripts either document only specified attributes, or at best only the attributes that have been assigned values. For example, the PowerShell script below only retrieves default attributes exposed by the cmdlet, plus those that have values assigned to the specified user.
Get-ADUser -Identity "jsmith" -Properties *
The solution would be to specify the attributes desired with the -Properties parameter. But this is not feasible if the list is large.
Only 10 properties are retrieved by Get-ADUser by default. These include SamAccountName, GivenName, Surname, and Name. See the link in the "See Also" section below that explains and documents the default properties exposed by the AD module cmdlets.
The following script retrieves all users in the domain. But it only retrieves the attributes in the default set, plus those where the first user retrieved by the cmdlet has values assigned. For example, if the first user in the results has no title assigned, then this attribute is not retrieved for any of the users, even if they have a title in AD.
Get-ADUser -Filter * -Properties *
Using the DirectorySearcher object results in a similar problem. The following script only retrieves attributes where the specified user has values assigned.
$Filter = "(sAMAccountName=jsmith)"
$Domain = New-Object System.DirectoryServices.DirectoryEntry
$Searcher = New-Object System.DirectoryServices.DirectorySearcher
$Searcher.SearchRoot = $Domain
$Searcher.Filter = $Filter
$Searcher.PropertiesToLoad.Add(*) > $Null
$Results = $Searcher.FindOne()
$Properties = $Results.Properties
$PropNames = $Properties.PropertyNames
ForEach ($PropName in $PropNames)
{
$PropName
}
The results are the same if you remove the PropertiesToLoad statement.
The best way to retrieve the names of all attributes appropriate for the object is to query the Schema partition for the mandatory and optional attributes for the object class. The following script uses the MandatoryProperties and OptionalProperties methods to retrieve the attribute names. The script also retrieves the syntax of each attribute, which will assist later in retrieving any value assigned to the attribute.
# Bind to the Active Directory object specified.
$ObjectDN = "cn=Jim Smith,ou=Sales,ou=West,dc=Domain,dc=com"
$ADObject = [ADSI]"LDAP://$ObjectDN"
# Determine the object class.
$Schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
$Class = $ADObject.objectClass.ToString().Split(" ")[-1]
# Retrieve attributes for this class from the Schema.
$ManAttributes = $Schema.FindClass("$Class").MandatoryProperties | Out-GridView
$OptAttributes = $Schema.FindClass("$Class").OptionalProperties | Out-GridView
ForEach ($Attribute In $ManAttributes)
{
$AttrName = $Attribute.Name
$AttrSyntax = $Attribute.Syntax
"Mandatory attribute: $AttrName ($AttrSyntax)"
}
ForEach ($Attribute In $OptAttributes)
{
$AttrName = $Attribute.Name
$AttrSyntax = $Attribute.Syntax
"Optional attribute: $AttrName ($AttrSyntax)"
}
The Name property exposed by the MandatoryProperties and OptionalProperties methods is actually the lDAPDisplayName of the attribute, not the Relative Distinguished Name (RDN).
Other Properties of the Attributes
In addition to the lDAPDisplayName and syntax, it is useful to know if the attribute is multi-valued or operational. Each property object in the mandatory and optional collections retrieved above has the IsSingleValued property. This Boolean is True if the attribute is single-valued, and False if it is multi-valued. To determine if the attribute is operational (also called constructed), the script must retrieve the systemFlags attribute of the attribute object in the Schema. If bit 4 of systemFlags is set, the attribute is operational. This means that the value of the attribute is not actually saved in the Active Directory database. The value is constructed by the domain controller on request. In many cases special techniques are required to prompt the domain controller to construct the value. Fortunately, the DirectorySearcher interface prompts the DC in all cases but one. The one exception is multi-valued operational attributes with Sid syntax. The most common example is the tokenGroups attribute of users. Special code is used in the script for these attributes, employing the RefreshCache method to prompt the DC to calculate the value. Even then, the value is a byte array that should be converted into the familiar SID string format. In addition, the NameTranslate interface is used to convert the SID into the sAMAccountName of the object.
Retrieving Attribute Values
Many complications arise when scripting to retrieve the values of attributes identified in the mandatory and optional properties collection. Fortunately, the script described in this article can retrieve the syntax. String attributes, such as those with syntax DirectoryString, are easy. But others can be a challenge. For example, attributes with syntax "Int64" (also called LargeInteger or Integer8) can be dates, timespans, or large integers. Timespans are in 100-nanosecond intervals (called ticks). Dates are represented as the number of ticks since 12:00 am January 1 of the year 1601, in Coordinated Universal Time (UTC). The .NET Framework has methods that allow a script to convert the ticks into timespans or dates in the time zone of the local computer. But logic is needed to determine which conversion to use. Otherwise the script would need to hard-code the name of every "Int64" attribute.
Attributes with syntax Byte[], which are byte arrays, are another challenge. Some are GUID values, some are SIDs. And some are special attributes, like the logonHours attribute of users, or the schedule attribute of connection objects.
If the attribute has no value assigned for the specified object in AD, the script described in this Wiki displays the value as "<not set>". For multi-valued attributes, each value is displayed on a separate line.
Hard-coding all attribute names in a script is not feasible. There are almost 1,500 attributes in the schema. Over 350 apply to user objects alone. And this does not count attributes added to the schema when applications like Exchange extend the schema. Plus, organizations can extend the schema to add their own custom attributes. The script described in this article queries the schema for all of the attributes appropriate for the class of the specified object.
String Attributes
String attribute values require no conversion to be understood. Strings include the following values for the Syntax property exposed by the MandatoryProperties and OptionalProperties methods of class objects in the schema.
- Oid
- NumericString
- PrintableString
- CaseIgnoreString
- IA5String
- GeneralizedTime
- DirectoryString
- DN
32-bit Integer Attributes
32-bit Integer attribute values can also be displayed without conversion. But it helps to display larger integers with culture-specific thousands separators (either the comma or the period). Also, some 32-bit integer attributes are "flag" attributes, described later.
DNWithBinary Syntax
Some AD attributes have syntax DNWithBinary. They combine a string distinguished name with a byte array representing a GUID value. An example is the wellKnownObjects attribute of domain objects. The script must separate the two parts and convert the byte array into the common GUID string format.
Special Attributes
The following attributes or syntaxes require special code to convert the values into a user friendly format.
- 64-bit syntax (LargeInteger) representing large integers (such as maxStorage)
- 64-bit syntax (LargeInteger) representing timespans (such as maxPwdAge)
- 64-bit syntax (LargeInteger) representing datetimes (such as pwdLastSet)
- Byte arrays representing GUIDs (such as objectGUID)
- Byte arrays representing SIDs (such as objectSID)
- The logonHours attribute (byte array)
- The schedule attribute (byte array)
- Multi-valued Sid attributes that are operational (such as tokenGroups)
The schedule attribute of connection objects specifies when replication between replication partners is allowed. Each byte of the array represents an hour in the week. Code is required to display the schedule in a format that can be understood. The logonHours attribute is similar, except that each bit of the byte array represents an hour in the week.
The following attributes are "flag" attributes. These are 32-bit enumerations, where each bit represents a setting. Functions are used to test each bit of the integer. Each bit that is set is converted into a setting string, such as "AccountDisabled". All of the settings in the attribute are concatenated into one string.
- userAccountControl
- msDS-User-Account-Control-Constructed
- groupType
- searchFlags
- systemFlags
- sAMAccountType
- instanceType
How to Run the Script
The script is designed to be run at a PowerShell prompt. It requires the distinguished name of an Active Directory object. Either pass the distinguished name enclosed in quotes on the command line, or the script will prompt for the DN. The output can be quite large, so it is best to redirect the output to a text file. Any errors are displayed in the shell, but are not redirected to the text file.
An example to retrieve all attributes of a user object would be as follows.
You can also have the script prompt for the distinguished name, as in this image.
The resulting output file is the same in both cases. Note that the distinguished name must not be quoted when the script prompts for the DN.
Script Output
The script output will be similar to the below text file. The file has hundreds of lines, so most have been deleted. This is just a representative sample of the attributes documented.
Object DN: cn=Jim M. Smith,OU=West,dc=Domain,dc=com
Object class: user
Mandatory Attributes (7)
cn (DirectoryString): Jim M. Smith
instanceType (Int): 4 (Writeable)
nTSecurityDescriptor (SecurityDescriptor) <1628 bytes>
objectCategory (DN): CN=Person,CN=Schema,CN=Configuration,DC=domain,DC=com
objectClass (Oid[]): top
objectClass (Oid[]): person
objectClass (Oid[]): organizationalPerson
objectClass (Oid[]): user
objectSid (Sid): S-1-5-21-73586283-152049171-839522115-1111
sAMAccountName (DirectoryString): jmsmith
Optional Attributes (345)
accountExpires (Int64): 0
accountNameHistory (DirectoryString[]):
...
badPasswordTime (Int64): 131,667,445,573,010,800 (03/28/2018 15:02:37)
c (DirectoryString): US
canonicalName (DirectoryString[] ): Domain.com/West/Jim M. Smith
co (DirectoryString): UNITED STATES
company (DirectoryString): Hilltop Lab, LLC
department (DirectoryString): IT Department (Hilltop)
directReports (DN[]): CN=Ed French,OU=Music,OU=West,DC=domain,DC=com
directReports (DN[]): CN=Johnson\, Will,OU=Staff,OU=West,DC=domain,DC=com
directReports (DN[]): CN=Frank Kappa,OU=Staff,OU=West,DC=domain,DC=com
displayName (DirectoryString): Jim M. Smith
displayNamePrintable (PrintableString): J. M. Smith
distinguishedName (DN): CN=Jim M. Smith,OU=West,DC=Domain,DC=com
lastLogon (Int64): 131,685,652,573,660,064 (04/18/2018 17:47:37)
lastLogonTimestamp (Int64): 131,703,541,183,044,096 (05/09/2018 10:41:58)
logonCount (Int): 731
logonHours (OctetString): 11111111-11111111-11111111
11111111-11111111-11111111
11111111-11111111-11111111
11111111-11111111-11111111
11111111-11111111-11111111
11111111-11111111-11111111
11111111-11111111-11111111
memberOf (DN[]): CN=AllShadow,OU=West,DC=domain,DC=com
memberOf (DN[]): CN=PLTestGrp,OU=West,DC=domain,DC=com
memberOf (DN[]): CN=West Sales,OU=West,DC=domain,DC=com
memberOf (DN[]): CN=Accounting,OU=West,DC=domain,DC=com
modifyTimeStamp (GeneralizedTime ): 06/25/2018 16:18:48
msDS-User-Account-Control-Computed (Int ): 8388608 (PwdExpired)
objectGUID (OctetString): {10359463-4361-4b8f-8266-2379f7c4408e}
proxyAddresses (DirectoryString[]): SMTP:jmsmith@ameritech.net
pwdLastSet (Int64): 131,667,447,636,878,496 (03/28/2018 15:06:03)
sAMAccountType (Int): 805306368 (UserAccount)
tokenGroups (Sid[] ): S-1-5-32-545 (Users)
tokenGroups (Sid[] ): S-1-5-21-73586283-152049171-839522115-1130 (West Sales)
tokenGroups (Sid[] ): S-1-5-21-73586283-152049171-839522115-1117 (Accounting)
tokenGroups (Sid[] ): S-1-5-21-73586283-152049171-839522115-513 (Domain Users)
tokenGroups (Sid[] ): S-1-5-21-73586283-152049171-839522115-1614 (PLTestGrp)
tokenGroups (Sid[] ): S-1-5-21-73586283-152049171-839522115-4500 (AllShadow)
userAccountControl (Int): 512 (NormalAccount)
userWorkstations (DirectoryString): Virginia,Oregon,Maine
uSNChanged (Int64): 5,196,272
uSNCreated (Int64): 8,356
whenChanged (GeneralizedTime): 06/25/2018 16:18:48
whenCreated (GeneralizedTime): 07/04/2015 12:16:22
See Also
- Wiki: Active Directory Domain Services (AD DS) Portal
- Active Directory: Glossary
- Active Directory: Document Connection Object Schedules
- PowerShell Script to Search Active Directory
- Active Directory: Syntaxes of Attributes
- Active Directory: PowerShell AD Module Properties (explains default properties)
Other Resources
- Document all Attributes of Specified Active Directory Object (Script described in this Wiki)
- Document Replication Schedule of Active Directory Connection Object (PowerShell script)
- Generic Search of Active Directory (PowerShell script)
- Extract arbitrary list of properties from AD user objects (Gallery script)
- List All the Attributes of the User Class (Gallery VBScript)
- PowerShell script to check group membership (PowerShell script, retrieve tokenGroups attribute)
- Document lastLogon and logonCount for a Specified User on All DCs (PowerShell script, convert LastLogon attribute)