如果项目不存在,则将项目从源复制到目标

时间:2014-09-18 15:01:44

标签: powershell

我有一个非常基本的PowerShell复制脚本,可以将项目从源文件夹复制到目标文件夹。然而,这会移动过多的数据,我想检查文件名是否已经存在,以便可以忽略该文件。我不需要像验证创建的日期/校验和/等那样复杂。

目前它的目的是:

Copy-Item source destination -recurse
Copy-Item source2 destination2 -recurse

我想我需要添加Test-Path cmdlet,但我不确定如何实现它。

7 个答案:

答案 0 :(得分:11)

您可以随时从ROBOCOPY致电PowerShell

使用/ xc(不包括已更改)/ xn(不包括更新)和/ xo(不包括旧版)标记:

robocopy /xc /xn /xo source destination 

这只会复制那些不在目标文件夹中的文件。

更多选项类型robocopy /?

答案 1 :(得分:4)

虽然我同意Robocopy是这类事情的最佳工具,但我只是为了给客户提供他们所要求的东西,这是一个有趣的PowerShell练习。

此脚本应该只按照您的要求执行操作:仅当源文件中的文件尚不存在且具有最少的多余装饰时,才将文件从源复制到目标。由于您的示例中有-recurse选项,因此只需在Destination文件夹中测试文件名就可以进行更多编码。

$Source = "C:\SourceFolder"
$Destination = "C:\DestinationFolder"

Get-ChildItem $Source -Recurse | ForEach {
    $ModifiedDestination = $($_.FullName).Replace("$Source","$Destination")
    If ((Test-Path $ModifiedDestination) -eq $False) {
        Copy-Item $_.FullName $ModifiedDestination
        }
    }

答案 2 :(得分:3)

$exclude = Get-ChildItem -recurse $dest
Copy-Item -Recurse $file $dest -Verbose -Exclude $exclude

答案 3 :(得分:2)

这是一个递归脚本,它同步处理2个文件夹而忽略现有文件:

function Copy-FilesAndFolders([string]$folderFrom, [string]$folderTo) {
    $itensFrom = Get-ChildItem $folderFrom
    foreach ($i in $itensFrom) 
    {
        if ($i.PSIsContainer)
        {
            $subFolderFrom = $folderFrom + "\" + $i.BaseName
            $subFolderTo = $folderTo + "\" + $i.BaseName
            Copy-FilesAndFolders $subFolderFrom $subFolderTo | Out-Null
        }
        else
        {
            $from = $folderFrom + "\" + $i.Name
            $to = $folderTo + "\" + $i.Name
            if (!(Test-Path $from)) # only copies non-existing files
            {
                if (!(Test-Path $fodlerTo)) # if folder doesn't exist, creates it
                {
                    New-Item -ItemType "directory" -Path $folderTo
                }
                Copy-Item $from $folderTo
            }           
        }
    }   
}

要调用它:

Copy-FilesAndFolders "C:\FromFolder" "C:\ToFolder"

答案 4 :(得分:1)

建立Wai Ha Lee的帖子,这是一个对我有用的例子:

> microbenchmark(f.old(),f.new())
Unit: milliseconds
    expr       min        lq      mean    median        uq       max neval
 f.old() 49.553825 53.486576 61.701149 57.710147 62.862921 136.02883   100
 f.new()  2.036781  2.365426  2.988266  2.685126  3.396083  10.88668   100

这会构建一个要排除的列表,然后将源目录和子目录中的任何pdf复制到单个文件夹中的目标 ...,不包括现有文件。同样,这是我需要的一个例子,但与你的相似。应该很容易调整你的心灵内容。

答案 5 :(得分:1)

函数Copy-IfNotPresent一次只能接受一个文件,但是很容易为所有要复制的文件循环。这是一个例子:

gci c:\temp\1\*.* -Recurse -File | % { Copy-IfNotPresent -FilePath $_ -Destination "C:\temp\2\$(Resolve-Path $_ -relative)" -Verbose }

这是功能。如有必要,它将生成文件夹树。以下是要点链接:https://gist.github.com/pollusb/cd47b4afeda8edbf8943a8808c880eb8

Function Copy-IfNotPresent {
<#
    Copy file only if not present at destination.
    This is a one file at a time call. It's not meant to replace complex call like ROBOCOPY.
    Destination can be a file or folder. If it's a folder, you can use -Container to force Folder creation when not exists
#>
[CmdletBinding()]
Param (
    [Parameter(Mandatory)]
    $FilePath,

    [Parameter(Mandatory)]
    [string]$Destination,

    [switch]$Container,

    [switch]$WhatIf
)
#region validations
if ($FilePath -isnot [System.IO.FileInfo]){
    $File = Get-ChildItem $FilePath -File
} else {
    $File = $FilePath
}

if (!$File.Count){
    Write-Warning "$FilePath no file found."
    return
} elseif ($File.Count -gt 1) {
    Write-Warning "$FilePath must resolve to one file only."
    return
}
#endregion

# Destination is a folder
if ($Container -or (Test-Path -Path $Destination -PathType Container)) {
    if (!(Test-Path $Destination)) {
        New-Item -Path $Destination -ItemType Container | Out-Null
    }
    $Destination += "\$($File.Name)"
}

# Destination is a file
if (!(Test-Path $Destination)) {
    if ($WhatIf) {
        Write-Host "WhatIf:Copy-IfNotPresent $FilePath -> $Destination"
    } else {
        # Force creation of parent folder
        $Parent = Split-Path $Destination -Parent
        if (!(Test-Path $Parent)) { 
            New-Item $Parent -ItemType Container | Out-Null
        }
        Copy-Item -Path $FilePath -Destination $Destination  
        Write-Verbose "Copy-IfNotPresent $FilePath -> $Destination (is absent) copying"
    }
} else {
    Write-Verbose "Copy-IfNotPresent $Destination (is present) not copying"
}
}

答案 6 :(得分:1)

$source = "c:\source"

$destination = "c:\destination"

  1. 创建要排除的文件列表,即目标中已存在的文件。
$exclude = Get-Childitem -Recurse $destination | ForEach-Object { $_.FullName -replace [Regex]::Escape($destination ), "" }
  1. 以递归方式将所有内容从source复制到destination,不包括先前收集的文件。
Copy-Item -Recurse -Path (Join-Path $source "*") -Destination $destination -Exclude $exclude -Force -Verbose
  • (Join-Path $source "*")最后添加一个通配符,以确保您获得source文件夹的子代,而不是源文件夹本身。
  • 使用
  • Force是因为我不介意已经存在文件夹(错误消息的结果)。 谨慎使用。
  • ForEach-Object { $_.FullName -replace [Regex]::Escape($destination ), "" }将现有文件的全名转换为可用作Exclude参数的值