Private/Set/Set-AnyPurposeEKUExist.ps1

function Set-AnyPurposeEKUExist {
    <#
        .SYNOPSIS
        Adds an AnyPurposeEKUExist property to AD CS certificate template objects.
 
        .DESCRIPTION
        Examines the pKIExtendedKeyUsage attribute of Active Directory Certificate Services
        certificate template objects to determine if they allow any purpose usage.
         
        The function checks for the presence of the Any Purpose Extended Key Usage (EKU) OID:
        - 2.5.29.37.0: Any Purpose (allows certificates to be used for all purposes)
         
        Additionally, if the pKIExtendedKeyUsage attribute is not populated (empty or missing),
        this indicates the template allows all purposes by default, which is functionally
        equivalent to having the Any Purpose EKU explicitly set.
         
        This is a critical check for AD CS auditing, as templates that allow any purpose
        combined with other risky settings can lead to privilege escalation vulnerabilities.
         
        The function adds a boolean AnyPurposeEKUExist property to each input object indicating
        whether the template can be used for any purpose.
 
        .PARAMETER AdcsObject
        One or more DirectoryEntry objects representing AD CS certificate templates.
        These objects may contain the pKIExtendedKeyUsage attribute.
 
        .PARAMETER AnyPurposeEKU
        An array of EKU OIDs that represent any purpose usage.
        Default is '2.5.29.37.0' (Any Purpose).
 
        .INPUTS
        System.DirectoryServices.DirectoryEntry[]
        You can pipe certificate template DirectoryEntry objects to this function.
 
        .OUTPUTS
        System.DirectoryServices.DirectoryEntry[]
        Returns the input objects with an added AnyPurposeEKUExist boolean property.
 
        .EXAMPLE
        $templates = Get-AdcsObject -RootDSE $rootDSE | Where-Object { $_.objectClass -contains 'pKICertificateTemplate' }
        $templates | Set-AnyPurposeEKUExist
        Processes all certificate templates and adds the AnyPurposeEKUExist property to each.
 
        .EXAMPLE
        Get-AdcsObject -RootDSE $rootDSE | Set-AnyPurposeEKUExist | Where-Object AnyPurposeEKUExist
        Retrieves all AD CS objects, adds AnyPurposeEKUExist property, and filters to only any-purpose templates.
 
        .EXAMPLE
        $template = Get-AdcsObject -RootDSE $rootDSE | Where-Object Name -eq 'WebServer'
        $template | Set-AnyPurposeEKUExist
        if ($template.AnyPurposeEKUExist) {
            Write-Host "Template allows any purpose usage"
        }
        Checks a specific template for any purpose capability.
 
        .NOTES
        The Any Purpose EKU (2.5.29.37.0) is a wildcard that permits certificates to be used
        for any purpose including authentication, code signing, encryption, etc.
         
        Templates with empty pKIExtendedKeyUsage are treated as any purpose because AD CS
        interprets missing EKU restrictions as allowing all purposes.
         
        This is considered high-risk when combined with other misconfigurations like allowing
        SAN specification or having weak enrollment permissions.
 
        .LINK
        https://posts.specterops.io/certified-pre-owned-d95910965cd2
         
        .LINK
        https://learn.microsoft.com/en-us/windows/win32/seccrypto/extended-key-usage
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.DirectoryServices.DirectoryEntry[]]$AdcsObject,
        
        [Parameter()]
        [string[]]$AnyPurposeEKU = @(
            '2.5.29.37.0'
        )
    )

    #requires -Version 5.1

    begin {
        Write-Verbose "Identifying templates that create Any Purpose/Certification Authority certificates..."
    }

    process {
        $AdcsObject | Where-Object SchemaClassName -eq pKICertificateTemplate | ForEach-Object {
            try {
                $objectName = if ($_.Properties.displayName.Count -gt 0) {
                    $_.Properties.displayName[0] 
                } elseif ($_.Properties.name.Count -gt 0) {
                    $_.Properties.name[0]
                } else {
                    $_.Properties.distinguishedName[0]
                }
                Write-Verbose "Processing template: $objectName"
                
                $anyPurposeEKUExist = $false
                
                # Check if pKIExtendedKeyUsage attribute exists and has values
                if ($_.Properties.pKIExtendedKeyUsage.Count -gt 0) {
                    $ekuList = $_.Properties.pKIExtendedKeyUsage
                    Write-Verbose "pKIExtendedKeyUsage contains $($ekuList.Count) EKU(s): $($ekuList -join ', ')"
                    
                    # Check if any of the Any Purpose EKUs are present
                    foreach ($eku in $ekuList) {
                        if ($eku -in $AnyPurposeEKU) {
                            $anyPurposeEKUExist = $true
                            Write-Verbose "Any Purpose EKU found: $eku"
                            break  # No need to check remaining EKUs
                        }
                    }
                    
                    if (-not $anyPurposeEKUExist) {
                        Write-Verbose "No Any Purpose EKUs found in template"
                    }
                } else {
                    $anyPurposeEKUExist = $true
                    Write-Verbose "pKIExtendedKeyUsage is empty. Template can be used for Any Purpose."
                }
                
                # Update the AdcsObjectStore with the AnyPurposeEKUExist property
                $dn = $_.Properties.distinguishedName[0]
                if ($script:AdcsObjectStore.ContainsKey($dn)) {
                    $script:AdcsObjectStore[$dn] | Add-Member -NotePropertyName AnyPurposeEKUExist -NotePropertyValue $anyPurposeEKUExist -Force
                    Write-Verbose "Updated AD CS Object Store for $dn with AnyPurposeEKUExist = $anyPurposeEKUExist"
                }
                
                # Also add to the pipeline object for backward compatibility
                $_ | Add-Member -NotePropertyName AnyPurposeEKUExist -NotePropertyValue $anyPurposeEKUExist -Force
                
                # Return the modified object
                $_
                
            } catch {
                $errorRecord = [System.Management.Automation.ErrorRecord]::new(
                    $_.Exception,
                    'AnyPurposeEKUProcessingFailed',
                    [System.Management.Automation.ErrorCategory]::InvalidOperation,
                    $_
                )
                $PSCmdlet.WriteError($errorRecord)
                
                # Still return the object even if processing failed
                $_
            }
        }
    }

    end {
        Write-Verbose "Done identifying templates that create Any Purpose/Certification Authority certificates."
    }
}