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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 09:38:09