复制子文件夹和文件,检查“上次修改时间”

时间:2014-03-23 18:10:48

标签: powershell backup

我制作了一个备份脚本:

  1. 从XML文件中读取源文件路径和目标文件夹路径
  2. 检查源文件和目标路径是否存在(对于每个文件)
  3. 检查目标文件夹中是否存在源文件(同名)
  4. 检查每个源和目标文件的上次修改日期(如果文件存在于目标文件夹中)
  5. 如果文件尚不存在,或者源文件比目标文件夹中的现有文件新,则将源文件复制到目标文件夹,否则不执行任何操作
  6. 这仅适用于源文件,如果在XML文件中指定了源文件夹,则只复制该文件夹,而不复制其内容。

    我不想使用Copy-Item -Recurse,因为我想检查每个项目的最后修改日期,如果它没有达到上述条件,我根本不想复制它。

    这让我Get-ChildItem -Recurse列出了所有内容,但是我无法提出适用于此示例的内容:

    C:\powershell\test\ (XML specified source)
    

    基础结构:

    C:\powershell\test\xmltest2.xml
    C:\powershell\test\test2\xmltest.xml
    C:\powershell\test\test3\test4\xmltest3.xml
    etc.
    

    即。我想在复制它之前检查每个文件,但是如果说文件夹没有被修改但是文件里面的文件应该被复制它仍然可以工作,并保留相同的文件夹结构。

    有什么想法吗? :)

1 个答案:

答案 0 :(得分:2)

正如Ansgar Wiechers所说,你正在重新发明轮子,RoboCopy将更容易做到这一点。 RoboCopy也可以复制安全权限和创建/修改日期,这很棒。相关的RoboCopy讨论:https://superuser.com/a/445137/67909

尽管如此,它并不像自己写的那么有趣,是吗?我想出了这个:

# Assuming these two come from your XML config, somehow
$xmlSrc = "c:\users\test\Documents\test1"
$xmlDestPath = "c:\users\test\Documents\test2"

#==========
# Functions
#==========
function process-file ($item) {
    #$item should be a string, full path to a file
    #e.g. 'c:\users\test\Documents\file.txt'

    # Make the destination file full path
    $destItem = $item.ToLower().Replace($xmlSrc, $xmlDestPath)

    if (-not (Test-Path $destItem)) {  #File doesn't exist in destination

        #Is there a folder to put it in? If not, make one
        $destParentFolder = Split-Path $destItem -Parent
        if (-not (Test-Path $destParentFolder)) { mkdir $destParentFolder }

        # Copy file
        Copy-Item $item -Destination $destParentFolder -WhatIf

    } else {  #File does exist

        if ((Get-Item $item).LastAccessTimeUtc -gt (Get-Item $destItem).LastAccessTimeUtc) {

            #Source file is newer, copy it
            $destParentFolder = Split-Path $destItem -Parent
            Copy-Item $item -Destination $destParentFolder -Force -WhatIf
        }
    }
}

function process-directory($dir) {
    # Function mostly handles "copying" empty directories
    # Otherwise it's not really needed

    # Make the destination folder path
    $destDir = $dir.ToLower().Replace($xmlSrc, $xmlDestPath)

    # If that doesn't exist, make it
    if (-not (Test-Path $destDir)) { mkdir $destDir -whatif }
}

#==========
# Main code
#==========
if ((Get-Item $xmlSrc).PsIsContainer) {

    # You specified a folder
    Get-ChildItem $xmlSrc -Recurse | ForEach { 
        if ($_.PsIsContainer) {
            process-directory $_.FullName
        } else {
            process-file $_.FullName
        }
    }|Out-Null

} else {

    # You specified a file
    process-file $xmlSrc
}

NB。副本是-WhatIf所以它不会做任何激烈的事情。它有两个直接的问题:

  • 它使一切都小写。否则,您必须正确匹配案例,因为.Replace()区分大小写。
    • 我使用.Replace()因为-replace将文件路径中的\视为正则表达式的一部分而不起作用。可能有一个转义字符串命令行程序来解决这个问题,但我没有找到它。
  • 如果您将\放在$ xmlSrc或$ xmlDestPath的末尾,它将会崩溃。