Private/Disable-Template.ps1

function Disable-Template {
    <#
        .SYNOPSIS
        Disables certificate templates for enrollment by removing them from Certificate Authority configurations.
 
        .DESCRIPTION
        This function takes one or more certificate template DirectoryEntry objects and disables them for enrollment
        by removing their names from the certificateTemplates attribute on all Certificate Authorities
        in the current forest. This prevents clients from requesting certificates based on these templates.
 
        The function uses DirectoryEntry objects to modify the CA configurations without requiring
        the ActiveDirectory PowerShell module.
 
        .PARAMETER Template
        One or more certificate template DirectoryEntry objects to disable for enrollment.
        These should be DirectoryEntry objects representing pKICertificateTemplate objects
        from Active Directory.
 
        .PARAMETER CertificateAuthority
        Optional. Specific Certificate Authority objects to modify. If not provided, the function
        will discover and modify all CAs in the current forest.
 
        .PARAMETER WhatIf
        Shows what changes would be made without actually performing them.
 
        .INPUTS
        System.DirectoryServices.DirectoryEntry[]
        Certificate template DirectoryEntry objects to disable.
 
        .OUTPUTS
        PSCustomObject[]
        Returns result objects indicating success/failure for each CA modification.
 
        .EXAMPLE
        $Templates = Get-AdcsObjects | Where-Object { $_.ObjectClass -eq 'pKICertificateTemplate' }
        $DemoTemplate = $Templates | Where-Object { $_.Properties['name'].Value -eq 'Demo1' }
        Disable-Template -Template $DemoTemplate
 
        .EXAMPLE
        $Templates = Get-AdcsObjects | Where-Object { $_.ObjectClass -eq 'pKICertificateTemplate' }
        $Templates | Where-Object { $_.Properties['name'].Value -like 'Demo*' } | Disable-Template -WhatIf
 
        .EXAMPLE
        $CAs = Get-AdcsObjects | Where-Object { $_.ObjectClass -eq 'pKIEnrollmentService' }
        $Template = Get-AdcsObjects | Where-Object { $_.Properties['name'].Value -eq 'CustomTemplate' }
        Disable-Template -Template $Template -CertificateAuthority $CAs
 
        .LINK
        https://docs.microsoft.com/en-us/windows-server/networking/core-network-guide/cncg/server-certs/configure-the-server-certificate-template
 
        .NOTES
        Requires appropriate permissions to modify Certificate Authority objects in Active Directory.
        The function will skip templates that are not currently enabled on each CA.
         
        WARNING: Disabling templates will prevent certificate enrollment using those templates.
        Ensure this is the intended behavior before proceeding.
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory, ValueFromPipeline)]
        [ValidateNotNull()]
        [System.DirectoryServices.DirectoryEntry[]]$Template,
        
        [Parameter()]
        [System.DirectoryServices.DirectoryEntry[]]$CertificateAuthority,
        
        [Parameter()]
        [switch]$PassThru
    )


    begin {
        Write-Verbose "[$(Get-Date -Format 'yyyy-MM-dd hh:mm:ss')] Starting $($MyInvocation.MyCommand) on $env:COMPUTERNAME..."
        
        # Initialize results array
        $results = @()
        
        # If no specific CAs provided, discover all CAs in the forest
        if (-not $CertificateAuthority) {
            Write-Verbose "No specific CAs provided, discovering all CAs in forest..."
            
            try {
                # Get the current forest
                $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
                Write-Verbose "Forest: $($forest.Name)"
                
                # Search for Certificate Authorities (pKIEnrollmentService objects)
                $configContext = "CN=Configuration," + $forest.RootDomain.GetDirectoryEntry().Properties['distinguishedName'].Value
                $searcher = [System.DirectoryServices.DirectorySearcher]::new()
                $searcher.SearchRoot = [System.DirectoryServices.DirectoryEntry]::new("LDAP://$configContext")
                $searcher.Filter = "(objectClass=pKIEnrollmentService)"
                $searcher.SearchScope = [System.DirectoryServices.SearchScope]::Subtree
                
                $caResults = $searcher.FindAll()
                $CertificateAuthority = @()
                
                foreach ($result in $caResults) {
                    $CertificateAuthority += $result.GetDirectoryEntry()
                }
                
                Write-Verbose "Found $($CertificateAuthority.Count) Certificate Authorities"
                
                # Clean up
                $searcher.Dispose()
                $caResults.Dispose()
                
            } catch {
                Write-Error "Failed to discover Certificate Authorities: $($_.Exception.Message)"
                return
            }
        }
        
        if ($CertificateAuthority.Count -eq 0) {
            Write-Warning "No Certificate Authorities found or provided"
            return
        }
    }

    process {
        foreach ($templateObj in $Template) {
            # Validate that this is a certificate template
            if ($templateObj.SchemaClassName -ne 'pKICertificateTemplate') {
                Write-Warning "Object is not a certificate template (SchemaClassName: $($templateObj.SchemaClassName))"
                continue
            }
            
            # Get the template name for enrollment
            $templateName = $templateObj.Properties['name'].Value
            Write-Verbose "Processing template: $templateName"
            
            foreach ($ca in $CertificateAuthority) {
                try {
                    # Refresh the CA object to get current values
                    $ca.RefreshCache()
                    
                    $caName = $ca.Properties['name'].Value
                    $caDN = $ca.Properties['distinguishedName'].Value
                    
                    Write-Verbose "Processing CA: $caName"
                    Write-Verbose "CA DN: $caDN"
                    
                    # Get current certificate templates
                    $currentTemplates = @()
                    if ($ca.Properties['certificateTemplates'].Count -gt 0) {
                        $currentTemplates = @($ca.Properties['certificateTemplates'].Value)
                    }
                    
                    Write-Verbose "Current templates on $caName : $($currentTemplates -join ', ')"
                    
                    # Check if template is currently enabled
                    if ($templateName -notin $currentTemplates) {
                        Write-Verbose "Template '$templateName' is not enabled on CA '$caName'"
                        
                        $results += [PSCustomObject]@{
                            Success = $true
                            CertificateAuthority = $caName
                            CertificateAuthorityDN = $caDN
                            TemplateName = $templateName
                            TemplateDistinguishedName = $templateObj.Properties['distinguishedName'].Value
                            Action = "Not Enabled"
                            Error = $null
                        }
                        
                        continue
                    }
                    
                    # Remove the template from the certificateTemplates attribute
                    if ($PSCmdlet.ShouldProcess("$caName", "Disable template '$templateName'")) {
                        # Remove the template from the list
                        $ca.Properties['certificateTemplates'].Remove($templateName)
                        
                        # Commit the changes
                        $ca.CommitChanges()
                        
                        Write-Verbose "Successfully disabled template '$templateName' on CA '$caName'"
                        
                        $results += [PSCustomObject]@{
                            Success = $true
                            CertificateAuthority = $caName
                            CertificateAuthorityDN = $caDN
                            TemplateName = $templateName
                            TemplateDistinguishedName = $templateObj.Properties['distinguishedName'].Value
                            Action = "Disabled"
                            Error = $null
                        }
                    } else {
                        # WhatIf scenario
                        $results += [PSCustomObject]@{
                            Success = $true
                            CertificateAuthority = $caName
                            CertificateAuthorityDN = $caDN
                            TemplateName = $templateName
                            TemplateDistinguishedName = $templateObj.Properties['distinguishedName'].Value
                            Action = "Would Disable"
                            Error = $null
                        }
                    }
                    
                } catch {
                    $errorMsg = "Failed to disable template '$templateName' on CA '$caName': $($_.Exception.Message)"
                    Write-Warning $errorMsg
                    
                    $results += [PSCustomObject]@{
                        Success = $false
                        CertificateAuthority = $caName
                        CertificateAuthorityDN = $caDN
                        TemplateName = $templateName
                        TemplateDistinguishedName = $templateObj.Properties['distinguishedName'].Value
                        Action = "Failed"
                        Error = $errorMsg
                    }
                }
            }
        }
    }

    end {
        Write-Verbose "[$(Get-Date -Format 'yyyy-MM-dd hh:mm:ss')] Finishing $($MyInvocation.MyCommand) on $env:COMPUTERNAME..."
        
        if ($PassThru -or $WhatIfPreference) {
            Write-Output $results
        }
        
        # Summary
        $successful = $results | Where-Object { $_.Success -and $_.Action -eq "Disabled" }
        $notEnabled = $results | Where-Object { $_.Success -and $_.Action -eq "Not Enabled" }
        $failed = $results | Where-Object { -not $_.Success }
        
        Write-Verbose "Summary:"
        Write-Verbose " Templates disabled: $($successful.Count)"
        Write-Verbose " Templates not enabled: $($notEnabled.Count)"
        Write-Verbose " Failed operations: $($failed.Count)"
    }
}