【问题标题】:Copy files including directory structure only if their modification date has changed since仅当修改日期已更改时才复制包括目录结构的文件
【发布时间】:2018-10-17 15:25:24
【问题描述】:

我正在尝试编写一个脚本,它将源路径作为输入并复制自给定日期以来已更改的所有文件,包括它们的目录结构:

param([string]$source,[string]$datum)
(Get-ChildItem $source -Recurse | Where-Object { $_.LastWriteTime -ge $datum }) | Copy-Item -Destination C:\tmp -Recurse

它有效。问题是,它复制了文件,包括它们的目录结构,但它还将所有文件从源目录复制到目标文件夹的基本路径。

错误在哪里?

【问题讨论】:

  • 此外,它会将所有子文件夹作为直接子文件夹复制到目标目录的基本文件夹:/
  • 我们都是这里的脚本爱好者,但有时最好使用本机执行此操作的工具,而不是尝试从头开始,好吧,除非它是一种学习努力。改用 Robocopy,因为这种东西是它的设计目的,它内置在操作系统中,您可以直接使用它或从脚本中调用它。在性能方面,robocopy 也比 Copy-Item 快。
  • @postanote:如果我可以使用 robocopy,我会的! ;)
  • 为什么 robocopy 在这种情况下没有帮助?
  • 福兰德,明白了。 ;^}

标签: powershell


【解决方案1】:

这是一个过于复杂的解决方案。它有很多错误处理,有 5 次重试尝试。您应该能够将其应用于您的需求。

我会查看Line 21 以添加您的Where-Object 并对其进行测试。

使用示例: Copy-Files -Source "C:\Path\" -Destination "C:\Path2\"

Function Retry-Command {
    $Script:Counter = $Script:Counter + 1
    Write-Host "Attempt #" $Script:Counter "out of 5"
    if ($Script:Counter -ge 5) {
        PAUSE
    }
    else {
        Start-Sleep -Seconds 5 -Verbose
    }
}
Function Copy-Files ([string]$Source, [string]$Destination ) {
    [System.Collections.ArrayList]$Folder_Content = @()
    [string]$Folder_Name = Split-Path $Source -Leaf
    [string]$Folder_Path = ($Source -replace [regex]::Escape($Source), ($Destination + $Folder_Name + "\"))
    [int]$Script:Counter = 0
    while (($Folder_Content.Count -eq "0") -and ($Counter -ne 5)) {
        try {
            Write-Host ""
            Write-Host "------------------------------" -ForegroundColor Cyan
            Write-Host "Getting Content of" $Folder_Name -ForegroundColor Yellow
            [System.Collections.ArrayList]$Folder_Content = @(Get-ChildItem -Path $Source -Recurse -Force -ErrorVariable Child_Error)
            if ((-Not $Child_Error) -and ($Folder_Content.Count -ne 0) ) {
                Write-Host "Finished Getting Content of" $Folder_Name -ForegroundColor Green
                [int]$Script:Counter = 0
            }
            else {
                Write-Host "Failed to get Content of" $Folder_Name -ForegroundColor Red
                Retry-Command
            }  
        }
        catch {
            Write-Host "Unexpected Error getting Content of" $Folder_Name -ForegroundColor Red
            Retry-Command
        }
    }        
    if (-Not $Folder_Content.Count -eq 0) {
        while ((Test-Path -Path $Folder_Path) -eq $false) {
            try {
                Write-Host ""
                Write-Host "Creating" $Folder_Name "Folder" -ForegroundColor Yellow
                Copy-Item -Path $Source -Destination $Folder_Path -Force -ErrorVariable Folder_Error
                if (-Not $Folder_Error) {
                    Write-Host "Finished Creating" $Folder_Name "Folder" -ForegroundColor Green
                    [int]$Script:Counter = 0
                }
                else {
                    Write-Host "Failed to create" $Folder_Name "Folder" -ForegroundColor Red
                    Retry-Command
                }            
            }
            catch {
                Write-Host "Unexpected Error Creating" $Folder_Name "Folder" -ForegroundColor Red
                Retry-Command
            }        
        }
        foreach ($Index in $Folder_Content) {
            [string]$Software_File_Name = Split-Path $Index.FullName -Leaf
            [string]$Software_File_Path = ($Index.FullName -replace [regex]::Escape($Source), ($Destination + (Split-Path $Source -Leaf) + "\"))
            while ((Test-Path -Path $Software_File_Path) -eq $false) {
                try {
                    Write-Host ""
                    Write-Host "Copying" $Index.FullName -ForegroundColor Yellow
                    Copy-Item -Path $Index.FullName -Destination $Software_File_Path -Force -ErrorVariable File_Error
                    if (-Not $File_Error) {
                        Write-Host "Finished Copying" $Index.FullName -ForegroundColor Green
                        [int]$Script:Counter = 0
                    }
                    else {
                        Write-Host "Failed to Copy" $Index.FullName -ForegroundColor Red
                        Retry-Command
                    }
                }
                catch {
                    Write-Host "Unexpected Error Copying" $Index.FullName -ForegroundColor Red
                    Retry-Command
                }
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    首先,您应该使用robocopy 来处理类似的事情。它有可能处理您的查询的开关:

    /e 复制子目录。请注意,此选项包括空目录。如需更多信息,请参阅备注。

    /maxage:指定最大文件年龄(排除超过 N 天或日期的文件)。

    /l 指定仅列出文件(而不是复制、删除或时间戳)。

    所以知道我将开始尝试robocopy $source $destination /e /maxage:30 /l,它应该会显示目录树中过去 30 天内修改过的所有文件。 /maxage 可能不是您正在寻找的开关,但它是一个合理的猜测。


    您当前逻辑的问题很可能是Get-ChildItem $source -Recurse 将返回文件夹和文件。因此,您可以将一个文件夹传递给Copy-Item,这是所有额外文件的来源。您应该可以使用-File 开关来缓解这种情况。

    Get-ChildItem $source -Recurse -File
    

    【讨论】:

    • 不幸的是,这并没有保留目录结构。
    • @Faulander 你想保持什么目录结构?无论文件被复制的整个目录结构?这将是微不足道的两个副本。一个只做目录,另一个做文件。我还不清楚结果应该是什么样子。
    猜你喜欢
    • 1970-01-01
    • 2018-09-23
    • 1970-01-01
    • 2017-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-06
    相关资源
    最近更新 更多