1、打开Jenkins,选择新建Item

2、填写项目名称,选择自由风格,点击确定

3、勾选This project is parameterized,开始设置参数


先看下这几种参数类型:常用的就几种,本文中用到的就
Choice Parameter:选择型参数
String Parameter:字符串参数
4、我们开始添加参数

这样以此类推,下面把参数都列举一下
分支名称-选择参数:
BRANCH_NAME master 分支名称
编译方式-选择参数:
COMPILE_MODE Debug Release 编译方式
启动项目所在文件夹-字符串参数:
PROJECT_START_PATH src/JwtDemoApi 启动项目文件夹
主版本号-字符串参数:
MAJOR_NO 1 主版本号
次版本号-字符串参数:
BUILD_NO 1 次版本号
IIS站点名称-字符串参数:
SITE_NAME JwtDemoApi IIS站点名称
IIS站点端口号-字符串参数:
SITE_PORT 809 IIS站点端口号
IIS发布站点绝对路径-字符串参数:
SITE_PUBLISH_PATH E:\WebSite\WebSite_JwtDemoApi IIS发布站点绝对路径(结尾不带斜杠,vs发布的路径/临时发布文件夹)
IIS运行地址绝对路径-字符串参数:
SITE_RUN_PATH E:\Feature\Host IIS运行站点绝对路径(结尾不带斜杠,IIS运行的就是这个目录下的文件,需要手动加一个Config文件夹,启用这个文件下的配置文件)
IIS绑定的域名-字符串参数:
SITE_HOST baidu.com IIS站点绑定的域名
5、配置源码管理-git

Repository URL:填你的git仓库地址
Credentials:添加一个能拉取操作你git仓库的账号
指定分支:${BRANCH_NAME},这里填写的变量
6、构建-增加构建步骤,选择Execute Windows Batch Command(执行windows bat命令)

