windows在cygwin64下使用acme.sh批量签发Let's Encrypt的ssl证书,并用powershell重新分配iis证书

使用前提

本脚本是在使用阿里云Windows服务器的前提,如果使用其他dns服务,请参看acme.sh的dns相关文档

配置好cygwin64、acme.sh并配置好阿里云账户,openssl最好也安装上

cygwin64配置

如果windows server 08R2启动安装程序失败,请使用cmd运行

setup-x86_64.exe --allow-unsupported-windows --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215 --no-verify

其他老旧系统请参考cygwin64官网网页的How can I install the last Cygwin version for an old, unsupported Windows回答

acme.sh配置

openssl参考,添加-certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -nomac 是为了应对pfx输入密钥不正确

最终路径就是项目路径

以下是batch脚本,请保存在autoacme.bat文件中

@echo off & setlocal EnableDelayedExpansion

:: 数组长度,不用管,会自己加值
set objLength=0
:: 公共证书备份路径
set commonPath=E:\cert
:: cygwin64用户路径
set cygwinPath=E:\Cygwin64\home\Administrator
:: cygwin64内部用户路径
set cygwinUserPath=/home/Administrator
:: pfx文件密钥,这里的密钥必须和powershell里的pfx密钥一致
set pfxPassword=dgfdgsdfg

:: 如果公共路径不存在,那么创建,如果路径已存在,不影响命令继续执行
md %commonPath%

:: 证书在以下列表中添加即可
:: 指定域名
set obj[%objLength%]*domain=www.test.com
:: 最终路径
set obj[%objLength%]*path=D:\Web\Main

set /a objLength+=1
:: 指定域名
set obj[%objLength%]*domain=buy.test.com
:: 最终路径
set obj[%objLength%]*path=D:\Web\buy

set /a objLength+=1
:: 指定域名
set obj[%objLength%]*domain=go.test.com
:: 最终路径
set obj[%objLength%]*path=D:\Web\Go

:: 初始索引
set objIndex=0
:: 重试次数
set retryCnt=0
::循环
:loopStart
::判断索引值是否大于数组长度,大于的话跳到结束,不大于的话继续循环
if %objIndex% gtr %objLength% goto end

::初始化当前变量
set curr.domain=0
set curr.path=0
::重置重试次数
set /a retryCnt=0

:: delims==*表示使用=和*分割字符串,tokens=1-3是取切割后字符串的前1到3个,循环对象的每个属性,%%i 是如 obj[0] 标识是第几个对象, %%j 标识是对象的那个属性,%%k 是指定对象属性的值
for /f "usebackq delims==* tokens=1-3" %%i in (`set obj[%objIndex%]`) do (
    :: 赋值变量
    set curr.%%j=%%k
)

echo domain=%curr.domain%
echo path=%curr.path%

:: 登录到cygwin使用acme.sh签发证书,并将文件拷贝到公共证书目录,并转成pfx格式,密码统一使用%pfxPassword%
echo 签发%curr.domain%证书
:: 设置执行命令后缀,这里是acme.sh相关命令,修改dns api就在这里
set issueCmd=--issue --dns dns_ali -d %curr.domain% --fullchain-file %cygwinUserPath%/.acme.sh/%curr.domain%_ecc/%curr.domain%.pem --key-file %cygwinUserPath%/.acme.sh/%curr.domain%_ecc/%curr.domain%.key
bash --login -i -c "acme.sh %issueCmd%"

echo 检查%curr.domain%key文件大小和backup目录是否存在文件
set byte=0
for %%A in ("%cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.key") do (
	set /a byte=%%~zA
)

echo %curr.domain%.key大小:%byte%字节
:: 如果key文件大小为零
if %byte% equ 0 (
    if EXIST %cygwinPath%\.acme.sh\%curr.domain%_ecc\backup\key.bak (
        echo 检查key.bak的大小
        for %%A in ("%cygwinPath%\.acme.sh\%curr.domain%_ecc\backup\key.bak") do (
            set /a byte=%%~zA
        )
        :: bak文件不为零,那么拷贝覆盖
        echo /backup/key.bak大小:%byte%字节
        if %byte% equ 0 (
            echo 拷贝key.bak到根目录
            copy %cygwinPath%\.acme.sh\%curr.domain%_ecc\backup\key.bak %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.key /y
        ) else (
            :: 如果全部失败,那么直接重新申请
            :forceIssue
            echo 尝试重新申请%curr.domain%证书第%retryCnt%次
            bash --login -i -c "acme.sh %issueCmd% --force"
            :: 重试一次,加一次次数
            set /a retryCnt+=1
        )
    )
)

