Jenkins通过sshCommand执行PowerShell脚本实现类nohup后台运行
核心原因
Windows 原生OpenSSH服务默认会把单次SSH会话启动的所有进程绑定到当前会话的作业对象(Job Object),会话断开时系统会自动强制终止该作业对象下的全部进程,这是会话关闭后服务全挂的根本原因。不需要开发Windows服务,用系统自带功能就能实现类nohup的持久运行效果,成本极低。
方案1:零改造成本,Start-Process脱离进程树
不需要修改原有run_services.ps1的任何逻辑,直接调整SSH执行的命令即可。Start-Process启动的新进程会默认脱离当前会话的进程树和作业对象,不会随会话断开被清理:
sshCommand remote: remote_server, command: "powershell.exe -WindowStyle Hidden -Command "Start-Process powershell.exe -ArgumentList '-ExecutionPolicy Bypass -File C:/run_services.ps1' -WindowStyle Hidden -RedirectStandardOutput C:/service_std.log -RedirectStandardError C:/service_err.log""
- 附带的日志重定向参数和Linux下nohup默认输出到
nohup.out的效果完全一致,所有控制台输出都会落到指定文件方便排查 - 不要给
Start-Process加-Wait参数,加了会阻塞等待脚本执行完成,进程会重新绑定到当前SSH会话,断连还是会被杀 - 适合临时快速启动服务的场景,改完命令直接生效
方案2:最高稳定性,计划任务启动(完全会话隔离)
如果需要服务完全不受SSH断连、用户注销的影响,甚至要开机自启,直接用系统内置的计划任务实现,全程两行命令,不需要额外编码:
通过SSH执行以下命令即可:
# 创建最高权限运行的一次性计划任务 schtasks /create /tn "PersistentPortServices" /tr "powershell.exe -ExecutionPolicy Bypass -File C:\run_services.ps1" /sc once /st 00:00 /ru SYSTEM /rl highest /f # 立即触发任务执行 schtasks /run /tn "PersistentPortServices"
- 该方式启动的进程运行在独立系统会话下,和SSH登录会话完全解耦,无论SSH怎么断开、用户是否注销,进程都会持续运行
- 如果需要开机自动启动这些服务,只需要把创建任务参数里的
/sc once /st 00:00替换为/sc onstart即可,不需要额外调整 - 后续要停服时,直接在服务器上结束对应进程,或者执行
schtasks /delete /tn "PersistentPortServices" /f删除任务即可
避坑说明
- 不要用
Start-Job、Invoke-Command这类在当前PowerShell运行空间内启动进程的命令,这类方式启动的进程属于当前会话,断连必然被终止 - 不需要下载第三方移植的nohup类工具,这类工具大多存在作业对象绑定的兼容问题,上述两个方案全是Windows原生能力,无任何额外依赖
- 即使你原有脚本里是用前台方式启动的各个端口服务,上述两个方案也能正常实现持久化,不需要修改脚本内的服务启动逻辑
内容的提问来源于stack exchange,提问作者Narek Hambardzumyan
相关产品推荐
相关产品推荐

