本文目录导读:

我来帮你编写一个自动清理无用证书的脚本,以下是针对不同系统的实现方案:
Linux 系统证书清理脚本
#!/bin/bash
# 证书清理脚本
# 功能:自动清理过期、无效或未使用的证书
# 配置参数
CERT_PATHS=(
"/etc/ssl/certs"
"/etc/pki/tls/certs"
"/usr/local/share/ca-certificates"
"/usr/share/ca-certificates"
)
LOG_FILE="/var/log/cert-cleanup.log"
DRY_RUN=false # 设为 true 进行预检查,不实际删除
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# 检查证书是否过期
check_expired() {
local cert_file="$1"
local expire_date=$(openssl x509 -enddate -noout -in "$cert_file" 2>/dev/null | cut -d= -f2)
local expire_epoch=$(date -d "$expire_date" +%s 2>/dev/null)
local current_epoch=$(date +%s)
if [ -n "$expire_epoch" ] && [ "$expire_epoch" -lt "$current_epoch" ]; then
return 0 # 已过期
fi
return 1 # 未过期
}
# 检查证书是否有效
check_valid() {
local cert_file="$1"
# 使用 openssl 验证证书
openssl x509 -noout -in "$cert_file" 2>/dev/null
if [ $? -ne 0 ]; then
return 0 # 无效
fi
# 检查证书链
openssl verify -CApath /etc/ssl/certs "$cert_file" 2>/dev/null
if [ $? -ne 0 ]; then
return 1 # 证书链问题
fi
return 2 # 完全有效
}
# 查找并清理证书
cleanup_certs() {
local cleaned=0
local expired=0
local invalid=0
log "开始清理证书..."
for cert_dir in "${CERT_PATHS[@]}"; do
if [ ! -d "$cert_dir" ]; then
log "目录不存在: $cert_dir"
continue
fi
log "检查目录: $cert_dir"
# 查找所有证书文件
find "$cert_dir" -type f \( -name "*.crt" -o -name "*.pem" -o -name "*.cert" \) 2>/dev/null | while read cert; do
# 跳过符号链接
if [ -L "$cert" ]; then
continue
fi
# 检查过期
if check_expired "$cert"; then
expired=$((expired + 1))
log "过期证书: $cert"
if [ "$DRY_RUN" = false ]; then
rm -f "$cert"
cleaned=$((cleaned + 1))
fi
continue
fi
# 检查有效性
check_valid "$cert"
case $? in
0)
invalid=$((invalid + 1))
log "无效证书: $cert"
if [ "$DRY_RUN" = false ]; then
rm -f "$cert"
cleaned=$((cleaned + 1))
fi
;;
esac
done
done
log "清理完成: 清理 $cleaned 个证书"
log " - 过期证书: $expired"
log " - 无效证书: $invalid"
}
# 更新证书存储
update_cert_store() {
log "更新证书存储..."
# Debian/Ubuntu
if command -v update-ca-certificates &> /dev/null; then
update-ca-certificates --fresh 2>&1 | tee -a "$LOG_FILE"
fi
# CentOS/RHEL/Fedora
if command -v update-ca-trust &> /dev/null; then
update-ca-trust extract 2>&1 | tee -a "$LOG_FILE"
fi
}
# 清理重复证书
cleanup_duplicates() {
log "检查重复证书..."
local hash_map=()
for cert_dir in "${CERT_PATHS[@]}"; do
if [ ! -d "$cert_dir" ]; then
continue
fi
find "$cert_dir" -type f \( -name "*.crt" -o -name "*.pem" \) 2>/dev/null | while read cert; do
if [ -f "$cert" ]; then
local hash=$(openssl x509 -noout -hash -in "$cert" 2>/dev/null)
if [ -n "$hash" ]; then
if [[ " ${hash_map[@]} " =~ " ${hash} " ]]; then
log "发现重复证书: $cert"
if [ "$DRY_RUN" = false ]; then
rm -f "$cert"
fi
else
hash_map+=("$hash")
fi
fi
fi
done
done
}
# 主函数
main() {
log "=== 证书清理脚本开始 ==="
# 检查 root 权限
if [ "$EUID" -ne 0 ]; then
log "错误: 需要 root 权限运行此脚本"
exit 1
fi
# 处理命令行参数
while [[ $# -gt 0 ]]; do
case $1 in
--dry-run)
DRY_RUN=true
log "运行在预览模式(不实际删除)"
;;
--help)
echo "用法: $0 [选项]"
echo "选项:"
echo " --dry-run 预览模式,不实际删除"
echo " --help 显示此帮助信息"
exit 0
;;
*)
echo "未知选项: $1"
exit 1
;;
esac
shift
done
# 执行清理
cleanup_certs
cleanup_duplicates
update_cert_store
log "=== 证书清理脚本结束 ==="
}
# 运行主函数
main "$@"
Windows 系统证书清理脚本 (PowerShell)
# Windows 证书清理脚本
param(
[switch]$DryRun = $false
)
# 配置
$LogFile = "C:\Windows\Temp\cert-cleanup.log"
$CurrentDate = Get-Date
# 日志函数
function Write-Log {
param([string]$Message)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$timestamp - $Message" | Out-File -FilePath $LogFile -Append
Write-Host "$timestamp - $Message"
}
# 检查证书是否过期
function Test-CertExpired {
param(
[System.Security.Cryptography.X509Certificates.X509Certificate2]$Cert
)
if ($Cert.NotAfter -lt $CurrentDate) {
return $true
}
return $false
}
# 清理指定存储中的证书
function Cleanup-CertStore {
param(
[string]$StoreName,
[string]$StoreLocation
)
Write-Log "检查证书存储: $StoreName ($StoreLocation)"
try {
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store(
$StoreName,
[System.Security.Cryptography.X509Certificates.StoreLocation]::$StoreLocation
)
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
$cleanedCount = 0
foreach ($cert in $store.Certificates) {
$removeCert = $false
$reason = ""
# 检查过期
if (Test-CertExpired -Cert $cert) {
$removeCert = $true
$reason = "已过期 (过期日: $($cert.NotAfter))"
}
# 检查自签名证书(非根证书)
if ($cert.Subject -eq $cert.Issuer -and $StoreName -ne "Root") {
# 可以自定义规则
}
if ($removeCert) {
Write-Log " 清理证书: $($cert.Subject) - $reason"
if (-not $DryRun) {
try {
$store.Remove($cert)
$cleanedCount++
}
catch {
Write-Log " 错误: 无法删除证书 - $($_.Exception.Message)"
}
}
else {
$cleanedCount++
}
}
}
$store.Close()
Write-Log " 完成: 清理 $cleanedCount 个证书"
}
catch {
Write-Log " 错误: $($_.Exception.Message)"
}
}
# 清理用户和计算机证书存储
function Cleanup-AllStores {
Write-Log "开始清理 Windows 证书存储..."
$stores = @(
@{Name="My"; Location="CurrentUser"},
@{Name="My"; Location="LocalMachine"},
@{Name="Root"; Location="CurrentUser"},
@{Name="Root"; Location="LocalMachine"},
@{Name="CA"; Location="CurrentUser"},
@{Name="CA"; Location="LocalMachine"},
@{Name="TrustedPublisher"; Location="CurrentUser"},
@{Name="TrustedPublisher"; Location="LocalMachine"},
@{Name="Disallowed"; Location="CurrentUser"},
@{Name="Disallowed"; Location="LocalMachine"}
)
foreach ($store in $stores) {
Cleanup-CertStore -StoreName $store.Name -StoreLocation $store.Location
}
}
# 清理过期且未使用的根证书
function Cleanup-UnusedRootCerts {
Write-Log "检查未使用的根证书..."
try {
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store(
"Root",
[System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine
)
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
foreach ($cert in $store.Certificates) {
# 检查是否为微软根证书计划中的证书
$isMicrosoftCert = $cert.Issuer -match "Microsoft"
# 如果证书已过期且不是微软证书
if ((Test-CertExpired -Cert $cert) -and -not $isMicrosoftCert) {
if (-not $DryRun) {
Write-Log " 删除过期非微软根证书: $($cert.Subject)"
$store.Remove($cert)
}
else {
Write-Log " [预览] 将删除过期非微软根证书: $($cert.Subject)"
}
}
}
$store.Close()
}
catch {
Write-Log " 错误: $($_.Exception.Message)"
}
}
# 主函数
function Main {
Write-Log "========================================"
Write-Log "Windows 证书清理脚本开始"
Write-Log "运行模式: $(if ($DryRun) { "预览模式" } else { "实际执行" })"
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Log "错误: 需要管理员权限运行此脚本"
exit 1
}
Cleanup-AllStores
Cleanup-UnusedRootCerts
Write-Log "证书清理完成"
Write-Log "========================================"
}
# 执行主函数
Main
使用方法
Linux 版本:
# 赋予执行权限 chmod +x cleanup-certs.sh # 预览模式(不实际删除) sudo ./cleanup-certs.sh --dry-run # 实际执行 sudo ./cleanup-certs.sh # 查看日志 cat /var/log/cert-cleanup.log
Windows 版本:
# 以管理员身份运行 PowerShell Set-ExecutionPolicy Bypass -Scope Process # 预览模式 .\cleanup-certs.ps1 -DryRun # 实际执行 .\cleanup-certs.ps1 # 查看日志 Get-Content C:\Windows\Temp\cert-cleanup.log
定时任务设置
Linux (cron):
# 每月1号凌晨3点执行 0 3 1 * * /root/scripts/cleanup-certs.sh >> /var/log/cert-cleanup-cron.log 2>&1
Windows (Task Scheduler):
# 创建定时任务 $action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-File C:\scripts\cleanup-certs.ps1" $trigger = New-ScheduledTaskTrigger -Monthly -DaysOfMonth 1 -At 3am $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest Register-ScheduledTask -TaskName "Certificate Cleanup" -Action $action -Trigger $trigger -Principal $principal
这个脚本会自动:
- 检查并清理过期的证书
- 清理无效或损坏的证书
- 清理重复的证书
- 提供预览模式用于安全检查
- 生成详细的日志记录
使用时请先在预览模式测试,确认不会误删重要证书后再实际执行。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播