You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Azure DevOps交互式代理启动的进程在流水线作业结束后持续运行?

问题

需要通过Azure DevOps流水线将一个长期运行的C#可执行文件部署到Windows Server 2019机器上,要求:

  • 以提升权限运行
  • 必须在UI会话中运行(需调用无法在会话0中运行的外部应用)
  • 已使用交互式代理,但流水线作业结束后,可执行文件会被关闭,无法保持运行

复现流水线

以下YAML可复现该问题:

jobs:
- deployment: 
  environment: MyEnvironment.MyInteractiveAgent
  strategy:
    runOnce:
      deploy:
        steps:
        - powershell: Start-Process -Verb RunAs C:\Windows\notepad.exe

现象对比

  • 手动在目标机器上以流水线用户身份执行Start-Process -Verb RunAs C:\Windows\notepad.exe,关闭PowerShell窗口后记事本仍保持运行
  • 通过流水线执行相同命令,流水线作业结束后记事本会被关闭

进程树分析

使用PowerShell Core脚本查看进程父级关系:

$process = Get-Process notepad;

while ($process) {
    Write-Host "$($process.Id) - $($process.Name)";
    $process = $process.Parent;
}

结果对比:

手动启动进程树代理启动进程树
9812 - notepad3940 - notepad
3480 - powershell1676 - powershell
5004 - explorer11388 - powershell
1720 - Agent.Worker
15748 - Agent.Listener
14708 - cmd

可见代理启动的记事本属于Agent进程树的子进程,流水线结束时Agent会终止整个子进程树,导致程序关闭。

解决方案

要让进程脱离Azure DevOps代理的进程树,避免被作业结束时终止,可采用以下几种方法:

1. 创建Windows计划任务

通过schtasks命令创建立即执行的计划任务,让进程以独立的父进程(taskeng.exe)启动,脱离代理进程树:

# 获取当前活跃的UI会话ID(以explorer进程所属会话为例)
$sessionId = (Get-Process -Name explorer | Select-Object -First 1).SessionId

# 创建并立即执行计划任务,启动目标程序(替换为你的C#程序路径)
schtasks /create /tn "StartMyAppTask" /tr "C:\Windows\notepad.exe" /sc once /st 00:00 /ru "NT AUTHORITY\SYSTEM" /rl highest /f /sd 01/01/2000
schtasks /run /tn "StartMyAppTask"
# 可选:执行完成后删除临时任务
schtasks /delete /tn "StartMyAppTask" /f

若需指定特定用户会话,可添加/s $env:COMPUTERNAME /u <用户名> /p <密码>参数。

2. 使用NSSM将程序注册为服务(适配UI会话)

NSSM(Non-Sucking Service Manager)可将普通程序注册为Windows服务,同时支持指定运行的UI会话ID,让程序脱离代理进程树并长期运行:

# 假设NSSM已下载至C:\tools\nssm.exe
# 注册服务
C:\tools\nssm.exe install MyAppService "C:\Path\To\Your\CSharpApp.exe"
# 设置服务以最高权限运行
C:\tools\nssm.exe set MyAppService ObjectName "NT AUTHORITY\SYSTEM"
# 设置服务自动启动
C:\tools\nssm.exe set MyAppService Start SERVICE_AUTO_START
# 指定在UI会话1中运行(根据实际会话ID调整)
C:\tools\nssm.exe set MyAppService AppSessionId 1
# 启动服务
Start-Service MyAppService

此方法适合需要随系统自动启动的长期运行程序。

3. PowerShell 7+ 用-Detached参数启动进程

PowerShell 7及以上版本的Start-Process支持-Detached参数,可直接让进程脱离父进程树:

Start-Process -Verb RunAs -NoNewWindow -Detached C:\Windows\notepad.exe

需确保Azure DevOps代理使用的是PowerShell Core环境。

4. 使用PsExec在用户会话启动进程

通过PsExec工具在指定UI会话中启动进程,让进程归属到用户会话的进程树:

# 假设PsExec已下载至C:\tools\psexec.exe,目标会话ID为1
C:\tools\psexec.exe -i 1 -h C:\Windows\notepad.exe

-i指定会话ID,-h表示以最高权限运行。

内容的提问来源于stack exchange,提问作者Matthias Schuchardt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 19:46:30