如何通过msg命令向服务器所有用户发送交互弹窗并捕获响应?
实现方案
msg.exe从设计上就是单向通知工具,没有提供返回用户交互结果的接口,无法直接捕获用户选择。要实现给所有在线用户推送可捕获返回值的确认弹窗,核心思路是把你已经写好的带交互逻辑的PowerShell脚本,直接投递到每个活跃用户会话内执行,不需要依赖msg做交互。
方案1:基于psexec投递(运维场景最常用,稳定性高)
这个方案无复杂配置,弹窗效果和你本地测试的Wscript.Shell弹窗完全一致,支持30秒超时、置顶模态、返回值捕获。
- 第一步:枚举服务器上所有处于活跃状态的用户会话ID,用系统自带的
query session命令即可解析:# 提取所有状态为Active的用户会话ID $activeSessions = query session | Where-Object { $_ -match '^(\s+)?[^\s]+\s+\d+\s+Active' } | ForEach-Object { $_.Split(' ', [StringSplitOptions]::RemoveEmptyEntries)[2] } - 第二步:把弹窗交互逻辑封装成独立脚本,存到所有用户可读的公共路径比如
C:\ProgramData\shutdown_confirm.ps1,加锁避免多用户重复调用取消API:# shutdown_confirm.ps1 内容 $lockFile = "C:\ProgramData\shutdown_cancel.lock" # 已有其他用户触发过取消则直接退出 if (Test-Path $lockFile) { exit } $wshell = New-Object -ComObject Wscript.Shell # 参数说明:30=超时秒数,0x4=显示是/否按钮,0x20=问号图标,0x1000=系统置顶模态窗 $result = $wshell.Popup( "服务器已触发关机流程,您是否仍在工作?`n本提示30秒后将自动判定您正在工作,取消本次关机", 30, "关机操作确认", 0x4 + 0x20 + 0x1000 ) # 返回值6=点击「是(我在工作)」,-1=超时无操作,两种情况均触发取消 if ($result -eq 6 -or $result -eq -1) { New-Item -Path $lockFile -ItemType File -Force | Out-Null $postParams = @{ trigger = "user_confirm_or_timeout" } Invoke-WebRequest -Uri '替换为你的取消关机API地址' -Method POST -Body $postParams -UseBasicParsing } - 第三步:遍历所有活跃会话,用psexec把脚本投递到对应会话的用户桌面运行:
# 提前清理历史锁文件 Remove-Item "C:\ProgramData\shutdown_cancel.lock" -Force -ErrorAction SilentlyContinue foreach ($sessionId in $activeSessions) { # -i 指定运行的会话ID,-d 不等待进程返回,避免阻塞其他会话的脚本投递 psexec -i $sessionId -d powershell.exe -ExecutionPolicy Bypass -File "C:\ProgramData\shutdown_confirm.ps1" }
方案2:无第三方工具依赖(原生计划任务投递)
如果不想使用psexec,可以用系统自带的计划任务功能完成脚本投递,核心交互逻辑和方案1完全一致,只需要把投递步骤替换为遍历会话创建临时计划任务即可:
foreach ($sessionId in $activeSessions) { $taskName = "TempShutdownConfirm_$sessionId" # 创建绑定指定会话、仅用户交互时运行的临时任务 schtasks /create /tn $taskName /sc once /st 00:00 /ru "Users" /it /tr "powershell.exe -ExecutionPolicy Bypass -File C:\ProgramData\shutdown_confirm.ps1" /f | Out-Null # 立即执行任务 schtasks /run /tn $taskName | Out-Null # 执行完成后自动删除临时任务 Start-Sleep -Seconds 1 schtasks /delete /tn $taskName /f | Out-Null }
注意事项
- 不要尝试hack msg命令获取返回值,该工具内部没有实现选择结果的输出接口,所有相关尝试都无法稳定生效。
- 弹窗务必加
0x1000系统模态参数,避免被用户打开的其他窗口遮挡导致看不到提示。 - 注意核对Popup返回值和按钮的对应关系:返回6为点击「是」,返回7为点击「否」,返回-1为超时,可根据自己的文案调整判断逻辑,不要搞反触发条件。
- 锁文件机制必须保留,避免多用户同时触发时重复调用取消API。
内容的提问来源于stack exchange,提问作者Mochael_DLite
相关产品推荐
相关产品推荐

