You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何导出带SAN扩展的证书并优化certutil导出CSV可读性

证书导出脚本优化及需求实现方案

原有脚本可读性调整

你当前使用的原生certutil导出命令存在两个影响可读性的问题:直接重定向输出的文件会夹带certutil运行日志、命令统计行,且默认输出编码为GBK,部分表格软件打开会出现乱码。可以先做基础优化,调整后导出的标准csv无冗余内容,打开即可正常查看:

$Local = $PSScriptRoot
$File = Join-Path $Local "IssuedCerts.csv"
# 导出字段可按需调整
$Header = "Request ID,Requester Name,Certificate Template,Serial Number,Certificate Effective Date,Certificate Expiration Date,Issued Country/Region,Issued Organization,Issued Organization Unit,Issued Common Name,Issued City,Issued State,Issued Email Address"

# 过滤certutil输出的冗余日志行,统一用UTF8编码输出
certutil -view -out $Header csv | 
    Where-Object { $_ -notmatch '^(CertUtil|  Row|  Maximum|The command completed successfully)' } | 
    Out-File $File -Encoding utf8

核心需求实现:导出即将过期证书+SAN扩展数据

certutil原生导出不支持直接输出格式化的SAN字段,且没有内置过期筛选能力,可以通过解析证书原始扩展字段+过期时间判断实现需求,脚本支持自定义即将过期的时间阈值(默认取30天内过期的证书),SAN字段会自动解析为分号分隔的可读格式(包含DNS名称、IP、邮箱等所有SAN条目):

# 配置项
$Local = $PSScriptRoot
$outFile = Join-Path $Local "ExpiringCerts_WithSAN.csv"
$expireThresholdDays = 30 # 自定义过期阈值,单位为天,即导出多少天内即将过期的证书
$deadline = (Get-Date).AddDays($expireThresholdDays)

# 基础导出字段,额外保留证书核心标识字段用于匹配详情
$baseFields = "Request ID,Requester Name,Certificate Template,Serial Number,Certificate Effective Date,Certificate Expiration Date,Issued Common Name,Issued Email Address"
$rawCsv = certutil -view -out $baseFields csv | 
    Where-Object { $_ -notmatch '^(CertUtil|  Row|  Maximum|The command completed successfully|$)' } | 
    ConvertFrom-Csv

$result = foreach ($certRow in $rawCsv) {
    # 解析证书过期时间,过滤不在过期阈值范围内的证书
    try {
        $expireDate = [datetime]::ParseExact($certRow.'Certificate Expiration Date', 'M/d/yyyy h:mm:ss tt', [Globalization.CultureInfo]::GetCultureInfo('en-US'))
        if ($expireDate -gt $deadline) { continue }
    }
    catch { continue }

    # 拉取单张证书的扩展信息,解析SAN字段
    $certDetail = certutil -view -restrict "Request ID=$($certRow.'Request ID')" -out "Certificate Extensions"
    $sanContent = $certDetail | Select-String -Pattern 'Subject Alternative Name\(s\):(.*?)(?=\n\s*\n|  CertUtil)' -Context 0,10
    $sanList = @()
    if ($sanContent) {
        $sanMatches = [regex]::Matches($sanContent.Value, 'DNS Name=(.*?)(?=\s|$)|IP Address=(.*?)(?=\s|$)|RFC822 Name=(.*?)(?=\s|$)')
        foreach ($match in $sanMatches) {
            if ($match.Groups[1].Value) { $sanList += "DNS:$($match.Groups[1].Value)" }
            if ($match.Groups[2].Value) { $sanList += "IP:$($match.Groups[2].Value)" }
            if ($match.Groups[3].Value) { $sanList += "Email:$($match.Groups[3].Value)" }
        }
    }

    # 组装输出结果
    [PSCustomObject]@{
        'Request ID' = $certRow.'Request ID'
        'Requester Name' = $certRow.'Requester Name'
        'Certificate Template' = $certRow.'Certificate Template'
        'Serial Number' = $certRow.'Serial Number'
        'Certificate Effective Date' = $certRow.'Certificate Effective Date'
        'Certificate Expiration Date' = $certRow.'Certificate Expiration Date'
        'Issued Common Name' = $certRow.'Issued Common Name'
        'Issued Email Address' = $certRow.'Issued Email Address'
        'SAN Values' = $sanList -join '; '
    }
}

# 导出最终结果文件
$result | Export-Csv -Path $outFile -NoTypeInformation -Encoding utf8

使用说明

  • 直接在CA服务器上运行该脚本即可,不需要额外安装第三方模块
  • 调整$expireThresholdDays的值即可修改过期筛选范围,比如设置为90就是导出90天内过期的证书
  • 导出的SAN字段会标注条目类型,多个条目用分号分隔,可直接在表格软件中筛选查看

内容的提问来源于stack exchange,提问作者Mark Delphi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 17:09:15