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

PowerShell对比文本文件差异并邮件发送的代码异常排查

问题描述

我有两个存储SQL函数名称列表的文本文件,想要对比$A与$B的内容,筛选出仅存在于$B而不存在于$A的SQL函数名称并写入$C文件,再将$C作为附件发送至指定邮箱。

我的代码如下:

$A = "c:\ReferenceFunctions.txt" 
$B = "c:\GeneratedFunctions.txt" 
$C = "c:\FileWithDifferences.txt" 
$fromaddress = "noreply@xyz" 
$toaddress = "123@hhh" 
$bccaddress = "3333@nnn.com" 
$login = "yourlogin" 
$password = "password" | Convertto-SecureString -AsPlainText -Force 
$smtpserver = "gggg.com" 
$smtp = new-object Net.Mail.SmtpClient($smtpserver, 800) 
$smtp.EnableSsl = $true 
$smtp.Credentials = New-Object System.Net.NetworkCredential($login, $password); 
$body = "see attached " 
$Subject = "checking differences" 
$message = new-object System.Net.Mail.MailMessage 
$message.From = $fromaddress 
$message.To.Add($toaddress) 
#$message.CC.Add($CCaddress) 
$message.Bcc.Add($bccaddress) 
$message.IsBodyHtml = $True 
$message.Subject = $Subject 
$message.body = $body 
$message.Priority = [System.Net.Mail.MailPriority]::High 

Compare-object (Get-Content $A) (Get-Content $B) | Out-File $C 

#Attach the eported file with differences 
$attachment = $C 
$attach = new-object Net.Mail.Attachment($attachment) 
$message.Attachments.Add($attach) 

IF (Compare-Object -ReferenceObject (Get-Content $A) -DifferenceObject (Get-Content $B)){ 
    $smtp.Send($message); 
}

$A文件内容:

fn_StatementEndOfMonth fn_Performance_Sql fn_DailyReturns

$B文件内容:

fn_Performance_Sql fn_DailyReturns fn_SQLPerfomance_Monitor

预期$C文件应包含:

fn_SQLPerfomance_Monitor

但当前代码执行后,附件中包含了两个文件中的所有SQL函数名称,而非预期的差异内容,我无法定位问题所在,请求协助排查。


问题排查与修复方案

我帮你梳理了代码里的问题,核心有两个关键点:

问题根源

  1. 文件内容读取方式错误:你的函数名是在同一行用空格分隔的,Get-Content默认会把整行内容当成一个字符串项,而不是拆分单个函数名。这会导致Compare-Object对比的是两行完整内容,自然会认为两边都是差异项,输出所有内容。
  2. Compare-Object默认行为不符合需求:默认情况下,它会返回两边所有差异项(包括仅在$A的<=标记项和仅在$B的=>标记项),且输出包含额外格式,直接写入文件会出现不符合预期的内容。

分步修复

1. 拆分文件中的函数名

先把单行空格分隔的内容拆分成单个函数名数组,确保对比逻辑针对每个函数:

$contentA = (Get-Content $A) -split '\s+' | Where-Object { $_ -ne '' }
$contentB = (Get-Content $B) -split '\s+' | Where-Object { $_ -ne '' }

用-split '\s+'按任意空白字符拆分,再过滤空字符串避免无效项。

2. 筛选仅存在于$B的函数

对比拆分后的数组,筛选出SideIndicator为=>的项(仅属于$B的函数),提取纯函数名:

$onlyInB = Compare-Object -ReferenceObject $contentA -DifferenceObject $contentB | 
           Where-Object { $_.SideIndicator -eq '=>' } | 
           Select-Object -ExpandProperty InputObject

3. 写入结果文件

把筛选后的结果写入$C,确保每行一个函数名:

$onlyInB | Out-File $C -Encoding utf8

4. 优化邮件发送逻辑

检查是否有差异内容,避免发送空附件的邮件,同时清理资源防止内存泄漏:

if ($onlyInB) {
    $attach = New-Object Net.Mail.Attachment($C)
    $message.Attachments.Add($attach)
    $smtp.Send($message)
    $attach.Dispose()
}
$smtp.Dispose()

修复后的完整代码

$A = "c:\ReferenceFunctions.txt" 
$B = "c:\GeneratedFunctions.txt" 
$C = "c:\FileWithDifferences.txt" 
$fromaddress = "noreply@xyz" 
$toaddress = "123@hhh" 
$bccaddress = "3333@nnn.com" 
$login = "yourlogin" 
$password = "password" | Convertto-SecureString -AsPlainText -Force 
$smtpserver = "gggg.com" 
$smtp = New-Object Net.Mail.SmtpClient($smtpserver, 800) 
$smtp.EnableSsl = $true 
$smtp.Credentials = New-Object System.Net.NetworkCredential($login, $password); 
$body = "see attached " 
$Subject = "checking differences" 
$message = New-Object System.Net.Mail.MailMessage 
$message.From = $fromaddress 
$message.To.Add($toaddress) 
#$message.CC.Add($CCaddress) 
$message.Bcc.Add($bccaddress) 
$message.IsBodyHtml = $True 
$message.Subject = $Subject 
$message.body = $body 
$message.Priority = [System.Net.Mail.MailPriority]::High 

# 修复:拆分函数名并筛选仅在B中的项
$contentA = (Get-Content $A) -split '\s+' | Where-Object { $_ -ne '' }
$contentB = (Get-Content $B) -split '\s+' | Where-Object { $_ -ne '' }
$onlyInB = Compare-Object -ReferenceObject $contentA -DifferenceObject $contentB | 
           Where-Object { $_.SideIndicator -eq '=>' } | 
           Select-Object -ExpandProperty InputObject

# 写入结果文件
$onlyInB | Out-File $C -Encoding utf8

# 仅当有差异时发送邮件
if ($onlyInB) {
    $attach = New-Object Net.Mail.Attachment($C)
    $message.Attachments.Add($attach)
    $smtp.Send($message)
    $attach.Dispose()
}

# 清理SMTP客户端资源
$smtp.Dispose()

这样修改后,$C文件就会只包含fn_SQLPerfomance_Monitor,完全符合你的预期啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:12:57