脚本V1-简单暴力版本,直接重新发布,删除iis站点,重新创建
chcp 65001 > nul echo "进入目录" cd %PROJECT_START_PATH% echo "还原项目包" dotnet restore rem dotnet restore -s "https://api.nuget.org/v3/index.json" -s "https://jhrs.com/lib/nuget" echo "编译代码" dotnet build -c "%COMPILE_MODE%" echo "停止IIS站点" C:\Windows\System32\inetsrv\appcmd.exe stop site "%SITE_NAME%" C:\Windows\System32\inetsrv\appcmd.exe stop appPool /appPool.name:"%SITE_NAME%" echo "删除现有文件,重新发布" del /f /s /q %SITE_PUBLISH_PATH%\*.* echo "发布项目" dotnet publish -c %COMPILE_MODE% -r win-x64 --self-contained true -o "%SITE_PUBLISH_PATH%" echo "新建版本号" md "%SITE_RUN_PATH%\%MAJOR_NO%.%BUILD_NO%.%BUILD_ID%" echo "拷贝项目到当前版本" xcopy %SITE_PUBLISH_PATH% %SITE_RUN_PATH%\%MAJOR_NO%.%BUILD_NO%.%BUILD_ID% /s/e/y echo "拷贝指定文件夹的配置文件" xcopy %SITE_RUN_PATH%\Config %SITE_RUN_PATH%\%MAJOR_NO%.%BUILD_NO%.%BUILD_ID% /s/e/y echo "删除站点" C:\Windows\System32\inetsrv\appcmd.exe delete site "%SITE_NAME%" C:\Windows\System32\inetsrv\appcmd.exe delete apppool "%SITE_NAME%" echo "新建站点" C:\Windows\System32\inetsrv\appcmd.exe add site /name:"%SITE_NAME%" /bindings:http://*:%SITE_PORT% /physicalpath:"%SITE_RUN_PATH%\%MAJOR_NO%.%BUILD_NO%.%BUILD_ID%" C:\Windows\System32\inetsrv\appcmd.exe add AppPool /name:"%SITE_NAME%" C:\Windows\System32\inetsrv\appcmd.exe Set app "%SITE_NAME%/" /applicationpool:"%SITE_NAME%" C:\Windows\System32\inetsrv\appcmd.exe set apppool /apppool.name:"%SITE_NAME%" /managedRuntimeVersion:"" echo "启动项目" C:\Windows\System32\inetsrv\appcmd.exe start site "%SITE_NAME%" C:\Windows\System32\inetsrv\appcmd.exe start appPool /appPool.name:"%SITE_NAME%" C:\Windows\System32\inetsrv\appcmd.exe recycle appPool /appPool.name:"%SITE_NAME%"
脚本V2-支持绑定域名和iis证书
@echo off
setlocal EnableExtensions DisableDelayedExpansion
if defined DEPLOY_UTF8_READY goto :main
chcp 65001 >nul
set "DEPLOY_UTF8_READY=1"
call "%~f0" %*
exit /b %errorlevel%
:main
for %%V in (PROJECT_START_PATH COMPILE_MODE SITE_NAME SITE_PORT SITE_PUBLISH_PATH SITE_RUN_PATH MAJOR_NO BUILD_NO THR_NO) do (
if not defined %%V (
echo [错误] 缺少环境变量:%%V
exit /b 1
)
)
set "APPCMD=%windir%\System32\inetsrv\appcmd.exe"
set "VERSION=%MAJOR_NO%.%BUILD_NO%.%THR_NO%"
set "VERSION_PATH=%SITE_RUN_PATH%\%VERSION%"
if not defined SITE_HOST set "SITE_HOST=这是你的域名"
set "SITE_HTTP_PORT=80"
set "SITE_HTTPS_PORT=443"
set "BUILD_ARTIFACTS_PATH=%SITE_PUBLISH_PATH%"
set "FINDSTR=%SystemRoot%\System32\findstr.exe"
if "%SITE_PORT%"=="%SITE_HTTP_PORT%" (
echo [错误] SITE_PORT 是额外监听端口,不能与域名 HTTP 端口 %SITE_HTTP_PORT% 相同
exit /b 1
)
if "%SITE_PORT%"=="%SITE_HTTPS_PORT%" (
echo [错误] SITE_PORT 是额外监听端口,不能与域名 HTTPS 端口 %SITE_HTTPS_PORT% 相同
exit /b 1
)
if not exist "%APPCMD%" (
echo [错误] 未找到 AppCmd:%APPCMD%
exit /b 1
)
echo ============================================================
echo [开始] %date% %time%
echo [信息] 站点名称:%SITE_NAME%
echo [信息] 发布版本:%VERSION%
echo [信息] 域名 HTTP 端口:%SITE_HTTP_PORT%
echo [信息] 域名 HTTPS 端口:%SITE_HTTPS_PORT%
echo [信息] 额外 HTTP 监听端口:%SITE_PORT%(不绑定域名)
echo ============================================================
echo [1/10] 还原程序
echo [信息] 项目目录:%PROJECT_START_PATH%
echo [信息] 编译模式:%COMPILE_MODE%
echo [信息] 目标运行时:win-x64
cd /d "%PROJECT_START_PATH%" || goto :fail
set "MSBUILDDISABLENODEREUSE=1"
dotnet restore --runtime win-x64 || goto :fail
echo [完成] 程序还原成功
echo [2/10] 停止 IIS 站点和应用程序池
echo [信息] IIS 站点:%SITE_NAME%
"%APPCMD%" list site /name:"%SITE_NAME%" /text:name 2>nul | "%FINDSTR%" /x "%SITE_NAME%" >nul
if not errorlevel 1 (
echo [信息] 站点已存在,正在停止
call :StopSiteAndWait "%SITE_NAME%" 5 2
if errorlevel 1 (
echo [错误] 停止站点超时或失败
goto :fail
)
) else (
echo [跳过] IIS 站点不存在
)
"%APPCMD%" list apppool /name:"%SITE_NAME%" /text:name 2>nul | "%FINDSTR%" /x "%SITE_NAME%" >nul
if not errorlevel 1 (
echo [信息] 应用程序池已存在,正在停止
call :StopAppPoolAndWait "%SITE_NAME%" 5 2
if errorlevel 1 (
echo [错误] 停止应用程序池超时或失败
goto :fail
)
) else (
echo [跳过] IIS 应用程序池不存在
)
echo [完成] IIS 停止检查完成
echo [3/10] 删除现有文件
echo [信息] 临时发布目录:%SITE_PUBLISH_PATH%
if exist "%SITE_PUBLISH_PATH%\." (
echo [信息] 正在删除临时发布目录
rmdir /s /q "%SITE_PUBLISH_PATH%" || goto :fail
) else (
echo [跳过] 临时发布目录不存在
)
echo [信息] 版本运行目录:%VERSION_PATH%
if exist "%VERSION_PATH%\." (
echo [信息] 正在删除现有版本目录
rmdir /s /q "%VERSION_PATH%" || goto :fail
) else (
echo [跳过] 现有版本目录不存在
)
echo [信息] 正在创建临时发布目录
md "%SITE_PUBLISH_PATH%" || goto :fail
echo [完成] 现有文件清理完成
echo [4/10] 发布项目到指定目录
echo [信息] 发布目标:%SITE_PUBLISH_PATH%
echo [信息] 自包含发布:true
dotnet publish -c "%COMPILE_MODE%" --runtime win-x64 --self-contained true --no-restore -o "%SITE_PUBLISH_PATH%" || goto :fail
echo [完成] 项目发布成功
echo [5/10] 拷贝项目文件到运行目录
echo [信息] 来源:%SITE_PUBLISH_PATH%
echo [信息] 目标:%VERSION_PATH%
md "%VERSION_PATH%" || goto :fail
set "VERSION_DIR_CREATED=1"
xcopy "%SITE_PUBLISH_PATH%\*" "%VERSION_PATH%\" /s /e /y /i
if errorlevel 1 goto :fail
echo [完成] 项目文件拷贝成功
echo [6/10] 拷贝配置文件到运行目录
echo [信息] 配置来源:%SITE_RUN_PATH%\Config
echo [信息] 配置目标:%VERSION_PATH%
if exist "%SITE_RUN_PATH%\Config\." (
echo [信息] 正在覆盖运行目录中的配置
xcopy "%SITE_RUN_PATH%\Config\*" "%VERSION_PATH%\" /s /e /y /i
if errorlevel 1 goto :fail
) else (
echo [跳过] 配置目录不存在
)
echo [完成] 配置文件处理完成
echo [7/10] 删除 IIS 站点和应用程序池
"%APPCMD%" list site /name:"%SITE_NAME%" /text:name 2>nul | "%FINDSTR%" /x "%SITE_NAME%" >nul
if not errorlevel 1 (
echo [信息] 正在删除 IIS 站点:%SITE_NAME%
"%APPCMD%" delete site "%SITE_NAME%" || goto :fail
) else (
echo [跳过] IIS 站点不存在
)
"%APPCMD%" list apppool /name:"%SITE_NAME%" /text:name 2>nul | "%FINDSTR%" /x "%SITE_NAME%" >nul
if not errorlevel 1 (
echo [信息] 正在删除 IIS 应用程序池:%SITE_NAME%
"%APPCMD%" delete apppool "%SITE_NAME%" || goto :fail
) else (
echo [跳过] IIS 应用程序池不存在
)
echo [完成] IIS 站点和应用程序池删除完成
echo [8/10] 创建 IIS 应用程序池和站点
echo [信息] 正在创建应用程序池:%SITE_NAME%
"%APPCMD%" add apppool /name:"%SITE_NAME%" || goto :fail
"%APPCMD%" set apppool /apppool.name:"%SITE_NAME%" /managedRuntimeVersion:"" || goto :fail
echo [信息] 正在创建站点:%SITE_NAME%
echo [信息] 站点物理路径:%VERSION_PATH%
echo [信息] 初始监听:http://*:%SITE_PORT%
"%APPCMD%" add site /name:"%SITE_NAME%" /bindings:"http/*:%SITE_PORT%:" /physicalPath:"%VERSION_PATH%" || goto :fail
"%APPCMD%" set app "%SITE_NAME%/" /applicationPool:"%SITE_NAME%" || goto :fail
echo [完成] IIS 应用程序池和站点创建成功
echo [9/10] 绑定 HTTP、HTTPS 域名和证书
echo [信息] HTTP 域名绑定:http://%SITE_HOST%:%SITE_HTTP_PORT%
echo [信息] HTTPS 绑定:https://%SITE_HOST%:%SITE_HTTPS_PORT%
echo [信息] 正在添加 HTTP 域名绑定
"%APPCMD%" set site /site.name:"%SITE_NAME%" /+bindings.[protocol='http',bindingInformation='*:%SITE_HTTP_PORT%:%SITE_HOST%'] || goto :fail
echo [信息] 正在添加 HTTPS SNI 绑定
"%APPCMD%" set site /site.name:"%SITE_NAME%" /+bindings.[protocol='https',bindingInformation='*:%SITE_HTTPS_PORT%:%SITE_HOST%',sslFlags='1'] || goto :fail
echo [信息] 正在从 Cert:\LocalMachine\My 和 Cert:\LocalMachine\WebHosting 检索并绑定证书
call :BindHttpsCertificate "%SITE_HOST%" "%SITE_HTTPS_PORT%"
if errorlevel 1 goto :fail
echo [完成] HTTP、HTTPS 域名和证书绑定成功
echo [10/10] 启动 IIS 应用程序池和站点
echo [信息] 正在启动应用程序池:%SITE_NAME%
"%APPCMD%" start apppool /apppool.name:"%SITE_NAME%" || goto :fail
echo [信息] 正在启动站点:%SITE_NAME%
"%APPCMD%" start site /site.name:"%SITE_NAME%" || goto :fail
echo [完成] IIS 应用程序池和站点启动成功
echo [成功] 发布完成
echo [结束] %date% %time%
echo [信息] 版本:%VERSION%
echo [信息] 运行目录:%VERSION_PATH%
echo [信息] HTTP 地址:http://%SITE_HOST%:%SITE_HTTP_PORT%
echo [信息] 访问地址:https://%SITE_HOST%:%SITE_HTTPS_PORT%
echo [信息] 额外监听:http://服务器IP:%SITE_PORT%
exit /b 0
:fail
set "FAIL_CODE=%errorlevel%"
if "%FAIL_CODE%"=="0" set "FAIL_CODE=1"
echo [失败时间] %date% %time%
echo [错误] 发布失败,退出码:%FAIL_CODE%
if defined BUILD_ARTIFACTS_PATH if exist "%BUILD_ARTIFACTS_PATH%\." (
echo [清理] 删除临时发布目录:%BUILD_ARTIFACTS_PATH%
rmdir /s /q "%BUILD_ARTIFACTS_PATH%"
)
if defined VERSION_DIR_CREATED if exist "%VERSION_PATH%\." (
echo [清理] 删除未完成的版本目录:%VERSION_PATH%
rmdir /s /q "%VERSION_PATH%"
)
echo [错误] 发布流程已终止
exit /b 1
rem ========== 子过程:按域名检索 LocalMachine\My/WebHosting 证书并绑定到 SNI 端点 ==========
:BindHttpsCertificate
setlocal
set "HTTPS_HOST=%~1"
set "HTTPS_PORT=%~2"
powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "$ErrorActionPreference='Stop'; $hostName=$env:HTTPS_HOST; $port=$env:HTTPS_PORT; $now=Get-Date; function Test-DnsName([string]$pattern,[string]$name) { if ($pattern -ieq $name) { return $true }; if ($pattern.StartsWith('*.')) { $suffix=$pattern.Substring(1); if ($name.EndsWith($suffix,[StringComparison]::OrdinalIgnoreCase)) { $prefix=$name.Substring(0,$name.Length-$suffix.Length); return $prefix.Length -gt 0 -and $prefix.IndexOf('.') -lt 0 } }; return $false }; $certPaths=@('Cert:\LocalMachine\My','Cert:\LocalMachine\WebHosting'); $certMatches=@(Get-ChildItem -Path $certPaths -ErrorAction SilentlyContinue | Where-Object { $candidate=$_; if (-not $candidate.HasPrivateKey -or $candidate.NotBefore -gt $now -or $candidate.NotAfter -le $now) { return $false }; $names=@($candidate.DnsNameList | ForEach-Object { $_.Unicode }); if ($names.Count -eq 0 -and $candidate.Subject -match '(?:^|,\s*)CN=([^,]+)') { $names=@($Matches[1].Trim()) }; foreach ($name in $names) { if (Test-DnsName $name $hostName) { return $true } }; return $false } | Sort-Object NotAfter -Descending); if ($certMatches.Count -eq 0) { throw ('在 Cert:\LocalMachine\My 和 Cert:\LocalMachine\WebHosting 中未找到域名 {0} 的有效且带私钥证书' -f $hostName) }; $cert=$certMatches[0]; $certStoreName=if ($cert.PSParentPath -match '\\WebHosting$') { 'WebHosting' } else { 'MY' }; $endpoint=('{0}:{1}' -f $hostName,$port); $appId='{4dc3e181-e14b-4a21-b022-59fc669b0914}'; & netsh.exe http show sslcert ('hostnameport={0}' -f $endpoint) *> $null; if ($LASTEXITCODE -eq 0) { & netsh.exe http update sslcert ('hostnameport={0}' -f $endpoint) ('certhash={0}' -f $cert.Thumbprint) ('appid={0}' -f $appId) ('certstorename={0}' -f $certStoreName) | Out-Host } else { & netsh.exe http add sslcert ('hostnameport={0}' -f $endpoint) ('certhash={0}' -f $cert.Thumbprint) ('appid={0}' -f $appId) ('certstorename={0}' -f $certStoreName) | Out-Host }; if ($LASTEXITCODE -ne 0) { throw ('HTTPS 证书绑定失败,netsh 退出码:{0}' -f $LASTEXITCODE) }; Write-Host ('已绑定证书:{0},证书存储:LocalMachine\{1},有效期至:{2:yyyy-MM-dd HH:mm:ss}' -f $cert.Subject,$certStoreName,$cert.NotAfter)"
if errorlevel 1 (
echo [错误] HTTPS 证书检索或绑定失败
exit /b 1
)
exit /b 0
rem ========== 子过程:停止站点并等待完全停止 ==========
:StopSiteAndWait
setlocal
set "SITE_NAME=%~1"
set "MAX_RETRIES=%~2"
set "SLEEP_SEC=%~3"
if "%MAX_RETRIES%"=="" set "MAX_RETRIES=5"
if "%SLEEP_SEC%"=="" set "SLEEP_SEC=2"
rem 先检查当前状态,如果已经是 Stopped 则直接返回成功
"%APPCMD%" list site /name:"%SITE_NAME%" /text:state 2>nul | "%FINDSTR%" /i "Stopped" >nul
if not errorlevel 1 (
echo 站点 %SITE_NAME% 已处于停止状态
exit /b 0
)
rem 尝试停止(忽略错误,因为可能正在停止或已停)
"%APPCMD%" stop site /site.name:"%SITE_NAME%" >nul 2>&1
set /a retry=0
:stop_site_loop
set /a display_retry=retry+1
echo [等待] 站点停止状态检查 %display_retry%/%MAX_RETRIES%,%SLEEP_SEC% 秒后重试
timeout /t %SLEEP_SEC% /nobreak >nul
"%APPCMD%" list site /name:"%SITE_NAME%" /text:state 2>nul | "%FINDSTR%" /i "Stopped" >nul
if not errorlevel 1 (
echo 站点 %SITE_NAME% 已成功停止
exit /b 0
)
set /a retry+=1
if %retry% lss %MAX_RETRIES% goto :stop_site_loop
echo 警告:停止站点 %SITE_NAME% 超时,当前状态:
"%APPCMD%" list site /name:"%SITE_NAME%" /text:state
exit /b 1
rem ========== 子过程:停止应用程序池并等待完全停止 ==========
:StopAppPoolAndWait
setlocal
set "APPPOOL_NAME=%~1"
set "MAX_RETRIES=%~2"
set "SLEEP_SEC=%~3"
if "%MAX_RETRIES%"=="" set "MAX_RETRIES=5"
if "%SLEEP_SEC%"=="" set "SLEEP_SEC=2"
"%APPCMD%" list apppool /name:"%APPPOOL_NAME%" /text:state 2>nul | "%FINDSTR%" /i "Stopped" >nul
if not errorlevel 1 (
echo 应用程序池 %APPPOOL_NAME% 已处于停止状态
exit /b 0
)
"%APPCMD%" stop apppool /apppool.name:"%APPPOOL_NAME%" >nul 2>&1
set /a retry=0
:stop_apppool_loop
set /a display_retry=retry+1
echo [等待] 应用程序池停止状态检查 %display_retry%/%MAX_RETRIES%,%SLEEP_SEC% 秒后重试
timeout /t %SLEEP_SEC% /nobreak >nul
"%APPCMD%" list apppool /name:"%APPPOOL_NAME%" /text:state 2>nul | "%FINDSTR%" /i "Stopped" >nul
if not errorlevel 1 (
echo 应用程序池 %APPPOOL_NAME% 已成功停止
exit /b 0
)
set /a retry+=1
if %retry% lss %MAX_RETRIES% goto :stop_apppool_loop
echo 警告:停止应用程序池 %APPPOOL_NAME% 超时,当前状态:
"%APPCMD%" list apppool /name:"%APPPOOL_NAME%" /text:state
exit /b 17、编译如果提示nuget 不存在则在工作目录新建 nuget.config文件,因为你的项目中,可能引用的dll来自你私有nuget

8、自动构建,根据仓库的变化,自动构建。

Poll SCM:设置定时检查代码仓库是否有变更,有变更则构建
定时构建语法
* * * * *
第一个*表示分钟,取值0~59
第二个*表示小时,取值0~23
第三个*表示一个月的第几天,取值1~31
第四个*表示第几月,取值1~12
第五个*表示一周中的第几天,取值0~7,其中0和7代表的都是周日
H开头是定时构建,不带H的定时检查,有变化才构建
每隔5分钟构建一次
H/5 * * * *
每两小时构建一次
H H/2 * * *
每天中午下班前定时构建一次
0 12 * * *
每天下午下班前定时构建一次
0 18 * * *
每15分钟构建一次:H/15 * * * * 或*/5 * * * *
每天8点构建一次:0 8 * * *
每天8点~17点,两小时构建一次:0 8-17/2 * * *
周一到周五,8点~17点,两小时构建一次:0 8-17/2 * * 1-5
每月1号、15号各构建一次,除12月:H H 1,15 1-11 *
*/5 * * * * (每5分钟检查一次源码变化) 0 2 * * * (每天2:00 必须build一次源码)
9、手动触发

川公网安备 51010702003150号
留下您的脚步
最近评论