如何使用powershell copy-item并保持结构

时间:2011-03-25 12:15:14

标签: powershell

我有一个如下所示的目录结构:

c:\folderA\folderB\folderC\client1\f1\files
c:\folderA\folderB\folderC\client1\f2\files
c:\folderA\folderB\folderC\client2\f1\files
c:\folderA\folderB\folderC\client2\f2\files
c:\folderA\folderB\folderC\client3\f1\files
c:\folderA\folderB\folderC\client4\f2\files

我想复制c:\ tmp \中f1文件夹的内容来获取此

c:\tmp\client1\f1\files
c:\tmp\client2\f1\files
c:\tmp\client3\f1\files

我试过了:

copy-item -recur -path: "*/f1/" -destination: c:\tmp\

但是它复制了内容而没有正确复制结构。

15 个答案:

答案 0 :(得分:42)

在PowerShell 3.0及更高版本中,这只是通过这种方式完成的:

Get-ChildItem -Path $sourceDir | Copy-Item -Destination $targetDir -Recurse -Container

参考:Get-ChildItem

答案 1 :(得分:12)

使用xcopyrobocopy,这两者都是为此目的而设计的。假设您的路径当然只是文件系统路径。

答案 2 :(得分:11)

<强> Powershell的:

$sourceDir = 'c:\folderA\folderB\folderC\client1\f1'
$targetDir = ' c:\tmp\'

