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

如何在PowerShell中捕获RabbitMQ卸载时的分离子进程

RabbitMQ无人值守卸载的进程等待问题

问题背景

在Windows系统中使用PowerShell执行RabbitMQ无人值守卸载时,通过注册表获取卸载字符串并启动进程,但遇到以下问题:

初始执行代码:

$RABBITMQ_PRODUCT_NAME = "RabbitMQ Server"
$rabbitMq = Get-ChildItem -Path HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall `
| Get-ItemProperty `
| Where-Object { $_.DisplayName -match $RABBITMQ_PRODUCT_NAME }
$rabbitUninstallProcess = Start-Process -FilePath $rabbitMq.UninstallString -ArgumentList "/S" -PassThru -ErrorAction Stop
# 无法使用-Wait参数,否则会无限挂起,因此需获取进程后调用WaitForExit。
$rabbitUninstallProcess.WaitForExit()

这段代码的问题是:$rabbitUninstallProcess启动真实卸载进程后就会立即退出,导致脚本在卸载完成前就收到成功状态码。

虽然可以通过进程名Un_A结合产品名称匹配找到真实卸载进程,但存在竞态条件,无法保证找到的进程就是当前启动的卸载流程创建的:

$UNINSTALL_PROCESS_NAME = "Un_A"
$process = Get-Process -Name $UNINSTALL_PROCESS_NAME `
| Where-Object { $_.Product -match $RABBITMQ_PRODUCT_NAME }
$process.WaitForExit()

完整脚本(含Erlang卸载逻辑)

$RABBITMQ_PRODUCT_NAME = "RabbitMQ Server"
$ERLANG_PRODUCT_NAME = "Erlang OTP"
$UNINSTALL_PROCESS_NAME = "Un_A"
$FAILURE = 9

$rabbitMq = Get-ChildItem -Path HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall `
| Get-ItemProperty `
| Where-Object { $_.DisplayName -match $RABBITMQ_PRODUCT_NAME }

$erlang = Get-ChildItem -Path HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall `
| Get-ItemProperty `
| Where-Object { $_.DisplayName -match $ERLANG_PRODUCT_NAME }

$rabbitMQDataDir = $env:RABBITMQ_BASE
if ($rabbitMq) {
  $installedRabbitMQVersion = $rabbitMq.DisplayVersion
  Write-Host "Removing $RABBITMQ_PRODUCT_NAME v$installedRabbitMQVersion"

  # 无法使用-Wait参数,否则会无限挂起,因此需获取进程后调用WaitForExit。
  $rabbitUninstallProcess = Start-Process -FilePath $rabbitMq.UninstallString -ArgumentList "/S" -PassThru -ErrorAction Stop
  # 该进程仅启动真实卸载进程,因此需等待其退出后再查找卸载进程
  $rabbitUninstallProcess.WaitForExit()
  # RabbitMQ的卸载程序(来自Nullsoft)进程名为"Un_A"。
  # Product属性用于识别该卸载进程属于RabbitMQ。
  # 存在竞态条件:能否在进程结束前找到它?通常可以,但仍存在风险。
  $process = Get-Process -Name $UNINSTALL_PROCESS_NAME `
  | Where-Object { $_.Product -match $RABBITMQ_PRODUCT_NAME }

  if ($process) {
    Write-Host "Waiting for uninstall process to finish"
    $process.WaitForExit()
  } else {
    # 如果未找到卸载进程,但进程实际在运行且卸载在脚本失败后完成,再次运行脚本可继续处理
    Write-Host "Didn't find an uninstall process. Going to sleep then check if the uninstall happened. If RabbitMQ is still installed, it will fail after the re-check."
    Start-Sleep -Seconds 60
  }
  $rabbitMqStillThere = Get-ChildItem HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall `
  | Get-ItemProperty `
  | Where-Object { $_.DisplayName -match $RABBITMQ_PRODUCT_NAME }

  if ($rabbitMqStillThere) {
    Write-Host "Unable to uninstall RabbitMQ. You may have to uninstall manually."
    exit $FAILURE
  } else {
    Write-Host "$($rabbitMq.DisplayName) has been uninstalled."
  }
} else {
  Write-Host "$RABBITMQ_PRODUCT_NAME not installed moving on."
}
# 需要清理RabbitMQ数据目录。
if([string]::IsNullOrWhiteSpace($rabbitMQDataDir)){
  # 如果未设置环境变量,使用默认路径。
  $rabbitMQDataDir = "C:\ProgramData\RabbitMQ"
}
if (Test-Path -Path $rabbitMQDataDir -PathType Container) {
  Write-Host "Removing RabbitMQ Data Dir $rabbitMQDataDir"
  Remove-Item -Path $rabbitMQDataDir -Recurse -Force -ErrorAction Stop
}

# 现在卸载Erlang。
if ($erlang) {
  $installedErlangVersion = $erlang.DisplayVersion
  Write-Host "Removing $ERLANG_PRODUCT_NAME v$installedErlangVersion"
  # Erlang卸载可正常使用-Wait参数
  $erlangUninstallProcess = Start-Process -FilePath $erlang.UninstallString -ArgumentList "/S" -PassThru -Wait -ErrorAction Stop
  if ($erlangUninstallProcess.ExitCode -ne 0) {
    Write-Host "Error Removing Erlang "
    exit $FAILURE
  } else {
    Write-Host "$($erlang.DisplayName) has been uninstalled."
  }
} else {
  Write-Host "$ERLANG_PRODUCT_NAME not installed moving on"
}

预期与实际情况

预期

  • 直接通过RabbitMQ卸载字符串启动的进程即为真实卸载进程,或能获取其句柄
  • 可以使用-Wait参数等待该进程完成,以确认卸载成功或失败

实际

  • 使用Start-Process -Wait会无限挂起
  • 使用Start-Process -PassThru获取进程句柄后调用WaitForExit(),该进程会在启动真实卸载进程后立即退出并返回成功状态
  • 无法确定性地找到由Start-Process启动的子进程/后代进程

内容的提问来源于stack exchange,提问作者Eric-R

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 04:52:17