PowerShell Version 2.0 script to find all Active Directory objects with values assigned to linked multi-valued attributes. Only the forward linked attributes are considered. If the values were assigned before the forest functional level was at least Windows Server 2003, these attributes of these objects may not be taking advantage of link value replication (LVR). These values are called "legacy".

Without LVR, any updates require that the entire attribute be replicated. For example, if a group has 1000 members, and you add one more, all 1001 values must be replicated. With LVR, only the updated or new values are replicated.

The script only outputs if there are at least a specified number of values. The variable $Limit specifies this limit. You can adjust this limit to meet your needs.
The output from the script should be redirected to a text file. For each object found, the script outputs the distinguished name of the object, the LDAPDisplayName of the attribute, and the number of values. The script follows:


# FindLegacy.ps1 
# PowerShell Version 2 script to find all Active Directory objects with 
# values assigned to linked multi-valued attributes that are the forward link. 
# The output should be redirected to a text file. These attributes of 
# these objects may not be taking advantage of link value replication (LVR) 
# if the values were assigned before the forest was at  
# Windows Server 2003 Forest functional level or above. 
# Author: Richard L. Mueller 
# Version 1.0 - August 202015 
# Version 2.0 - September 42015 - Search all naming contexts. 
# Specify a limit for the number of values. Only objects with at least 
# this number of values assigned to the attribute will be documented. 
$Limit = 100 
# Retrieve all attributes from the schema that are multi-valued, linked, 
# and are the forward link (linkID is even). 
$SchemaNC = (Get-ADRootDSE).schemaNamingContext 
$NCs = (Get-ADRootDSE).NamingContexts 
$Attrs = Get-ADObject -SearchBase $SchemaNC ` 
    -Filter {(isSingleValued -eq "FALSE") -and (linkID -Like "*")} ` 
    -Properties lDAPDisplayName, linkID | Where {$_.linkID % 2 -eq 0} 
# Enumerate the attributes and find all objects with at least one value for each. 
ForEach ($Attr In $Attrs) 
    $AttrName = $Attr.lDAPDisplayName 
    $ID = $Attr.linkID 
    # Search each naming context. 
    ForEach ($NC In $NCs) 
        $Names = Get-ADObject -SearchBase $NC -LDAPFilter "($AttrName=*)" -Properties $AttrName ` 
            | Select distinguishedName, $AttrName 
        # Enumerate all objects with at least one value for this linked multi-valued attribute. 
        If ($Names) 
            ForEach ($Name In $Names) 
                # Only consider objects where the number of values is equal to or greater 
                # than the specified limit. 
                If ($Name.$AttrName.Count -ge $Limit) 
                    # For each object output the DN, the attribute name, and the number of values. 
                    $Name.distinguishedName + ": " + $AttrName + " (" + $Name.$AttrName.Count + ")" 
The fix to allow the attributes to take advantage of LVR would be to remove the affected values (those added when the forest functional level was Windows 2000) and then add them back. Such values are called "legacy". The repadmin command line tool can be used to determine which values are "legacy", as opposed to "present" (uses LVR) or "absent" (deleted but within the tombstone lifetime). The repadmin command would be similar to:



Windows Shell Script
repadmin /showobjmeta mydc "CN=VBPSGroup,OU=West,DC=MyDomain,DC=com" > report.txt


where "mydc" is the host name of a domain controller and the distinguished name is that of an object identified by the FindLegacy.ps1 script.

The most common attribute to require such remediation is the member attribute of group objects. However, this script considers all forward linked multi-valued attributes of all objects in Active Directory. It is possible for other attributes to have many values and benefit from the suggested fix.

Example output from the script, with $Limit of 5, would be similar to below:


Windows Shell Script
CN=Engineering,OU=West,DC=MyDomain,DC=com: member (502) 
CN=VBPSGroup,OU=West,DC=MyDomain,DC=com: member (1801) 
CN=VBSGroup,OU=West,DC=MyDomain,DC=com: member (1001) 
CN=TestComputers,OU=West,DC=MyDomain,DC=com: member (501) 
CN=TestGroup1,OU=West,DC=MyDomain,DC=com: member (25) 
CN=TestGroup2,OU=West,DC=MyDomain,DC=com: member (72) 
CN=MyDC,OU=Domain Controllers,DC=MyDomain,DC=com: msDS-HostServiceAccount (5