PowerShell中SaveToFile保存EML的PDF附件丢失扩展名问题求助
问题分析与修复方案
你的代码丢失PDF扩展名的核心问题有两个:
- 遍历附件时,错误地从附件集合(
$CdoMessage.Attachments)而非当前单个附件($attachment)获取文件名 - 未处理邮件主题中的非法字符,可能导致文件名异常或保存失败
修复后的代码
# 一次性获取所有eml文件,避免重复遍历目录 $emlFiles = Get-ChildItem -Path C:\Extract -Filter *.eml -Recurse -File foreach ($emlFile in $emlFiles) { $adoDbStream = New-Object -ComObject ADODB.Stream $adoDbStream.Open() $adoDbStream.LoadFromFile($emlFile.FullName) $cdoMessage = New-Object -ComObject CDO.Message $cdoMessage.DataSource.OpenObject($adoDbStream, "_Stream") # 清理主题中的Windows非法文件名字符 $cleanSubject = $cdoMessage.Subject -replace '[<>:"/\\|?*]', '_' foreach ($attachment in $cdoMessage.Attachments) { # 从当前附件对象获取完整文件名(含扩展名) $filename = $attachment.Filename # 仅处理PDF附件(按需保留此过滤逻辑) if ($filename -like '*.pdf') { $attFilename = "$cleanSubject-$filename" Write-Output $attFilename $savePath = Join-Path -Path C:\Extract -ChildPath $attFilename $attachment.SaveToFile($savePath) } } $adoDbStream.Close() # 释放COM对象,避免内存泄漏 [System.Runtime.Interopservices.Marshal]::ReleaseComObject($adoDbStream) | Out-Null [System.Runtime.Interopservices.Marshal]::ReleaseComObject($cdoMessage) | Out-Null }
关键修改说明
- 优化文件遍历:原代码两次执行相同的
Get-ChildItem,改为一次获取所有eml文件,提升运行效率 - 修正文件名获取逻辑:将
$CdoMessage.Attachments.Filename改为$attachment.Filename,确保拿到当前附件的完整文件名(包含扩展名) - 清理非法字符:邮件主题常包含
<>:\"/\\|?*等Windows禁止的文件名字符,用-replace替换为下划线,避免保存失败 - 新增PDF过滤:添加
if ($filename -like '*.pdf')确保只处理PDF附件,减少无效操作 - 释放COM对象:添加
ReleaseComObject释放ADODB和CDO的COM对象,防止长期运行导致内存泄漏
内容的提问来源于stack exchange,提问作者Raif
相关产品推荐
相关产品推荐

