PowerShell服务监控脚本执行正常但邮件无内容问题求助
问题修复:PowerShell邮件内容为空的解决方法
核心问题分析
- 参数类型不匹配:
New-Email的EmailBody参数定义为PSCustomObject[],但传入的是纯字符串数组($results是存储字符串的ArrayList),ConvertTo-Html处理纯字符串数组时无法生成有效HTML片段,导致邮件内容为空。 - HTML构造逻辑错误:你将邮件说明消息放到了
ConvertTo-Html的-Head参数中,而-Head仅用于定义HTML头部(如样式),消息内容应该放在HTML主体的前置位置。 - 作用域潜在隐患:全局变量
$results在函数中修改时,若未明确作用域可能导致值未正确传递(虽你提到CheckServices运行正常,此为优化项)。
具体修复代码
1. 调整CheckServices函数,优化结果存储
将结果存储为自定义对象(方便生成结构化表格),并明确作用域:
Function CheckServices { # 初始化结果集合,存储为自定义对象 $script:results = [System.Collections.ArrayList]@() foreach ($server in $computers) { foreach ($service in $checklist) { try { $state = (Invoke-Command -ComputerName $server -ScriptBlock { param ($service) Get-Service -Name $service } -ArgumentList $service -Credential $cred -ErrorAction Stop).Status switch ($state) { 'Running' { $null = $script:results.Add([PSCustomObject]@{ 服务器 = $server 服务名称 = $service 状态 = "运行正常" 操作 = "无" }) } 'Stopped' { $null = $script:results.Add([PSCustomObject]@{ 服务器 = $server 服务名称 = $service 状态 = "已停止" 操作 = "已重启服务" }) # 执行服务重启 Invoke-Command -ComputerName $server -ScriptBlock { param ($service) Restart-Service -Name $service -ErrorAction Stop } -ArgumentList $service -Credential $cred } $null { $null = $script:results.Add([PSCustomObject]@{ 服务器 = $server 服务名称 = $service 状态 = "未找到服务" 操作 = "无" }) } } } catch { $null = $script:results.Add([PSCustomObject]@{ 服务器 = $server 服务名称 = $service 状态 = "检查失败" 操作 = $_.Exception.Message }) Write-Logfile -ActionType ERROR -Message "检查服务器$server的服务$service失败:$($_.Exception.Message)" } } } # 调用邮件函数传递结果 New-Email -EmailBody $script:results -Subject "服务状态报告" -Message "请查看以下服务状态报告。若邮件无结果表格,则夜间无服务异常情况。" }
2. 修改New-Email函数,修复HTML生成逻辑
调整参数适配、修正HTML构造方式,确保内容正常显示:
Function New-Email { Param( [Parameter(Mandatory=$false)] [string]$Attachment, [Parameter(Mandatory=$false)] [PSCustomObject[]]$EmailBody, [Parameter(Mandatory=$true)] [string]$Message, [Parameter(Mandatory=$true)] [string]$Subject ) try { Write-Logfile -ActionType INFO -Message "函数New-Email:尝试发送状态邮件..." $style = @" <style> BODY{font-family: Arial; font-size: 10pt;} TABLE{border: 1px solid black; border-collapse: collapse; margin-top:10px;} TH{border: 1px solid black; background: #dddddd; padding: 5px;text-align: center;} TD{border: 1px solid black; padding: 5px;text-align: left;} </style> "@ # 生成结果HTML片段,无结果时显示提示文本 $BodyResults = if ($EmailBody) { $EmailBody | ConvertTo-Html -Fragment | Out-String } else { "<p>无服务状态异常或检查记录</p>" } # 构造完整HTML,将消息作为前置内容,样式放入头部 $Body = ConvertTo-Html -Head $style -PreContent "<p>$Message</p>" -PostContent $BodyResults | Out-String # 发送邮件 $mailParams = @{ BodyAsHtml = $true From = $EmailFrom To = $EmailTo Subject = $Subject Body = $Body SmtpServer = $PSEmailServer } if ($Attachment) { $mailParams['Attachments'] = $Attachment Send-MailMessage @mailParams Write-Logfile -ActionType SUCCESS -Message "函数New-Email:已发送带附件[$Attachment]的状态邮件!" } else { Send-MailMessage @mailParams Write-Logfile -ActionType SUCCESS -Message "函数New-Email:已发送无附件的状态邮件!" } } catch { Write-Logfile -ActionType ERROR -Message "函数New-Email:无法发送状态邮件!" Write-Logfile -ActionType ERROR -Message $_.Exception.Message } }
3. 补充全局配置变量
脚本开头需定义以下变量,否则邮件和日志功能会报错:
# 全局配置 $EmailFrom = "你的发件邮箱@域名.com" $EmailTo = "收件邮箱@域名.com" $PSEmailServer = "smtp.你的域名.com" $currentloc = $PSScriptRoot # 日志文件存储路径,也可手动指定如"C:\Logs" $cred = Get-Credential # 或提前定义远程服务器访问凭据 # 服务器列表 $computers = @( "Server01", "Server02" ) # 待检查服务列表 $checklist = @( "WinRM", "Spooler" )
额外优化建议
- 为
Invoke-Command添加-ErrorAction Stop,确保捕获远程执行的错误。 - 可在
CheckServices末尾将$results写入日志文件,方便离线排查。
内容的提问来源于stack exchange,提问作者Eddie Bailey
相关产品推荐
相关产品推荐

