Подтвердить что ты не робот

Как использовать PowerShell copy-item и сохранить структуру

У меня есть структура каталогов, которая выглядит следующим образом:

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

Я хочу скопировать содержимое папок f1 в C:\tmp \, чтобы получить это

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

Я попробовал это:

Copy-Item -recur -path: "*/f1/" -destination: C:\tmp\

Но он копирует содержимое без правильного копирования структуры.

4b9b3361

Ответ 1

В PowerShell версии 3.0 и новее это делается следующим образом:

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

Ссылка: Get-ChildItem

Ответ 2

Используйте xcopy или robocopy, оба из которых были разработаны именно для этой цели. Предполагая, что ваши пути - это только пути к файловой системе, конечно.

Ответ 3

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.
  • Еще нужно вызвать New-Item с -Force чтобы фактически создать структуру папок.

Ответ 4

Я покопался и нашел множество решений этой проблемы, причем все они были неким изменением, а не просто командой copy-item. Конечно, некоторые из этих вопросов предшествуют PowerShell 3.0, поэтому ответы не являются неправильными, но с помощью PowerShell 3.0 я наконец смог сделать это, используя переключатель -Container для Copy-Item:

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, and
#       it does not create the folder1 container
#Copy-Item D:\tmp\test_copy\* D:\tmp\test_copy2 -Recurse -Container

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

Ответ 5

Если вы хотите правильно скопировать структуру папок с помощью 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", как вы упомянули.

Ответ 6

Container переключатель (для Copy-Item) поддерживает структуру папок. Наслаждаться.

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 -force}}

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>>

Ответ 7

Мне нужно было сделать то же самое, поэтому я нашел эту команду:

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

И в вашем случае:

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

И если вам нужно исключить некоторые элементы, создайте текстовый файл со списком исключений. Например:.

Создайте текстовый файл exclude.txt на диске C:\и добавьте в него:

.svn
.git

И ваша команда копирования будет выглядеть следующим образом:

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

Ответ 8

Ниже работал для меня

@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"
    )

Для каждой строки (файла) в списке создайте в целевой папке один и тот же путь, указанный в строке чтения (%% ~ pa - это путь элемента, на который ссылается %% a). Затем скопируйте прочитанный файл в целевую папку.

Ответ 9

$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".


Вот пример того, как это работает для меня с функцией "Где-Объект". Вы можете просто опустить оператор 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
}

Убедитесь, что пути не указаны с "\" в конце.