使用前提
本脚本是在使用阿里云Windows服务器的前提,如果使用其他dns服务,请参看
配置好cygwin64、acme.sh并配置好阿里云账户,openssl最好也安装上
,添加-certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -nomac 是为了应对pfx输入密钥不正确
最终路径就是项目路径
一、安装cygwin64
1. 下载
如果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
其他老旧系统请参考 网页的How can I install the last Cygwin version for an old, unsupported Windows回答
2. 非老旧系统配置镜像点
如果不是老久系统 ,则可以考虑使用阿里云镜像
阿里云镜像点: https://mirrors.aliyun.com
3. 安装包参考列表
curl
cron
bzip2
wget
gcc-core
gcc-g++
make
openssh
openssl
lynx
dos2unix
vim
4. Windows配置环境变量
在Path后加 ;C:\cygwin64\bin;C:\cygwin64\usr\local\bin
5. 如果遇到VIM不能粘贴复制
打开cygwin64桌面图标Cygwin64 Terminal,进入控制台
cd /home
vim .vimrc
i键进入编辑模式,键入以下内容
set mouse=csyntax on
esc键退出编辑模式,输入 :wq
即可保存文件
shift+ins 是cygwin64控制台下的粘贴键
二、安装acme.sh
1. 通过curl命令直接安装acme.sh
curl -k https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | sh -s -- --install-online -m my@example.com
如果报错如图
输入以下,使curl忽略全局ssl认证,成功后 ,再去通过curl安装acme.sh试试
echo insecure > ~/.curlrc
2. 如果步骤二.1成功则不需要看此条
1)直接去git下载acme.sh的源码
使用解压软件如7z将acme.sh-3.0.7.tar.gz解压两次放在/usr/download目录下,并重命名为acme.sh,如图
2)安装acme.sh
切换到cygwin64控制台
cd /usr/download/acme.sh./acme.sh --install -m example@qq.com
3. 配置acme.sh
0)安装完成后重新加载 Bash
source ~/.bashrc
1)配置自动更新
acme.sh --upgrade --auto-upgrade
2)切换至Letsencrypt
acme.sh --set-default-ca --server letsencrypt
3)配置DNSApi,这里是参考阿里云的dnsapi,其他请参考
cd /home/Administrator/.acme.sh
vim account.conf
i键进入编辑模式,输入阿里云帐号的AccessKey相关内容
export Ali_Key="LTAIsadfd8J9qs4fxxxxxxxxxx"export Ali_Secret="Xp3adgfNDOW0CJcPLKoUwqxxxxxxxxxx"
esc键退出编辑模式,输入 :wq 保存文件并退出
三、准备powershell脚本
PowerShell 脚本,使用前,更改执行策略
关于执行策略:
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser
以下是PowerShell脚本,如果乱码,请将文件保存为GB2312字符文件
1.acme自动申请证书脚本,请保存在 cygwin64批量自动签发证书.ps1
文件中
# 设定bash别名,如果系统装了wsl可能冲突,使用别名强制使用cygwin64命令Set-Alias -Name bash C:\cygwin64\bin\bash.exe# 设定openssl别名,如果系统装了wsl可能冲突,使用别名强制使用cygwin64命令Set-Alias -Name openssl C:\cygwin64\bin\openssl.exe# 公共证书备份路径,务必带盘符$commonPath = "E:\cert"# cygwin64用户路径,务必带盘符,Administrator是计算机安装cygwin64的用户名,不同情况名字不同$userPath = "C:\Cygwin64\home\Administrator"# cygwin64内部用户路径$cygwinUserPath = "/home/Administrator"# pfx文件密钥$pfxPassword = "dgfdgsdfg"# 证书在以下列表中添加即可$data = @( [pscustomobject]@{ # 要申请的域名 domain = "buy.test.com"; # 项目路径,可空 path = "D:\Web\Main" }, [pscustomobject]@{ domain = "go.test.com"; }, [pscustomobject]@{ domain = "*.test.com"; })# 如果公共路径不存在,那么创建,如果路径已存在,不影响命令继续执行if (![System.IO.Directory]::Exists($commonPath)) { md $commonPath}# 获取公共证书备份路径在cygwin64环境下的路径$cygwinCommonPath = "/cygdrive/" + $commonPath.Replace(":", "").Replace("\", "/");# 重试次数$retryCnt = 0function IssueKey { param ( [string]$currDomain, [string]$currPath, [bool]$force ) # 如果重试次数大于2,那么退出当前函数 if ($retryCnt -gt 2) { return } # 替换特殊路径名 $domain = $currDomain.Replace("*", "_") $cygDomain = $currDomain.Replace("*", "\*") # 设置执行命令后缀,这里是acme.sh相关命令,修改dns api就在这里 $issueCmd = "--issue --dns dns_ali -d $($currDomain) --key-file $($cygwinCommonPath)/$($domain).key --fullchain-file $($cygwinCommonPath)/$($domain)_fullchain.cer" #如果是强制重发 if ($force) { $issueCmd += " --force" } Write-Host 被执行的acme.sh后缀命令 $issueCmd bash --login -i -c "acme.sh $($issueCmd)" Write-Host 检查$currDomain key文件大小和backup目录是否存在文件 $commonFullChainPath = "$($commonPath)\$($domain)_fullchain.cer" $commonKeyPath = "$($commonPath)\$($domain).key" $commonPfxPath = "$($commonPath)\$($domain).pfx" $commonPemPath = "$($commonPath)\$($domain).pem" # cygwin环境下的目录 $cygwinCertPath = "$($cygwinUserPath)/.acme.sh/$($cygDomain)_ecc" Write-Host 赋予权限 bash --login -i -c "chmod -R g+rw $($cygwinCertPath)" Write-Host 拷贝Key、Fullchain文件到公共目录 bash --login -i -c "cp -f $($cygwinCertPath)/$($cygDomain).key $($cygwinCommonPath)/$($domain).key" bash --login -i -c "cp -f $($cygwinCertPath)/fullchain.cer $($cygwinCommonPath)/$($domain)_fullchain.cer" # 判断绝对路径下证书文件是否存在,如果不存在直接强制重新生成证书 Write-Host 第一次检查$commonKeyPath 文件是否存在 if (![System.IO.File]::Exists($commonKeyPath)) { Write-Host 检查key.bak是否存在 # 尝试从备份中恢复文件到原目录 bash --login -i -c "cp -f $($cygwinCertPath)/backup/key.bak $($cygwinCertPath)/$($cygDomain).key" # 尝试从原目录拷贝文件到公共目录 bash --login -i -c "cp -f $($cygwinCertPath)/$($cygDomain).key $($cygwinCommonPath)/$($domain).key" Write-Host 第二次检查$commonKeyPath 文件是否存在 if (![System.IO.File]::Exists($commonKeyPath)) { Write-Host 公共路径证书文件不存在 $commonKeyPath 即将强制重新申请 # 重试次数+1 $retryCnt += 1 IssueKey -currDomain $currDomain -currPath $currPath -force $true } } Write-Host 第一次检查 $($domain).pfx 文件是否存在 if (![System.IO.File]::Exists($commonPfxPath)) { Write-Host openssl转换pfx # openssl 3.x 版本 openssl pkcs12 -export -certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -nomac -out $commonPfxPath -inkey $commonKeyPath -in $commonFullChainPath -password pass:$pfxPassword # openssl 1.0 版本 # openssl pkcs12 -export -out $commonPfxPath -inkey $commonKeyPath -in $commonFullChainPath -password pass:$pfxPassword } Write-Host 第二次检查 $($domain).pfx 文件是否存在 if (![System.IO.File]::Exists($commonPfxPath)) { # 如果重试次数大于2,那么退出当前函数 if ($retryCnt -gt 2) { return } else { # 重试次数+1 $retryCnt += 1 IssueKey -currDomain $currDomain -currPath $currPath -force $true } } # 如果pem格式文件不存在,那么使用openssl转换成pem格式 if (![System.IO.File]::Exists($commonPemPath)) { Write-Host openssl转换pem openssl pkcs12 -in $commonPfxPath -out $commonPemPath -nodes -password pass:$pfxPassword } # 如果对象path不为空且存在,将证书拷贝到项目路径下 if (![string]::IsNullOrEmpty($currPath)) { Write-Host 拷贝$domain 证书文件到项目目录 Copy-Item -Path $commonKeyPath -Destination "$($currPath)\$($domain).key" -Force Copy-Item -Path $commonPfxPath -Destination "$($currPath)\$($domain).pfx" -Force Copy-Item -Path $commonPemPath -Destination "$($currPath)\$($domain).pem" -Force }}foreach ($curr in $data) { # 每次弄新的,就重置次数 $retryCnt = 0 try { # 登录到cygwin使用acme.sh签发证书,并将文件拷贝到公共证书目录,并转成pfx格式,密码统一使用$pfxPassword Write-Host 地址 $curr.path Write-Host 签发 $curr.domain 证书 IssueKey -currDomain $curr.domain -currPath $curr.path -force $false } catch { Write-Host "发生异常:$_" break }}# 执行完后退出exit
2.iis分配证书脚本,请保存在 iis批量重新分配证书.ps1
文件中
# 使用前先将策略设置为不严格 Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser# 保证证书有效的情况下再运行次脚本,将证书名称、证书目录、密钥放入以下数组# 公共证书密钥$pfxpassword = "dgfdgsdfg"# 公共证书路径$pfxCommandDir= "E:\cert"# 域名$domain="test.com"# 服务器上的证书与端口映射关系$data = @( [pscustomobject]@{subDomain = '*';port=443} [pscustomobject]@{subDomain = 'buy';port=8443} [pscustomobject]@{subDomain = 'go';port=7443})$certRootStore = "LocalMachine"$certStore = "My"# 创建证书存储$store = new-object System.Security.Cryptography.X509Certificates.X509Store($certStore, $certRootStore) $store.open("MaxAllowed")# 开始循环数组操作foreach ($element in $data) { $currDomain=$element.subDomain.Replace("*","_"); $pfxPath = "$($pfxCommandDir)\$($currDomain).$($domain).pfx" Write-Host $pfxPath # 创建pfx对象 try { $certificateObject = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($pfxPath, $pfxpassword) if (!$certificateObject.Verify()) { Write-Host $element.subDomain证书验证失败, 请检查相关配置 break } else { Write-Host 证书验证成功 } # 存储证书到个人 if (!$store.Certificates.Contains($certificateObject)) { $store.Add($certificateObject) Write-Host 导入证书成功 } $newThumbprint = $certificateObject.Thumbprint Write-Host 获取证书信息成功 $guid = [System.Guid]::NewGuid() $applicationID = "{$($guid)}" $addr = "0.0.0.0:$($element.port)" Write-Host $addr $newThumbprint # netsh删除原有监听端口 netsh http delete sslcert ipport=$addr # netsh添加端口 netsh http add sslcert ipport=$addr certhash=$newThumbprint appid=$applicationID # 如果对象path不为空且存在,将证书拷贝到项目路径下 if (![string]::IsNullOrEmpty($element.path)) { $dest = "$($element.path)\$($currDomain).$($domain).pfx" Copy-Item -Path $pfxPath -Destination $dest -Force Write-Host 拷贝文件到项目目录成功 } } catch { Write-Host "发生异常:$_" break }}# 关闭证书存储$store.close() # 执行完后退出exit
在常规页面中,勾选“只在用户登录时运行”以及“使用最高权限”,保存即可
任务计划程序是按照顺序执行的。
任务计划程序设置界面效果最终如图
以Windows Server 2008R2所示: