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

如何用PowerShell持续将TEMP文件夹文件复制到指定目录?

Windows Server 2019中FileSystemWatcher自动复制TEMP文件问题修复

问题场景

在Windows Server 2019上尝试通过PowerShell的FileSystemWatcher持续监控C:\Users\Administrator\AppData\Local\Temp文件夹,将新创建或修改的文件自动复制到C:\Users\Administrator\copied目录,但运行代码后出现大量“无文件路径、文件不存在或事件类型不支持”的错误,且复制操作未正常执行。

原代码

# Define the source and destination directories
$sourceDirectory = 'C:\Users\Administrator\AppData\Local\Temp'
$destinationDirectory = 'C:\Users\Administrator\copied'

# Create an instance of the FileSystemWatcher class
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $sourceDirectory
$watcher.IncludeSubdirectories = $true

# Specify the type of changes to monitor
$watcher.NotifyFilter = [System.IO.NotifyFilters]'FileName, LastWrite'

# Filter the file types to monitor
$watcher.Filter = "*.*"

# Define the action to take when a file is created or modified
$action = {
    param($sender, $eventArgs)
$destinationDirectory = 'C:\Users\Administrator\copied'
    $eventType = $eventArgs.ChangeType
    $filePath = $eventArgs.FullPath

    if ($filePath -and (Test-Path $filePath) -and ($eventType -eq 'Created' -or $eventType -eq 'Changed')) {
        # Construct the destination file path
        $destFilePath = Join-Path -Path $destinationDirectory -ChildPath (Split-Path -Path $filePath -Leaf)

        # Copy the file to the destination directory
        try {
            Copy-Item -Path $filePath -Destination $destFilePath -Force
        }
        catch {
            Write-Host ("Failed to copy file. Error: " + $_.Exception.Message)
        }
    }
    else {
        Write-Host "Event detected with no file path, or the file does not exist, or the event type is not supported. Ignoring."
        Write-Host "Full event details: $eventArgs"
    }
}

# Add the event handlers for the Created and Changed events
Register-ObjectEvent -InputObject $watcher -EventName 'Created' -Action $action
Register-ObjectEvent -InputObject $watcher -EventName 'Changed' -Action $action

# Start monitoring the files
$watcher.EnableRaisingEvents = $true

# Keep the PowerShell console open
while ($true) {
    Start-Sleep -Seconds 1
}

错误信息

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
31     aa937f11-a26...                 NotStarted    False                                ...
32     2db275b2-991...                 NotStarted    False                                ...
Event detected with no file path, ignoring.
Full event details: System.IO.FileSystemEventArgs
Event detected with no file path, or the file does not exist, or the event type is not supported. Ignoring.
Full event details: System.IO.FileSystemEventArgs
Event detected with no file path, or the file does not exist, or the event type is not supported. Ignoring.
Full event details: System.IO.FileSystemEventArgs

问题原因分析

  1. 文件写入未完成:当Created或Changed事件触发时,文件可能仍被其他进程写入,此时Test-Path会返回false,导致跳过复制。
  2. Changed事件重复触发:FileSystemWatcher的Changed事件会因文件元数据(如修改时间)变化多次触发,部分触发时文件状态不稳定。
  3. 无文件锁定处理:TEMP目录的文件常被进程占用,直接执行Copy-Item会因文件锁定失败,且无重试逻辑。

修复方案

  • 增加文件存在性检查的重试逻辑,等待文件写入完成。
  • 针对Changed事件,仅处理文件内容变更,过滤元数据变化。
  • 为Copy-Item添加重试机制,应对文件锁定情况。
  • 优化事件参数处理,确保$filePath有效。

修正后的代码

# 定义源目录和目标目录
$sourceDirectory = 'C:\Users\Administrator\AppData\Local\Temp'
$destinationDirectory = 'C:\Users\Administrator\copied'

# 创建目标目录(如果不存在)
if (-not (Test-Path -Path $destinationDirectory)) {
    New-Item -Path $destinationDirectory -ItemType Directory | Out-Null
}

# 初始化FileSystemWatcher
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $sourceDirectory
$watcher.IncludeSubdirectories = $true
$watcher.NotifyFilter = [System.IO.NotifyFilters]'FileName, LastWrite, Size'
$watcher.Filter = "*.*"

# 定义事件处理动作
$action = {
    param($sender, $eventArgs)
    
    $destinationDirectory = 'C:\Users\Administrator\copied'
    $eventType = $eventArgs.ChangeType
    $filePath = $eventArgs.FullPath
    $maxRetries = 5
    $retryDelay = 200  # 毫秒
    
    # 仅处理Created和Changed事件,且确保文件路径有效
    if (-not $filePath -or ($eventType -notin @('Created', 'Changed'))) {
        Write-Host "无效事件或路径,忽略。事件类型: $eventType,路径: $filePath"
        return
    }

    # 重试检查文件是否存在且可访问
    for ($i = 0; $i -lt $maxRetries; $i++) {
        try {
            # 尝试打开文件以确认是否可访问
            $fileStream = [System.IO.File]::Open($filePath, 'Open', 'Read', 'ReadWrite')
            $fileStream.Close()
            $fileStream.Dispose()
            break
        }
        catch {
            if ($i -eq $maxRetries - 1) {
                Write-Host "多次尝试后仍无法访问文件: $filePath,错误: $($_.Exception.Message)"
                return
            }
            Start-Sleep -Milliseconds $retryDelay
        }
    }

    # 构造目标路径
    $destFilePath = Join-Path -Path $destinationDirectory -ChildPath (Split-Path -Path $filePath -Leaf)

    # 重试复制文件
    for ($i = 0; $i -lt $maxRetries; $i++) {
        try {
            Copy-Item -Path $filePath -Destination $destFilePath -Force -ErrorAction Stop
            Write-Host "成功复制文件: $filePath -> $destFilePath"
            break
        }
        catch {
            if ($i -eq $maxRetries - 1) {
                Write-Host "复制失败,已达最大重试次数。文件: $filePath,错误: $($_.Exception.Message)"
            }
            Start-Sleep -Milliseconds $retryDelay
        }
    }
}

# 注册事件处理器
Register-ObjectEvent -InputObject $watcher -EventName 'Created' -Action $action | Out-Null
Register-ObjectEvent -InputObject $watcher -EventName 'Changed' -Action $action | Out-Null

# 开始监控
$watcher.EnableRaisingEvents = $true

Write-Host "开始监控目录: $sourceDirectory,目标目录: $destinationDirectory"
Write-Host "按Ctrl+C停止监控..."

# 保持控制台运行
try {
    while ($true) {
        Start-Sleep -Seconds 1
    }
}
finally {
    # 清理资源
    $watcher.EnableRaisingEvents = $false
    $watcher.Dispose()
    Get-Job | Remove-Job -Force
    Write-Host "监控已停止,资源已清理"
}

关键改进说明

  1. 预创建目标目录:避免因目标目录不存在导致复制失败。
  2. 文件可访问性检查:通过尝试打开文件确认是否可读取,替代简单的Test-Path,更准确判断文件是否准备好。
  3. 多级重试机制:对文件访问和复制操作分别设置重试,应对文件锁定和写入未完成的情况。
  4. 资源清理:在脚本终止时自动清理FileSystemWatcher和事件作业,避免资源泄漏。
  5. 更详细的日志输出:便于排查问题,了解复制状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 11:24:54