Private/Initialize/Initialize-DomainStore.ps1

function Initialize-DomainStore {
    <#
        .SYNOPSIS
        Populates the module-level DomainStore with all domains in the forest.
 
        .DESCRIPTION
        Queries the Configuration partition for all crossRef objects representing domain
        partitions and stores their Distinguished Names, NetBIOS names, and DNS names in
        the module-level DomainStore hashtable for fast lookups.
         
        This function should be called once during module initialization to pre-populate
        domain information for the entire forest, avoiding repeated LDAP queries during
        principal resolution.
 
        .INPUTS
        None
        Uses module-level variables $script:Credential and $script:RootDSE.
 
        .OUTPUTS
        None
        Populates the module-level $script:DomainStore hashtable.
 
        .EXAMPLE
        Initialize-DomainStore
        Populates the DomainStore with all domains in the forest.
 
        .NOTES
        Requires $script:Credential and $script:RootDSE to be set before calling.
        The DomainStore is keyed by domain DN (e.g., "DC=contoso,DC=com").
         
        Store structure:
        - Key: Domain Distinguished Name
        - Value: PSCustomObject with distinguishedName, nETBIOSName, dnsRoot, objectSid
    #>

    [CmdletBinding()]
    param()

    #requires -Version 5.1

    begin {
        Write-Verbose "Initializing DomainStore..."
        
        # Initialize Domain Store if it doesn't exist
        if (-not $script:DomainStore) {
            $script:DomainStore = @{}
        }
    }

    process {
        # Require Credential and RootDSE
        if (-not $script:Credential) {
            Write-Warning "Credential not set. Cannot initialize DomainStore."
            return
        }

        if (-not $script:RootDSE) {
            Write-Warning "RootDSE not set. Cannot initialize DomainStore."
            return
        }

        try {
            $configNC = $script:RootDSE.configurationNamingContext.Value
            if ($script:RootDSE.Path -match 'LDAP://([^/]+)') {
                $server = $Matches[1]
                $partitionsPath = "LDAP://$server/CN=Partitions,$configNC"
                
                $partitionsEntry = New-AuthenticatedDirectoryEntry -Path $partitionsPath
                
                $partitionsSearcher = New-Object System.DirectoryServices.DirectorySearcher
                $partitionsSearcher.SearchRoot = $partitionsEntry
                $partitionsSearcher.Filter = "(objectClass=crossRef)"
                $partitionsSearcher.PropertiesToLoad.AddRange(@('nCName', 'nETBIOSName', 'dnsRoot')) | Out-Null
                $partitionsSearcher.SearchScope = [System.DirectoryServices.SearchScope]::OneLevel
                
                # We'll need to query each domain directly for its objectSid
                # as crossRef objects don't contain the domain's SID
                
                $allPartitions = $partitionsSearcher.FindAll()
                
                $domainCount = 0
                foreach ($partition in $allPartitions) {
                    if ($partition.Properties['nCName'].Count -gt 0) {
                        $domainDN = $partition.Properties['nCName'][0]
                        
                        # Create domain store entry with all properties
                        if (-not $script:DomainStore.ContainsKey($domainDN)) {
                            # Query the domain directly for its objectSid
                            $domainSid = $null
                            try {
                                $domainEntry = New-AuthenticatedDirectoryEntry -Path "LDAP://$server/$domainDN"
                                if ($domainEntry.Properties['objectSid'].Count -gt 0) {
                                    $sidBytes = $domainEntry.Properties['objectSid'][0]
                                    $domainSid = (New-Object System.Security.Principal.SecurityIdentifier($sidBytes, 0)).Value
                                }
                                $domainEntry.Dispose()
                            } catch {
                                Write-Warning "Failed to retrieve objectSid for domain ${domainDN}: $_"
                            }
                            
                            $domainObject = [PSCustomObject]@{
                                distinguishedName = $domainDN
                                nETBIOSName = if ($partition.Properties['nETBIOSName'].Count -gt 0) { $partition.Properties['nETBIOSName'][0] } else { $null }
                                dnsRoot = if ($partition.Properties['dnsRoot'].Count -gt 0) { $partition.Properties['dnsRoot'][0] } else { $null }
                                objectSid = $domainSid
                            }
                            
                            $script:DomainStore[$domainDN] = $domainObject
                            Write-Verbose "Stored domain: $domainDN (NetBIOS: $($domainObject.nETBIOSName), DNS: $($domainObject.dnsRoot), SID: $($domainObject.objectSid))"
                            $domainCount++
                        }
                    }
                }
                
                Write-Verbose "DomainStore initialized with $domainCount domain(s)"
                
                $allPartitions.Dispose()
                $partitionsSearcher.Dispose()
                $partitionsEntry.Dispose()
            } else {
                Write-Warning "Could not extract server from RootDSE path: $($script:RootDSE.Path)"
            }
        } catch {
            Write-Warning "Failed to initialize DomainStore: $_"
        }
    }
}