Private/Set/Set-CAInterfaceFlags.ps1

function Set-CAInterfaceFlags {
    <#
        .SYNOPSIS
        Adds InterfaceFlags configuration properties to AD CS Certification Authority objects.

        .DESCRIPTION
        For each pKIEnrollmentService (CA) object, queries the CA's InterfaceFlags registry
        configuration using PSCertutil's Get-PSCInterfaceFlag cmdlet and stores the results
        in the AdcsObjectStore.
        
        This function tracks various interface flags that control CA RPC/DCOM behavior,
        including the IF_ENFORCEENCRYPTICERTREQUEST flag which when disabled leads to
        the ESC11 vulnerability (allowing unauthenticated/unencrypted certificate requests).
        
        The function adds these properties to each CA object:
        - InterfaceFlags: Array of all InterfaceFlag objects returned by Get-PSCInterfaceFlag
        - RPCEncryptionNotRequired: Boolean indicating if IF_ENFORCEENCRYPTICERTREQUEST is disabled (ESC11)

        .PARAMETER AdcsObject
        One or more DirectoryEntry objects representing AD CS Certification Authorities.
        Must have the CAFullName property set (typically by Set-CAComputerPrincipal).

        .INPUTS
        System.DirectoryServices.DirectoryEntry[]
        You can pipe CA DirectoryEntry objects to this function.

        .OUTPUTS
        System.DirectoryServices.DirectoryEntry[]
        Returns the input objects with added InterfaceFlags properties.

        .EXAMPLE
        $cas | Set-CAInterfaceFlags
        Queries InterfaceFlags for all CAs and stores the results.

        .EXAMPLE
        $cas | Set-CAComputerPrincipal | Set-CAInterfaceFlags
        Sets up CA identification and then queries InterfaceFlags.

        .NOTES
        Requires the PSCertutil module to be installed and loaded.
        This function must be called after Set-CAComputerPrincipal has set the CAFullName property.
        
        The function silently skips CAs that:
        - Don't have a CAFullName property
        - Are unreachable or don't respond to certutil queries
        - Return errors from Get-PSCInterfaceFlag

        .LINK
        https://posts.specterops.io/certified-pre-owned-d95910965cd2
    #>

    [CmdletBinding()]
    [OutputType([LS2AdcsObject[]])]
    param (
        [Parameter(Mandatory, ValueFromPipeline)]
        [LS2AdcsObject[]]$AdcsObject
    )

    #requires -Version 5.1

    begin {
        Write-Verbose "Querying InterfaceFlags for Certification Authorities..."
    }

    process {
        $AdcsObject | Where-Object { $_.IsCertificationAuthority() } | ForEach-Object {
            try {
                $caName = $_.cn
                Write-Verbose "Processing CA: $caName"
                
                # Get CAFullName directly from the LS2AdcsObject (ScriptProperty)
                $caFullName = $_.CAFullName
                
                if (-not $caFullName) {
                    Write-Verbose " CA '$caName' has no CAFullName property - skipping InterfaceFlags query"
                    $_
                    continue
                }
                
                Write-Verbose " Querying InterfaceFlags for: $caFullName"
                
                try {
                    # Query InterfaceFlags using PSCertutil
                    $interfaceFlags = Get-PSCInterfaceFlag -CAFullName $caFullName -ErrorAction Stop
                    
                    if ($interfaceFlags) {
                        Write-Verbose " Retrieved $(@($interfaceFlags).Count) InterfaceFlags"
                        
                        # Check specifically for IF_ENFORCEENCRYPTICERTREQUEST
                        $encryptionFlag = $interfaceFlags | Where-Object { $_.InterfaceFlag.ToString() -eq 'IF_ENFORCEENCRYPTICERTREQUEST' }
                        $rpcEncryptionNotRequired = if ($encryptionFlag) { -not $encryptionFlag.Enabled } else { $true }
                        
                        Write-Verbose " IF_ENFORCEENCRYPTICERTREQUEST is $(if ($rpcEncryptionNotRequired) { 'disabled or missing - RPC encryption not required' } else { 'enabled - RPC encryption required' })"
                        
                        # Set properties directly on the LS2AdcsObject (same reference as store)
                        $_.InterfaceFlags = $interfaceFlags
                        $_.RPCEncryptionNotRequired = $rpcEncryptionNotRequired
                        Write-Verbose " Updated $($_.distinguishedName) with InterfaceFlags data"
                        
                    } else {
                        Write-Verbose " No InterfaceFlags returned from Get-PSCInterfaceFlag"
                    }
                    
                } catch {
                    Write-Verbose " Failed to query InterfaceFlags for '$caFullName': $($_.Exception.Message)"
                    # Continue processing other CAs
                }
                
                # Return the modified object
                $_
                
            } catch {
                $errorRecord = [System.Management.Automation.ErrorRecord]::new(
                    $_.Exception,
                    'InterfaceFlagQueryFailed',
                    [System.Management.Automation.ErrorCategory]::InvalidOperation,
                    $_
                )
                $PSCmdlet.WriteError($errorRecord)
                
                # Still return the object even if processing failed
                $_
            }
        }
    }

    end {
        Write-Verbose "Done querying InterfaceFlags for Certification Authorities."
    }
}