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 in the TechNet Script Gallery, 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).

↑ Return to Top


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.

↑ Return to Top


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.

↑ Return to Top


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

↑ Return to Top


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.

↑ Return to Top


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.

↑ Return to Top


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

↑ Return to Top


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.

↑ Return to Top


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

↑ Return to Top


See Also

↑ Return to Top


Other Resources

↑ Return to Top