PowerShell邮件附件报错:文件被占用无法访问,求脚本优化方案
解决PowerShell脚本发送被Word占用文件的报错问题
方案1:复制文件到临时目录发送副本
当原文件被Word占用时,直接读取会触发锁定报错,但尝试复制文件到临时路径通常能绕过锁定(Word的文件锁一般不阻止读取复制操作)。复制成功后发送临时文件副本,完成后再清理临时文件。
示例代码:
# 配置目标目录和邮件信息 $targetDir = "C:\Your\Target\Directory" $senderAddr = "sender@example.com" $recipientAddr = "recipient@example.com" $smtpServer = "smtp.example.com" # 获取过去8小时内生成的最新文件 $latestFile = Get-ChildItem -Path $targetDir -File | Where-Object { $_.CreationTime -ge (Get-Date).AddHours(-8) } | Sort-Object CreationTime -Descending | Select-Object -First 1 if ($latestFile) { # 创建临时文件路径 $tempFile = Join-Path -Path $env:TEMP -ChildPath $latestFile.Name try { # 复制原文件到临时路径 Copy-Item -Path $latestFile.FullName -Destination $tempFile -Force -ErrorAction Stop # 发送邮件 Send-MailMessage -From $senderAddr -To $recipientAddr ` -Subject "Latest 8-Hour Report" ` -Body "Attached is the latest generated file." ` -SmtpServer $smtpServer -Attachments $tempFile Write-Host "邮件发送成功" } catch { Write-Host "操作失败: $_" } finally { # 清理临时文件(忽略删除失败的情况) if (Test-Path $tempFile) { Remove-Item $tempFile -Force -ErrorAction SilentlyContinue } } } else { Write-Host "过去8小时内没有生成新文件" }
方案2:先检测文件是否被占用
编写辅助函数检查文件是否被其他进程锁定,确认未被占用时再直接发送;若被占用则跳过或触发后续处理逻辑。
示例代码:
# 检测文件是否被锁定的函数 function Test-FileLocked { param([string]$FilePath) try { $fileStream = [System.IO.File]::Open( $FilePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None ) $fileStream.Close() return $false } catch { return $true } } # 配置基础参数 $targetDir = "C:\Your\Target\Directory" $senderAddr = "sender@example.com" $recipientAddr = "recipient@example.com" $smtpServer = "smtp.example.com" # 获取目标文件 $latestFile = Get-ChildItem -Path $targetDir -File | Where-Object { $_.CreationTime -ge (Get-Date).AddHours(-8) } | Sort-Object CreationTime -Descending | Select-Object -First 1 if ($latestFile) { if (-not (Test-FileLocked -FilePath $latestFile.FullName)) { # 文件未被占用,直接发送 try { Send-MailMessage -From $senderAddr -To $recipientAddr ` -Subject "Latest 8-Hour Report" ` -Body "Attached is the latest generated file." ` -SmtpServer $smtpServer -Attachments $latestFile.FullName Write-Host "邮件发送成功" } catch { Write-Host "发送失败: $_" } } else { Write-Host "文件 $($latestFile.Name) 正在被占用,跳过本次发送" # 此处可添加日志记录或重试触发逻辑 } } else { Write-Host "过去8小时内没有生成新文件" }
方案3:添加重试机制
如果文件只是被Word临时占用(比如正在保存),可以设置重试次数和间隔,多次尝试复制或发送,直到成功或达到重试上限。
示例代码(结合方案1的复制逻辑):
# 配置基础参数 $targetDir = "C:\Your\Target\Directory" $senderAddr = "sender@example.com" $recipientAddr = "recipient@example.com" $smtpServer = "smtp.example.com" $maxRetries = 3 $retryInterval = 5 # 每次重试间隔5秒 # 获取目标文件 $latestFile = Get-ChildItem -Path $targetDir -File | Where-Object { $_.CreationTime -ge (Get-Date).AddHours(-8) } | Sort-Object CreationTime -Descending | Select-Object -First 1 if ($latestFile) { $tempFile = Join-Path -Path $env:TEMP -ChildPath $latestFile.Name $sendSuccess = $false for ($i=1; $i -le $maxRetries; $i++) { try { Copy-Item -Path $latestFile.FullName -Destination $tempFile -Force -ErrorAction Stop Send-MailMessage -From $senderAddr -To $recipientAddr ` -Subject "Latest 8-Hour Report" ` -Body "Attached is the latest generated file." ` -SmtpServer $smtpServer -Attachments $tempFile $sendSuccess = $true Write-Host "第 $i 次尝试成功,邮件已发送" break } catch { Write-Host "第 $i 次尝试失败: $_" Start-Sleep -Seconds $retryInterval } } if (-not $sendSuccess) { Write-Host "已达到最大重试次数,文件 $($latestFile.Name) 仍无法处理" } # 清理临时文件 if (Test-Path $tempFile) { Remove-Item $tempFile -Force -ErrorAction SilentlyContinue } } else { Write-Host "过去8小时内没有生成新文件" }
额外提示
- 确保脚本运行账户对目标目录和系统临时目录有读写权限
- 若Word文件处于实时编辑状态,复制的副本可能是未保存版本,可添加文件大小稳定性检测(比如间隔几秒检查文件大小是否一致),确认文件完全生成后再处理
内容的提问来源于stack exchange,提问作者Nessuno
相关产品推荐
相关产品推荐

