Private/Set-AGEnrollmentServiceAce.ps1

function Set-AGEnrollmentServiceAce {
    <#
    .SYNOPSIS
        Adds access rules to a CA's pKIEnrollmentService directory object.

    .DESCRIPTION
        The ESC5 half of the unpublished chain (issue #30): layers access rules
        onto the DACL of the pKIEnrollmentService object — the directory object
        that holds certificateTemplates — never the CA host or service security
        descriptor. The copied DACL is preserved; rules are added, not replaced.

        Add is idempotent: an identical rule (same trustee, rights, type, and
        object type) already present is skipped, so redeploy never stacks a
        duplicate ACE. Teardown does not surgically remove the grant — it
        byte-restores the CA's pre-change security descriptor captured in the
        state file (see New-AGDeployState), which reverses this wholesale.

    .PARAMETER DistinguishedName
        The distinguished name of the CA's pKIEnrollmentService object.

    .PARAMETER AccessRules
        The ActiveDirectoryAccessRule objects to add.

    .PARAMETER Server
        The domain controller to write to. Defaults to the logon server.

    .EXAMPLE
        $rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $authUsersSid, 'GenericAll', 'Allow', ([guid]::Empty)
        Set-AGEnrollmentServiceAce -DistinguishedName $ca.DistinguishedName -AccessRules $rule
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',
        Justification = 'AD writes gated by the caller scenario deploy collision / -Force contract per module precedent.')]
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$DistinguishedName,

        [Parameter(Mandatory)]
        [ValidateNotNull()]
        [System.DirectoryServices.ActiveDirectoryAccessRule[]]$AccessRules,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$Server
    )

    begin {
        Add-Type -AssemblyName System.DirectoryServices
        $serverPrefix = if ($PSBoundParameters.ContainsKey('Server')) { "LDAP://$Server/" } else { 'LDAP://' }
    }

    process {
        $path = "$serverPrefix$DistinguishedName"
        if (-not [System.DirectoryServices.DirectoryEntry]::Exists($path)) {
            $exception = New-Object System.InvalidOperationException("Enrollment Services object not found at '$path'. No AD changes were made.")
            $errorRecord = New-Object System.Management.Automation.ErrorRecord($exception, 'EnrollmentServiceNotFound', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $DistinguishedName)
            $PSCmdlet.ThrowTerminatingError($errorRecord)
        }

        $entry = New-Object System.DirectoryServices.DirectoryEntry($path)
        $sd = $entry.ObjectSecurity

        $added = 0
        foreach ($rule in $AccessRules) {
            # Dedupe predicate extracted pure (Test-AGAccessRulePresent) so it
            # is unit-testable without a forest.
            if (-not (Test-AGAccessRulePresent -ExistingRules $sd.Access -Rule $rule)) {
                $sd.AddAccessRule($rule)
                $added++
            }
        }

        if ($added -gt 0) {
            $entry.ObjectSecurity = $sd
            $entry.CommitChanges()
            Write-Verbose "Added $added access rule(s) to '$DistinguishedName'."
        } else {
            Write-Verbose "All access rules already present on '$DistinguishedName'; no change."
        }

        $entry.Dispose()
    }
}

function Test-AGAccessRulePresent {
    <#
    .SYNOPSIS
        Returns $true when an identical access rule already exists in a DACL.

    .DESCRIPTION
        Pure predicate matching trustee (SID), rights, access type, and object
        type. Internal seam for Set-AGEnrollmentServiceAce's idempotency,
        unit-testable without a forest.
    #>

    [CmdletBinding()]
    param (
        [Parameter()]
        $ExistingRules,

        [Parameter(Mandatory)]
        [System.DirectoryServices.ActiveDirectoryAccessRule]$Rule
    )

    process {
        foreach ($existing in @($ExistingRules)) {
            if ($existing.IdentityReference.Value -eq $Rule.IdentityReference.Value -and
                $existing.ActiveDirectoryRights -eq $Rule.ActiveDirectoryRights -and
                $existing.AccessControlType -eq $Rule.AccessControlType -and
                "$($existing.ObjectType)" -eq "$($Rule.ObjectType)") {
                return $true
            }
        }
        return $false
    }
}