Public/Submit-PWSHCertreqCSR.ps1

function Submit-PWSHCertreqCSR {
    <#
    .SYNOPSIS
        Submits a certificate signing request (CSR) to a CA in a profile.
    .DESCRIPTION
        Connects to the specified CA via WinRM, transfers the local CSR file to the CA,
        and runs certreq -submit with the given certificate template. Returns the request
        status and, if the certificate is immediately issued, the ASN.1-decoded certificate.

        When the CA template requires manager approval the request enters Pending state.
        Use Approve-PWSHCertutilPendingCert (as a CA administrator) to issue the request,
        then use Get-PWSHCertreqCert to retrieve the issued certificate. The returned object
        carries Profile, CAServer, and RequestID so it can be piped directly into those cmdlets.
    .PARAMETER Profile
        The configuration profile to use.
    .PARAMETER CAFqdn
        The CA to submit the request to. Must be defined in the profile.
    .PARAMETER CSRPath
        Path to the certificate request file (.req, .csr, or .p10) on the local machine.
    .PARAMETER CertificateTemplate
        The LDAP name of the certificate template (not the display name).
    .PARAMETER OutputCertPath
        Optional. When the certificate is immediately issued, save the DER-encoded certificate
        to this local file path.
    .PARAMETER Credential
        Optional PSCredential for WinRM. Defaults to the current user.
    .EXAMPLE
        Submit-PWSHCertreqCSR -Profile 'prod-pki' -CAFqdn 'ca01.corp.local' `
            -CSRPath 'C:\requests\server01.req' -CertificateTemplate 'WebServer'
        Submits the CSR to ca01.corp.local using the WebServer template.
        Returns an object with Status='Issued' or Status='Pending'.
    .EXAMPLE
        Submit-PWSHCertreqCSR -Profile 'prod-pki' -CAFqdn 'ca01.corp.local' `
            -CSRPath 'C:\requests\server01.req' -CertificateTemplate 'WebServer' `
            -OutputCertPath 'C:\certs\server01.cer'
        Submits the CSR and saves the issued certificate to disk if immediately approved.
    .EXAMPLE
        $pending = Submit-PWSHCertreqCSR -Profile 'prod-pki' -CAFqdn 'ca01.corp.local' `
            -CSRPath 'C:\requests\server01.req' -CertificateTemplate 'ManualApproval'
        $pending | Approve-PWSHCertutilPendingCert -Confirm:$false
        $pending | Get-PWSHCertreqCert
        Full pending-approval workflow: submit, approve as CA manager, retrieve certificate.
    .OUTPUTS
        PSCustomObject. Properties: Profile, CAServer, RequestID, Status, CertificateTemplate,
        CertBase64, Certificate, RawOutput.
        Status is one of: Issued, Pending.
        Certificate (ASN.1-decoded PSCustomObject) is populated only when Status is Issued.
    #>

    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory, Position = 0)]
        [string] $Profile,

        [Parameter(Mandatory)]
        [string] $CAFqdn,

        [Parameter(Mandatory)]
        [ValidateScript({
            if (-not (Test-Path -Path $_ -PathType Leaf)) {
                throw "CSR file not found: '$_'"
            }
            $true
        })]
        [string] $CSRPath,

        [Parameter(Mandatory)]
        [string] $CertificateTemplate,

        [Parameter()]
        [string] $OutputCertPath,

        [Parameter()]
        [pscredential] $Credential
    )

    $config        = Read-ConfigFile
    $profileConfig = Get-ProfileConfig -Config $config -ProfileName $Profile

    $found = $profileConfig.cas | Where-Object { $_.fqdn -eq $CAFqdn }
    if (-not $found) { throw "CA '$CAFqdn' is not defined in profile '$Profile'." }

    $csrBytes = [IO.File]::ReadAllBytes((Resolve-Path $CSRPath).Path)

    $sessionArgs = @{ CAFqdn = $CAFqdn; RemotingConfig = $profileConfig.remoting }
    if ($PSBoundParameters.ContainsKey('Credential')) { $sessionArgs['Credential'] = $Credential }
    $session = Get-CASession @sessionArgs

    try {
        $result = Invoke-CertreqSubmit -Session $session -CSRBytes $csrBytes `
                      -CertificateTemplate $CertificateTemplate

        $certificate = $null
        if ($result.Status -eq 'Issued' -and $result.CertBase64) {
            $certificate = ConvertFrom-CertutilAsn1 -CertBase64 $result.CertBase64
            if ($PSBoundParameters.ContainsKey('OutputCertPath')) {
                [IO.File]::WriteAllBytes($OutputCertPath, [Convert]::FromBase64String($result.CertBase64))
                Write-Verbose "Certificate saved to $OutputCertPath"
            }
        }

        [PSCustomObject]@{
            Profile             = $Profile
            CAServer            = $CAFqdn
            RequestID           = $result.RequestID
            Status              = $result.Status
            CertificateTemplate = $CertificateTemplate
            CertBase64          = $result.CertBase64
            Certificate         = $certificate
            RawOutput           = $result.RawOutput
        }
    } catch {
        Write-Error "Failed to submit CSR to '$CAFqdn': $_"
    }
}