echo 拷贝key文件到公共目录
copy %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.key %commonPath%\%curr.domain%.key /y

echo 赋予权限
bash --login -i -c "chmod -R g+rw %cygwinUserPath%/.acme.sh/%curr.domain%_ecc"

echo 第一次检查%curr.domain%.pfx文件是否存在
IF NOT EXIST %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.pfx (
    echo openssl转换pfx,因为acme.sh转换失败
    openssl pkcs12 -export -certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -nomac -out %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.pfx -inkey %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.key -in %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.cer -password pass:"%pfxPassword%"
)

echo 第二次检查%curr.domain%.pfx文件是否存在
IF NOT EXIST %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.pfx (
    IF %retryCnt% gtr 3 goto skipCurr 
    else goto forceIssue
)

echo 拷贝pfx文件到公共目录
copy %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.pfx %commonPath%\%curr.domain%.pfx /y

:: 如果pem格式文件不存在,那么使用openssl转换成pem格式
IF NOT EXIST %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.pem (
    echo openssl转换pem
    openssl pkcs12 -in %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.pfx -out %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.pem -nodes -password pass:"%pfxPassword%"
)

:: 拷贝pem文件到公共目录
echo 拷贝pem到公共目录
copy %cygwinPath%\.acme.sh\%curr.domain%_ecc\%curr.domain%.pem %commonPath%\%curr.domain%.pem /y

:: 拷贝证书到最终路径,如果路径相等会直接拷贝失败,如果最终路径不存在,也会拷贝失败
echo 拷贝%curr.domain%证书到项目目录
copy %commonPath%\%curr.domain%.pem %curr.path%\%curr.domain%.pem /y & copy %commonPath%\%curr.domain%.key %curr.path%\%curr.domain%.key /y & copy %commonPath%\%curr.domain%.pfx %curr.path%\%curr.domain%.pfx /y


:skipCurr
:: 索引+1
set /a objIndex=%objIndex% + 1
:: 继续循环
goto loopStart

:end
:: 暂停看结果
:: pause
:: 执行完后退出
exit

PowerShell 脚本,使用前,更改执行策略

关于执行策略:
https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.4#powershell-execution-policies

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser

将以下脚本保存为reissueIISCert.ps1文件

# 使用前先将策略设置为不严格 Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser
# 保证证书有效的情况下再运行次脚本,将证书名称、证书目录、密钥放入以下数组
# 公共证书密钥
$pfxpassword = "dgfdgsdfg"
# 公共证书路径
$pfxCommandDir= "E:\cert"
# 域名
$domain="test.com"
# 服务器上的证书与端口映射关系
$data = @(
    [pscustomobject]@{subDomain = 'www';port=443}
    [pscustomobject]@{subDomain = 'buy';port=8443}
    [pscustomobject]@{subDomain = 'go';port=7443}
)
# 开始循环数组操作
foreach ($element in $data) {
    $pfxPath="$($pfxCommandDir)\$($element.subDomain).$($domain).pfx"
    Write-Host $pfxPath
    $securePfxKey = ConvertTo-SecureString -String $pfxpassword -AsPlainText -Force
    Import-PfxCertificate -FilePath $pfxPath -CertStoreLocation Cert:\LocalMachine\My -Password $securePfxKey
    $pfxData = Get-PfxData -FilePath $pfxPath -Password $securePfxKey
    $newThumbprint = $pfxData.EndEntityCertificates.Thumbprint
    $guid=New-Guid
    $applicationID = "{$($guid)}" # hardcode it once
    $addr="0.0.0.0:$($element.port)"
    netsh http delete sslcert ipport=$addr
    netsh http add sslcert ipport=$addr certhash=$newThumbprint appid=$applicationID
}
# 执行完后退出
exit

创建任务计划程序参考

将启动程序设置为autoacme.bat即可,设置完成后,右键对应任务计划程序->属性->操作,在这一对话框中,将reissueIISCert.ps1加入到队列中。在常规页面中,勾选“不管用户是否登录都要运行”以及“使用最高权限”,保存即可
任务计划程序是按照顺序执行的。

热门相关:风流医圣   美女总裁之贴身高手   强宠头号鲜妻:陆少,滚!   重生豪门宠婚:枭宠不乖娇妻   红色比基尼