Get-ChildItem $sourceDir -filter "*" -recurse | `
    foreach{ 
        $targetFile = $targetDir + $_.FullName.SubString($sourceDir.Length); 
        New-Item -ItemType File -Path $targetFile -Force;  
        Copy-Item $_.FullName -destination $targetFile 
    } 

注意:

  • -filter“*”没有做任何事情。它只是在这里说明您是否要复制某些特定文件。例如。所有* .config文件。
  • 仍然必须使用-Force调用New-Item来实际创建文件夹结构。

答案 3 :(得分:7)

这里有另一个答案,同样的解决方案虽然不是很清楚所以我会把它扔进去,因为我花了一段时间才找到这个答案。

我一直在挖掘并找到了很多解决这个问题的方法,所有这些都是一些改动而不仅仅是一个直接的copy-item命令。在PS 3.0之前给出一些这些问题,所以答案没有错,但是使用powershell 3.0我终于能够使用-Co​​ntainer开关来实现这一点。

Copy-Item $from $to -Recurse -Container

这是我运行的测试,没有错误,目标文件夹代表相同的文件夹结构。

New-Item -ItemType dir -Name test_copy
New-Item -ItemType dir -Name test_copy\folder1
New-Item -ItemType file -Name test_copy\folder1\test.txt
#NOTE: with no \ at the end of the destination the file is created in the root of the destination, does not create the folder1 container
#Copy-Item D:\tmp\test_copy\* D:\tmp\test_copy2 -Recurse -Container

#if the destination does not exists this created the matching folder structure and file with no errors
Copy-Item D:\tmp\test_copy\* D:\tmp\test_copy2\ -Recurse -Container

希望这有助于某人

答案 4 :(得分:4)

如果要使用PowerShell正确复制文件夹结构,请执行以下操作:

$sourceDir = 'C:\source_directory'
$targetDir = 'C:\target_directory'

Get-ChildItem $sourceDir -Recurse | % {
   $dest = $targetDir + $_.FullName.SubString($sourceDir.Length)

   If (!($dest.Contains('.')) -and !(Test-Path $dest))
   {
        mkdir $dest
   }

   Copy-Item $_.FullName -Destination $dest -Force
}

这说明了创建目录并只复制文件。当然,如果您的文件夹包含句点,则需要修改上面的Contains()调用;如果您想要搜索“f1”,则需要添加过滤器。

答案 5 :(得分:3)

Container开关维护文件夹结构。享受。

testing>> tree
Folder PATH listing
Volume serial number is 12D3-1A3F
C:.
├───client1
│   ├───f1
│   │   └───files
│   └───f2
│       └───files
├───client2
│   ├───f1
│   │   └───files
│   └───f2
│       └───files
├───client3
│   └───f1
│       └───files
└───client4
    └───f2
        └───files
testing>> ls client* | % {$subdir=(join-path $_.fullname f1); $dest=(join-path temp ($_
.name +"\f1"));if(test-path ($subdir)){ copy-item $subdir $dest -recurse -container -fo
rce}}
testing>> tree
Folder PATH listing
Volume serial number is 12D3-1A3F
C:.
├───client1
│   ├───f1
│   │   └───files
│   └───f2
│       └───files
├───client2
│   ├───f1
│   │   └───files
│   └───f2
│       └───files
├───client3
│   └───f1
│       └───files
├───client4
│   └───f2
│       └───files
└───temp
    ├───client1
    │   └───f1
    │       └───files
    ├───client2
    │   └───f1
    │       └───files
    └───client3
        └───f1
            └───files
testing>>

答案 6 :(得分:2)

我需要做同样的事情,所以我找到了这个命令:

XCopy souce_path destination_path /E /C /I /F /R /Y

在你的情况下:

XCopy c:\folderA\folderB\folderC c:\tmp /E /C /I /F /R /Y

如果您需要排除某些项目,请创建包含排除列表的文本文件。 E.g:

在驱动器C:\上创建文本文件'exclude.txt'并在其中添加:

.svn
.git

你的复制命令现在看起来像这样:

XCopy c:\folderA\folderB\folderC c:\tmp /EXCLUDE:c:\exclude.txt /E /C /I /F /R /Y

答案 7 :(得分:1)

以下为我工作

@echo off
    setlocal enableextensions disabledelayedexpansion 

    set "target=e:\backup"

    for /f "usebackq delims=" %%a in ("TextFile.txt") do (
        md "%target%%%~pa" 2>nul
        copy /y "%%a" "%target%%%~pa"
    )

对于列表中的每一行(文件),在目标文件夹下创建readed行中指示的相同路径(%%〜pa是%% a引用的元素的路径)。然后,将readed文件复制到目标文件夹

答案 8 :(得分:1)

自从我花时间寻找一种更简单的方法,该方法不涉及管道或内联脚本:

Copy-Item -Path $sourceDir -Destination $destinationDir -Recurse -Container -Verbose

如果需要复制条件,则还可以提供-Filter参数。

使用PowerShell 5.1.18362.752。

来源:https://devblogs.microsoft.com/scripting/powertip-use-powershell-to-copy-items-and-retain-folder-structure/

答案 9 :(得分:0)

$sourceDir = 'C:\source_directory'
$targetDir = 'C:\target_directory'

Get-ChildItem $sourceDir -Recurse | % {
   $dest = $targetDir + $_.FullName.SubString($sourceDir.Length)

   If (!($dest.Contains('.')) -and !(Test-Path $dest))
   {
        mkdir $dest
   }

   Copy-Item $_.FullName -Destination $dest -Force
}

此代码有效,尤其是当您将Get-ChildItem与filter / where-object方法结合使用时。

但是,此代码存在一个小错误: 通过“ IF”语句和以下代码“ mkdir”,将在$ targetDir上创建文件夹...之后,命令“ copy-item”在由“ mkdir”命令创建的文件夹内创建相同的文件夹。


这里是“ Where-Object”功能如何为我工作的示例。 您可以简单地省略IF语句。

$Sourcefolder= "C:\temp1"
$Targetfolder= "C:\temp2"


$query = Get-ChildItem $Sourcefolder -Recurse | Where-Object {$_.LastWriteTime -gt [datetime]::Now.AddDays(-1)}
$query | % {
    $dest = $Targetfolder + $_.FullName.SubString($Sourcefolder.Length)
    Copy-Item $_.FullName -Destination $dest -Force
}

确保路径的末尾不带“ \”。

答案 10 :(得分:0)

我有一个相似的要求,即我只想共享库文件(不同的平台和构建类型)。我正准备编写PowerShell脚本,我意识到可以使用“ SyncBackFree”工具在不到一分钟的时间内完成该脚本。它按预期工作。

1>创建个人资料

2>选择源和目标文件夹

3>单击“选择子目录和文件

4>单击左侧的“更改过滤器”

5>添加文件扩展名(“ * .lib”)和“ * \”(用于文件夹结构)

enter image description here

答案 11 :(得分:0)

忘记复制项,它永远不会做您期望的事情,Invoke-Expression调用命令行命令并允许使用powershell变量。我在/ E上使用了较旧的xcopy命令,因此目录被复制(也为空目录)和/ Y来抑制提示并确认覆盖。

$sourceDir = "c:\source\*"
$targetDir = "c:\destination\"
Invoke-Expression "xcopy $sourceDir $targetDir /E /Y"

答案 12 :(得分:0)

通常,只要目标文件夹已经存在,Copy-Item 就会为您执行此操作。 documentation 与我通过测试验证的内容不符。目标路径中的尾部斜杠无法解决此问题。复制文件夹层次结构时,必须使用 -Recurse。 Container 参数默认为 true,您可以将其关闭。

在您的问题中,您正在根据命名的子文件夹过滤要复制的文件列表。虽然这适用于 Copy-Item 的 Path 属性,但问题是目标文件夹 ( client* ) 不存在,这就是文件被放置在目标文件夹的根目录中的原因。大多数其他答案没有专门针对这种情况,因此没有回答所提出的问题。要实现您的解决方案,这将需要两个步骤:

  1. 选择要复制的文件
  2. 将所选文件复制到目标文件夹,同时确保目标文件夹存在
$source = 'C:\FolderA\FolderB\FolderC'
$dest = 'C:\tmp'
# Only need the full name
$files = Get-ChildItem -Path $source -Recurse -File | Where-Object { $_.FullName -match '^.+\\client\d\\f1\\.+\..+$' } | ForEach-Object { $_.FullName }

# Iterate through the list copying files
foreach( $file in $files ) {
    $destFile = $file.Replace( $source, $dest )
    $destFolder = Split-Path -Path $destFile -Parent

    # Make sure the destination folder for the file exists
    if ( -not ( Test-Path -Path $destFolder ) ) {
        New-Item -Path ( Split-Path -Path $destFolder -Parent ) -Name ( Split-Path -Path $destFolder -Leaf ) -ItemType Directory -Force
    }
    
    Copy-Item -Path $file -Destination $destFolder
}

答案 13 :(得分:0)

$source ="c:\"
$destination="c:\tmp"
sl $source
md $destination
ls "." -rec -Filter *.zip | %{
$subfolder=($_.FullName)
$pathtrim=($subfolder -split [regex]::escape([system.io.path])::directoryseperatorchar)[-3] # update -2,-3 here to match output, we need 'client1\f1\files' here 
echo $pathtrim
$finaldest=Join-Path -Path $destination -ChildPath $pathtrim
cp $source $finaldest -Verbose
}

答案 14 :(得分:0)

我创建了以下函数,该函数将从目录中复制所有文件并保留文件夹结构。然后,您可以指定文件夹结构应开始的起始索引。

    function Copy-FileKeepPath {

    param (
        $filter,$FileToCopy,$des,$startIndex
    )
    Get-ChildItem -Path $FileToCopy -Filter $filter -Recurse -File | ForEach-Object {
        $fileName = $_.FullName
        #Remove the first part to ignore from the path.
        $newdes=Join-Path -Path $des -ChildPath $fileName.Substring($startIndex)
        $folder=Split-Path -Path $newdes -Parent
        $err=0
    
        #check if folder exists"
        $void=Get-Item $folder -ErrorVariable err  -ErrorAction SilentlyContinue
        if($err.Count -ne 0){
          #create when it doesn't
          $void=New-Item -Path $folder -ItemType Directory -Force -Verbose
        }

        $void=Copy-Item -Path $fileName -destination $newdes -Recurse -Container -Force -Verbose
    }
}

如下使用:

Copy-FileKeepPath -FileToCopy 'C:\folderA\folderB\folderC\client1\f1\' -des "C:\tmp" -filter * -startIndex "C:\folderA\folderB\folderC\".Length
相关问题