Private/Set/Set-CAAuditFilter.ps1

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

        .DESCRIPTION
        For each pKIEnrollmentService (CA) object, queries the CA's AuditFilter registry
        configuration using PSCertutil's Get-PSCAuditFilter cmdlet and stores the results
        in the AdcsObjectStore.
        
        This function tracks the AuditFilter registry value which controls what events
        are audited by the Certificate Authority. Insufficient auditing can make it
        difficult to detect and respond to attacks.
        
        The function adds this property to each CA object:
        - AuditFilter: Integer value representing the audit bitmask

        .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 AuditFilter property.

        .EXAMPLE
        $cas | Set-CAAuditFilter
        Queries AuditFilter for all CAs and stores the results.

        .EXAMPLE
        $cas | Set-CAComputerPrincipal | Set-CAAuditFilter
        Sets up CA identification and then queries AuditFilter.

        .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-PSCAuditFilter

        .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 AuditFilter 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)
                $dn = $_.distinguishedName
                $caFullName = $_.CAFullName
                
                if (-not $caFullName) {
                    Write-Verbose " CA '$caName' has no CAFullName property - skipping AuditFilter query"
                    $_
                    continue
                }
                
                Write-Verbose " Querying AuditFilter for: $caFullName"
                
                try {
                    # Query AuditFilter using PSCertutil
                    $auditFilterResult = Get-PSCAuditFilter -CAFullName $caFullName -ErrorAction Stop
                    
                    if ($auditFilterResult -and $null -ne $auditFilterResult.AuditFilter) {
                        $auditFilter = $auditFilterResult.AuditFilter
                        Write-Verbose " Retrieved AuditFilter: $auditFilter"
                        
                        # Set the property directly on the LS2AdcsObject (same reference as store)
                        $_.AuditFilter = $auditFilter
                        Write-Verbose " Updated $($_.distinguishedName) with AuditFilter data"
                        
                    } else {
                        Write-Verbose " No AuditFilter returned from Get-PSCAuditFilter"
                    }
                } catch {
                    Write-Verbose " Failed to query AuditFilter for '$caFullName': $($_.Exception.Message)"
                }
            } catch {
                Write-Warning "Error processing CA: $($_.Exception.Message)"
            }
            
            # Always return the object to continue the pipeline
            $_
        }
    }

    end {
        Write-Verbose "Completed AuditFilter queries for all CAs"
    }
}