PowerShell: Resolve dsHeursitics

This function is handy for resolving dsHeuristics values:

PowerShell
function Resolve-DsHeuristics {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $false, ValueFromPipeline = $true)]
        [ValidatePattern("^[0-9a-f]+$")]
        [string]$Heuristics
    )
    if (-not [string]::IsNullOrEmpty($Heuristics)) {
        $res = @()
        for($pos = 1; $pos -le $Heuristics.Length; $pos++) {
            $char = $Heuristics[($pos - 1)]
            $item = [PSCustomObject]@{
                'Position' = $pos
                'Character' = $char
                'Name' = ''
                'Value' = $false
                'IsValid' = $true
                'IsDefault' = $true
                'Behavior' = ''
                'URI' = ''
                'SupportedOn' = 'all versions'
            }
            $addItem = $true
            switch ($pos) {
                1 {
                    $item.Name = 'fSupFirstLastANR'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.Behavior = 'Ambiguous Name Resolution will not include search by "Firstname Lastname"'
                        $item.IsDefault = $false
                    } else {
                        $item.Behavior = 'Ambiguous Name Resolution will include search by "Firstname Lastname"'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/1a9177f4-0272-4ab8-aa22-3c3eafd39e4b'
                }
                2 {
                    $item.Name = 'fSupLastFirstANR'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.Behavior = 'Ambiguous Name Resolution will not include search by "Lastname Firstname"'
                        $item.IsDefault = $false
                    } else {
                        $item.Behavior = 'Ambiguous Name Resolution will include search by "Lastname Firstname"'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/1a9177f4-0272-4ab8-aa22-3c3eafd39e4b'
                }
                3 {
                    $item.Name = 'fDoListObject'
                    $item.Value = ($char -eq '1')
                    if ($item.Value) {
                        $item.Behavior = 'The "List Object" right will be enforced and children will be hidden if the searcher does not have the DS_LIST_OBJECT right on the parent'
                        $item.IsDefault = $false
                    } else {
                        $item.Behavior = 'The "List Object" right will not be enforced and children willl be shown regardless of the DS_LIST_OBJECT right on the parent'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/990fb975-ab31-4bc1-8b75-5da132cd4584'
                }
                4 {
                    $item.Name = 'fDoNickRes'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.Behavior = 'Ambiguous Name Resolution request via MAPI will attempt an exact match against the MAPI nickname'
                        $item.IsDefault = $false
                    } else {
                        $item.Behavior = 'MAPI nickname will not be matched by Ambiguous Name Resolution'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/1a9177f4-0272-4ab8-aa22-3c3eafd39e4b'
                }
                5 {
                    $item.Name = 'fLDAPUsePermMod'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.Behavior = 'LDAP will use the LDAP_SERVER_PERMISSIVE_MODIFY control (return success even if no modification is performed)'
                        $item.IsDefault = $false
                    } else {
                        $item.Behavior = 'LDAP will use strict modification behavior and return an error if no modifications are to be performed, like deleting an attribute that is not present.'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/49cdb1e3-3baa-4c7c-8cde-7c26b13d3ba7'
                }
                6 {
                    $item.Name = 'ulHideDSID'
                    switch ($char) {
                        '0' {
                            $item.Value = 0
                            $item.Behavior = 'DSID will always be returned'
                        }
                        '1' {
                            $item.Value = 1
                            $item.IsDefault = $false
                            $item.Behavior = 'DSID will only be returned if it does not reveal the identity of the object otherwise invisible to the client'
                        }
                        default {
                            $item.Value = -1
                            $item.IsDefault = $false
                            $item.Behavior = 'DSID will NOT be returned'
                        }
                    }
                }
                7 {
                    $item.Name = 'fLDAPBlockAnonOps'
                    $item.Value = ($char -ne '2')
                    if ($item.Value) {
                        $item.Behavior = 'LDAP will only allow searching RootDSE anonymously, regardless of ACL'
                    } else {
                        $item.IsDefault = $false
                        $item.Behavior = 'LDAP will allow anonymous searches if the ACLs permit them'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/4e11a7e6-e18c-46e4-a781-3ca2b4de6f30'
                    $item.SupportedOn = 'DC FL 2003 and newer'
                }
                8 {
                    $item.Name = 'fAllowAnonNSPI'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'Allow anonymous NSPI (RPC) calls'
                    } else {
                        $item.Behavior = 'Reject anonymous NSPI (RPC) calls'
                    }
                }
                9 {
                    $item.Name = 'fUserPwdSupport'
                    $item.Value = ($char -notin ('0','2'))
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'Disable access to userPassword attribute, regardless of permissions'
                    } else {
                        $item.Behavior = 'Allow access to userPassword attribute, ACLs permitting'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/4e11a7e6-e18c-46e4-a781-3ca2b4de6f30'
                }
                10 {
                    $item.Name = 'tenthChar'
                    $item.Value = ($char -eq '1')
                    if ($item.Value) {
                        $item.Behavior = 'If heuristics beyond the 9th char are to be set, the 10th char must have a value of 1'
                    } else {
                        $item.IsDefault = $false
                        $item.IsValid = $false
                        $item.Behavior = 'If 10th char is anything else than 1, the server should reject the update!'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/76df255d-dc67-4c1f-adc6-1e5b60021304'
                }
                11 {
                    $item.Name = 'fSpecifyGUIDOnAdd'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'On adding an object, specifying its GUID is allowed'
                    } else {
                        $item.Behavior = 'Specifying GUIDs is not allowed for add operations'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/7dfeb38c-3cb9-4215-ae1c-ef209fd251ae'
                }
                12 {
                    $item.Name = 'fDontStandardizeSDs'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'The order of ACEs supplied by the client is preserved'
                    } else {
                        $item.Behavior = 'ACEs are sorted according to the ordering rules'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/081c41f0-4c8d-4ab0-971d-77ec2504375a'
                }
                13 {
                    $item.Name = 'fAllowPasswordOperationsOverNonSecureConnection'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'Password operations are allowed without encryption (valid for ADLDS only!)'
                    } else {
                        $item.Behavior = 'Password operations require encryption (valid for ADLDS only!)'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/6e803168-f140-4d23-b2d3-c3a8ab5917d2'
                }
                14 {
                    $item.Name = 'fDontPropagateOnNoChangeUpdate'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'ntSecurityDescriptor is propagated to descendant objects on change, even if the new value is bitwise identical to the old one'
                    } else {
                        $item.Behavior = 'Changes in ntSecurityDescriptor where the old and the new value are bitwise identical, do not trigger propagation'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/b645c125-a7da-4097-84a1-2fa7cea07714#gt_b581857f-39aa-4979-876b-daba67a40f15'
                    $item.SupportedOn = 'Windows Server 2008 and newer'
                }
                15 {
                    $item.Name = 'fComputeANRStats'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'ANR searches are optimized using cardianlity estimates'
                    } else {
                        $item.Behavior = 'ANR searches are not optimized using cardinality from previous searches'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/1a9177f4-0272-4ab8-aa22-3c3eafd39e4b'
                }
                16 {
                    $item.Name = 'dwAdminSDExMask'
                    $item.Value = @()
                    $mask = "0x$char" -as [int]
                    if (($mask -band 1) -gt 0) { $item.Value += 'ACCOUNT_OPS' }
                    if (($mask -band 2) -gt 0) { $item.Value += 'SYSTEM_OPS' }
                    if (($mask -band 4) -gt 0) { $item.Value += 'PRINT_OPS' }
                    if (($mask -band 8) -gt 0) { $item.Value += 'BACKUP_OPS' }
                    if ($item.Value.Count -gt 0) {
                        $item.IsDefault = $false
                        $item.Behavior = ('The following groups will be excluded aus SDPROP: {0}' -f ($item.Value -join ','))
                    } else {
                        $item.Behavior = 'All privileged groups are included in SDPROP'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/dd3d29f3-8e1e-4e8c-a210-9eaef3abd628'
                }
                17 {
                    $item.Name = 'fKVNOEmuW2K'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'msDS-KeyVersionNumber will always equal 1 (W2K emulation)'
                    } else {
                        $item.Behavior = 'msDS-KeyVersionNumber will be read from object'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/cb85ccdf-6469-42d5-a61c-ebae09b72e9d'
                }
                18 {
                    $item.Name = 'fLDAPBypassUpperBoundsOnLimits'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'DCs will bypass implementation-dependent limits on LDAP policies'
                    } else {
                        $item.Behavior = 'DCs will respect implementation-dependent limits on LDAP policies'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/3f0137a1-63df-400c-bf97-e1040f055a99'
                    $item.SupportedOn = 'Windows Server 2008 and newer'
                }
                19 {
                    $item.Name = 'fDisableAutoIndexingOnSchemaUpdate'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'Index creation is triggered by index-related changes to the searchFlags attribute'
                    } else {
                        $item.Behavior = 'Index creation can be delayed upon detection of index-related changes to the searchFlags attribute until either an administrator issues the schemaUpdateNow rootDSE modify operation, the DC is rebooted, or an implementation-dependent time period has elapsed'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/3f0137a1-63df-400c-bf97-e1040f055a99'
                    $item.SupportedOn = 'Windows Server 2012 and newer'
                }
                20 {
                    $item.Name = 'twentiethChar'
                    $item.Value = ($char -eq '2')
                    if ($item.Value) {
                        $item.Behavior = 'If heuristics beyond the 19th char are to be set, the 20th char must have a value of 2'
                    } else {
                        $item.IsDefault = $false
                        $item.IsValid = $false
                        $item.Behavior = 'If 20th char is anything else than 2, the server should reject the update!'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/76df255d-dc67-4c1f-adc6-1e5b60021304'
                }
                21 {
                    $item.Name = 'DoNotVerifyUPNAndOrSPNUniqueness'
                    $item.Value = @()
                    $mask = "0x$char" -as [int]
                    if (($mask -band 1) -eq 0) { $item.Value += 'UPN' }
                    if (($mask -band 2) -eq 0) { $item.Value += 'SPN' }
                    if (($mask -band 4) -eq 0) { $item.Value += 'SPN alias' }
                    if ($item.Value.Count -gt 0) {
                        $item.IsDefault = $false
                        $item.Behavior = ('The following uniqueness consraints will not be checked prior to submitting the change: {0}' -f $item.Value -join ',')
                    } else {
                        $item.Behavior = 'All uniqueness constraints will be checked before submitting'
                    }
                    
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/3c154285-454c-4353-9a99-fb586e806944'
                    $item.SupportedOn = 'Windows Server 2012R2 and newer'
                }
                22 {
                    if ($pos -lt $Heuristics.Length) {
                        $char = ('0x{0}{1}' -f $Heuristics[$pos -1], $Heuristics[$pos])
                        $item.Character = ('{0}{1}' -f $Heuristics[$pos -1], $Heuristics[$pos])
                        $item.Value = $char
                        $minver = $char -as [int]
                        $item.Name = 'MinimumGetChangesRequestVersion'
                        if ($minver -eq 0) {
                            $item.Behavior = 'No restrictions on GETCHGREQ version will be imposed'
                        } else {
                            $item.IsDefault = $false
                            $item.Behavior = ('GETCHGREQ must have the minimum version of {0}' -f $minver)
                        }
                        $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/20ddf6d7-ac4e-4e16-8910-fbeca8f6e980'
                    } else {
                        $item.Name = '<MISSING DATA - position 23 must be set as well!>'
                        $item.IsValid = $false
                        $item.IsDefault = $false
                    }
                }
                23 {
                    Write-Verbose "Skipping byte 23 since it's paired with 22!"
                    $addItem = $false
                }
                24 {
                    if ($pos -lt $Heuristics.Length) {
                        $char = ('0x{0}{1}' -f $Heuristics[$pos -1], $Heuristics[$pos])
                        $item.Character = ('{0}{1}' -f $Heuristics[$pos -1], $Heuristics[$pos])
                        $item.Value = $char
                        $minver = $char -as [int]
                        $item.Name = 'MinimumGetChangesReplyVersion'
                        if ($minver -eq 0) {
                            $item.Behavior = 'No restrictions on GETCHGREPLY version will be imposed'
                        } else {
                            $item.IsDefault = $false
                            $item.Behavior = ('GETCHGREPLY must have the minimum version of {0}' -f $minver)
                        }
                        $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/20ddf6d7-ac4e-4e16-8910-fbeca8f6e980'
                    } else {
                        $item.Name = '<MISSING DATA - position 25 must be set as well!>'
                        $item.IsValid = $false
                        $item.IsDefault = $false
                    }
                }
                25 {
                    Write-Verbose "Skipping byte 25 since it's paired with 24!"
                    $addItem = $false
                }
                26 {
                    $item.Name = 'fLoadV1AddressBooksOnlySetting'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'MAPI address book is calculated using V1 attributes'
                    } else {
                        $item.Behavior = 'MAPI address book is calculated using V2 attributes'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/3f0137a1-63df-400c-bf97-e1040f055a99'
                    $item.SupportedOn = 'Windows Client/Server 1903 and newer'
                }
                27 {
                    $item.Name = 'fTreatTokenGroupsAsLDAPTransitiveAttribute'
                    $item.Value = ($char -ne '0')
                    if ($item.Value) {
                        $item.IsDefault = $false
                        $item.Behavior = 'LDAP Policy "MaxValueRangeTransitive" is respected for token groups'
                    } else {
                        $item.Behavior = 'LDAP Policy "MaxValueRange" is respected for token groups'
                    }
                    $item.URI = 'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/01002598-92db-4c59-822e-b22f53168c90'
                    $item.SupportedOn = 'Windows Client/Server 1903 and newer'
                }
                28 {
                    $item.Name = 'AttributeAuthorizationOnLDAPAdd'
                    $enforcementDateHasPassed = ((Get-Date) -gt (Get-Date -Year 2023 -Month 4 -Day 11))
                    switch ($char) {
                        "0" { 
                            $item.Value = 0 
                            $item.Behavior = 'KB5008383 LDAP Add AuthZ verification disabled (not supported after 2023-04-11)'
                            $item.IsValid = (-not $enforcementDateHasPassed)
                            $item.IsDefault = (-not $enforcementDateHasPassed)
                        }
                        "2" { 
                            $item.IsDefault = $false
                            $item.Value = 2
                            $item.Behavior = 'KB5008383 LDAP Add AuthZ enforcement mode disabled, updated auditing disabled'
                        }
                        default { 
                            $item.Value = 1 
                            $item.IsDefault = $enforcementDateHasPassed
                            $item.Behavior = 'KB5008383 LDAP Add AuthZ enforcement mode'
                        }
                    }
                    $item.URI = 'https://support.microsoft.com/en-us/topic/kb5008383-active-directory-permissions-updates-cve-2021-42291-536d5555-ffba-4248-a60e-d6cbc849cde1'
                    $item.SupportedOn = 'Windows Server 2008R2 and higher'
                }
                29 {
                    $item.Name = 'BlockOwnerImplicitRights'
                    $enforcementDateHasPassed = ((Get-Date) -gt (Get-Date -Year 2023 -Month 4 -Day 11))
                    switch ($char) {
                        "0" { 
                            $item.Value = 0 
                            $item.Behavior = 'KB5008383 Owner Implicit Rights Audit enabled'
                            $item.IsDefault = (-not $enforcementDateHasPassed)
                        }
                        "2" { 
                            $item.IsDefault = $false
                            $item.Value = 2
                            $item.Behavior = 'KB5008383 Owner Implicit Rights enforcement mode disabled'
                        }
                        default { 
                            $item.Value = 1 
                            $item.IsDefault = $enforcementDateHasPassed
                            $item.Behavior = 'KB5008383 Owner Implicit Rights enforcement mode'
                        }
                    }
                    $item.URI = 'https://support.microsoft.com/en-us/topic/kb5008383-active-directory-permissions-updates-cve-2021-42291-536d5555-ffba-4248-a60e-d6cbc849cde1'
                    $item.SupportedOn = 'Windows Server 2008R2 and higher'
                }
                default {
                    $item.Value = $null
                    $item.IsValid = $false
                    $item.IsDefault = $false
                    $item.Behavior = 'This position in the dsHeuristics string has not yet been assigned'
                }
            }
            if ($addItem) {
                $res += $item
            }
        }
        return $res
    }
}