functions/CA/Get-PkiCaIssuedCertificate.ps1

function Get-PkiCaIssuedCertificate {
    <#
    .SYNOPSIS
        Lists issued certificates.
     
    .DESCRIPTION
        Lists issued certificates.
     
    .PARAMETER ComputerName
        The computername of the CA (automatically detects the CA name)
        Specifying this will cause the command to use PowerShell remoting.
 
    .PARAMETER Credential
        The credentials to use when connecting to the server.
        Only used in combination with -ComputerName.
         
    .PARAMETER FQCAName
        The fully qualified name of the CA.
        Specifying this allows remote access to the target CA.
        '<Computername>\<CA Name>'
 
    .PARAMETER CommonName
        Filter by common name.
 
    .PARAMETER RequestID
        Search for a certificate by its specific request ID.
 
    .PARAMETER Requester
        Search for certificates by who requested them.
 
    .PARAMETER TemplateName
        Search for certificates by the template they were made from.
     
    .PARAMETER Properties
        The properties to retrieve.
        These are the headers as shown in the CA mmc console on an English languaged device.
        The result objects will have the same properties, but without the whitespace.
 
    .PARAMETER Server
        The active directory server to contact using LDAP.
        Used to resolve the templates used.
     
    .EXAMPLE
        PS C:\> Get-PkiCaIssuedCertificate
     
        Returns all issued certificates from the current computer (assumes localhost is a CA)
 
    .EXAMPLE
        PS C:\> Get-PkiCaIssuedCertificate -FQCAName "ca.contoso.com\MS-CA-01"
 
        Returns all issued certificates from the CA "ca.contoso.com\MS-CA-01"
        Requires the local computer to have the CA management tools installed
 
    .EXAMPLE
        PS C:\> Get-PkiCaIssuedCertificate -Computername ca.contoso.com
 
        Returns all issued certificate from ca.contoso.com.
        Requires PS remoting access to the target computerh osting the CA service.
#>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingEmptyCatchBlock", "")]
    [CmdletBinding()]
    param (
        [PSFComputer[]]
        $ComputerName,

        [PSCredential]
        $Credential,
        
        [string]
        $FQCAName,

        [string]
        $CommonName,

        [int]
        $RequestID,

        [string]
        $Requester,

        [PsfArgumentCompleter('PkiExtension.TemplateName')]
        [string]
        $TemplateName,
        
        [String[]]
        $Properties = (
            'Issued Common Name',
            'Certificate Expiration Date',
            'Certificate Effective Date',
            'Certificate Template',
            'Issued Request ID',
            'Certificate Hash',
            'Request Disposition Message',
            'Requester Name',
            'Binary Certificate'
        ),

        [string]
        $Server
    )
    begin {
        $tmplParam = $PSBoundParameters | ConvertTo-PSFHashtable -Include Server, Credential
        $templates = Get-PkiTemplate @tmplParam
        
        $data = @{
            FQCAName     = $FQCAName
            Properties   = $Properties
            Templates    = $templates
            CommonName   = $CommonName
            RequestID    = $RequestID
            Requester    = $Requester
            TemplateName = $TemplateName
        }

        $parameters = @{
            ArgumentList = $data
        }
        if ($ComputerName) {
            $parameters["HideComputerName"] = $true
            $parameters["ComputerName"] = $ComputerName
            if ($Credential) {
                $parameters['Credential'] = $Credential
            }
        }
    }
    process {
        Invoke-PSFCommand @parameters -ScriptBlock {
            param (
                $Data
            )

            # Copy variables over
            foreach ($pair in $Data.GetEnumerator()) {
                Set-Variable -Name $pair.Key -Value $pair.Value
            }

            $ErrorActionPreference = 'Stop'
            trap {
                Write-Warning "Error retrieving Certificate information: $_"
                throw $_
            }
            
            #region Preparation CA Connect
            try { $caView = New-Object -ComObject CertificateAuthority.View }
            catch { throw "Unable to create Certificate Authority View. $env:COMPUTERNAME does not have ADSC Installed" }
            
            if ($FQCAName) {
                $null = $CaView.OpenConnection($FQCAName)
            }
            else {
                $caName = (Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Services\CertSvc\Configuration' -Name Active).Active
                $null = $caView.OpenConnection("$($env:COMPUTERNAME)\$($caName)")
            }
            $CaView.SetResultColumnCount($Properties.Count)
            
            foreach ($item in $Properties) {
                $index = $caView.GetColumnIndex($false, $item)
                $caView.SetResultColumn($index)
            }
            
            # https://learn.microsoft.com/en-us/windows/win32/api/certview/nf-certview-icertview-setrestriction
            $CVR_SEEK_EQ = 1
            # $CVR_SEEL_LE = 2
            # $CVR_SEEK_LT = 4
            # $CVR_SEEK_GE = 8
            # $CVR_SEEK_GT = 16

            $CVR_SORT_NONE = 0
            
            # 20 - issued certificates
            $caView.SetRestriction($caView.GetColumnIndex($false, 'Request Disposition'), $CVR_SEEK_EQ, $CVR_SORT_NONE, 20)
            if ($CommonName) { $caView.SetRestriction($caView.GetColumnIndex($false, 'Issued Common Name'), $CVR_SEEK_EQ, $CVR_SORT_NONE, $CommonName) }
            if ($RequestID) { $caView.SetRestriction($caView.GetColumnIndex($false, 'Issued Request ID'), $CVR_SEEK_EQ, $CVR_SORT_NONE, $RequestID) }
            if ($Requester) { $caView.SetRestriction($caView.GetColumnIndex($false, 'Requester Name'), $CVR_SEEK_EQ, $CVR_SORT_NONE, $Requester) }
            if ($TemplateName) {
                $templateID = ($Templates | Where-Object DisplayName -EQ $TemplateName).'msPKI-Cert-Template-OID'
                if (-not $templateID) { $templateID = $TemplateName }
                $caView.SetRestriction($caView.GetColumnIndex($false, 'Certificate Template'), $CVR_SEEK_EQ, $CVR_SORT_NONE, $templateID)
            }

            
            $CV_OUT_BASE64HEADER = 0
            $CV_OUT_BASE64 = 1
            $RowObj = $caView.OpenView()
            #endregion Preparation CA Connect
            
            #region Process Certificates
            while ($RowObj.Next() -ne -1) {
                #region Process Properties
                $Cert = @{
                    PSTypeName = "PkiExtension.IssuedCertificate"
                }
                $ColObj = $RowObj.EnumCertViewColumn()
                $null = $ColObj.Next()
                do {
                    $displayName = $ColObj.GetDisplayName()
                    # format Binary Certificate in a savable format.
                    if ($displayName -eq 'Binary Certificate') {
                        $Cert[$displayName.Replace(" ", "")] = $ColObj.GetValue($CV_OUT_BASE64HEADER)
                        $Cert['Certificate'] = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new(([System.Text.Encoding]::UTF8.GetBytes($Cert[$displayName.Replace(" ", "")])))
                    }
                    else { $Cert[$displayName.Replace(" ", "")] = $ColObj.GetValue($CV_OUT_BASE64) }
                }
                until ($ColObj.Next() -eq -1)
                Clear-Variable -Name ColObj
                #endregion Process Properties
                
                #region Process Template Name
                $Cert['TemplateDisplayName'] = $null
                if ($Cert.CertificateTemplate) {
                    try {
                        $Cert['TemplateDisplayName'] = ($Templates | Where-Object msPKI-Cert-Template-OID -EQ $Cert.CertificateTemplate).DisplayName
                        if (-not $Cert['TemplateDisplayName']) {
                            $Cert['TemplateDisplayName'] = ($Templates | Where-Object Name -EQ $Cert.CertificateTemplate).DisplayName
                        }
                        if (-not $Cert['TemplateDisplayName']) { $Cert['TemplateDisplayName'] = $Cert.CertificateTemplate }
                        if ($Cert['Certificate']) { Add-Member -InputObject $Cert['Certificate'] -MemberType NoteProperty -Name TemplateDisplayName -Value $Cert['TemplateDisplayName'] }
                    }
                    catch { }
                }
                #endregion Process Template Name
                
                [pscustomobject]$Cert | Add-Member -MemberType ScriptMethod -Name ToString -Value { $this.IssuedCommonName } -Force -PassThru
            }
            #endregion Process Certificates
        } | Select-PSFObject -KeepInputObject -TypeName 'PkiExtension.IssuedCertificate'
    }
}