PowerShell脚本手动运行正常 登出后后台作业无法发送Teams消息
故障排查方向及修复方案
核心故障原因(优先级从高到低)
Start-Job生命周期依赖父会话:这是最可能的根因。Start-Job创建的后台作业完全依附于启动它的PowerShell终端会话,Windows Server 2012默认RDP策略会在用户断开远程连接1-5分钟后自动销毁孤立的用户会话,会话销毁后所有关联的后台作业会被直接终止,自然跑不到发告警的逻辑。- 相对路径加载模块失败:你用
Import-Module message_module写的是相对路径,Start-Job启动子进程时默认工作目录是%USERPROFILE%\Documents,不是你脚本存放的目录,作业启动时根本找不到message_module模块,调用Send-TeamsMessage时会直接抛命令不存在的错误,只是你没捕获错误看不到而已。 - 用户上下文网络配置丢失:手动运行脚本时用的是你当前登录用户的上下文,你配置的代理、外网访问权限、防火墙白名单都是用户级的;当你断开RDP会话用户被注销后,后台作业拿不到这些用户级网络配置,调用Teams webhook时会出现网络不通、鉴权失败的问题。
- 顺带提一个脚本逻辑bug:你写的
$test_table.clear是方法引用,没有加括号执行,实际不会清空数组,运行时间长了在线率计算会完全失真,这个和发告警失败无关但需要修。
可落地的修复步骤
- 弃用
Start-Job跑长期驻留任务,改用Windows任务计划程序配置,这是Win2012上跑后台常驻脚本最稳定的方案:- 打开任务计划程序,新建任务
- 安全选项选择「不管用户是否登录都要运行」,运行账户选有外网访问权限的专用服务账号,或者直接选本地System账号(注意提前确认System账号能访问VPN目标和Teams webhook)
- 触发器设置为「系统启动时」,避免服务器重启后任务不自动运行
- 操作设置为启动程序,程序路径填
powershell.exe,参数填-ExecutionPolicy Bypass -NoProfile -File "C:\你脚本的完整路径\file.ps1" - 任务设置页取消勾选「如果任务运行时间超过以下时间则停止任务」,避免脚本被系统自动杀掉
- 修正脚本里的路径问题:把模块导入语句改成绝对路径,比如
Import-Module "C:\你模块存放的完整路径\message_module.psm1",不要依赖相对路径。 - 加错误日志方便后续排查:给
Send-TeamsMessage函数加上错误捕获,把报错信息写到本地日志文件,参考修改如下:function Send-TeamsMessage { Param( [Parameter(Position = 0, Mandatory = $true)][String]$Message, [Parameter(Position = 1, Mandatory = $true)][String]$Title ) try { $JSONBody = [PSCustomObject][Ordered]@{ "@type" = "MessageCard" "@context" = "http://schema.org/extensions" "themeColor" = '0078D7' "title" = $Title "text" = $Message } $TeamMessageBody = ConvertTo-Json $JSONBody -Depth 100 $parameters = @{ "URI" = '你的Teams webhook实际地址' "Method" = 'POST' "Body" = $TeamMessageBody "ContentType" = 'application/json' "ErrorAction" = 'Stop' } Invoke-RestMethod @parameters | Out-Null } catch { # 把错误写到本地日志,出问题时直接查日志定位 $errMsg = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] 发送Teams告警失败:$_`n" Add-Content -Path "C:\自定义脚本日志目录\error.log" -Value $errMsg } } - 修正脚本里的方法调用bug:把
$test_table.clear改成$test_table.Clear(),确保每次计算完在线率后数组能正常清空。
内容的提问来源于stack exchange,提问作者Jo Wilson
相关产品推荐
相关产品推荐

