53 votes

Comment utiliser PowerShell copy-item et garder la structure

J'ai une structure de répertoire qui ressemble à ceci :

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

Je veux copier le contenu du f1 dossiers dans C:\tmp\ pour obtenir ce

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

J'ai essayé ça :

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

Mais il copie le contenu sans copier correctement la structure.

0voto

klaas-jan Points 17

Oubliez Copy-Item, il ne fait jamais ce que vous attendez, Invoke-Expression invoque une commande en ligne de commande et permet d'utiliser des variables powershell. J'utilise le bon vieux xcopy avec /E pour que les répertoires soient copiés (y compris les répertoires vides) et /Y pour supprimer l'invite et confirmer l'écrasement.

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

0voto

Jim Points 68

En général, Copy-Item le fait pour vous, à condition que le dossier cible existe déjà. Le site documentation ne correspond pas à ce que j'ai validé par des tests. Une barre oblique de fin dans le chemin de destination ne résout pas ce problème. Lorsque vous copiez une hiérarchie de dossiers, vous devez utiliser le paramètre -Recourse. Le paramètre Container est défini par défaut sur true (vrai), mais vous pouvez le désactiver.

Dans votre question, vous filtrez la liste des fichiers à copier en fonction d'un sous-dossier nommé. Bien que cela fonctionne pour la propriété Path de Copy-Item, le problème est que le dossier cible (client*) n'existe pas, c'est pourquoi les fichiers sont placés dans la racine du dossier cible. La majorité des autres réponses ne traitent pas spécifiquement de ce scénario et ne répondent donc pas à la question posée. Pour réaliser votre solution, il faudra procéder en deux étapes :

  1. Sélectionnez les fichiers que vous voulez copier
  2. Copier les fichiers sélectionnés dans le dossier de destination tout en s'assurant que le dossier de destination existe.

    $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

    }

0voto

Himanshu Points 81
$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
}

0voto

Darrelk Points 430

J'ai créé la fonction suivante qui copiera tous les fichiers d'un répertoire en conservant la structure du dossier. Vous pouvez ensuite spécifier l'index de départ où la structure du dossier doit commencer.

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

Utilisez-le comme suit :

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

-3voto

littleom Points 31

J'avais une exigence similaire où je voulais partager uniquement des fichiers de bibliothèque (différentes plateformes et types de construction). J'étais sur le point d'écrire mon script PowerShell, quand j'ai réalisé que cela pouvait être fait en moins d'une minute en utilisant le " SyncBackFree Outil ". Il a fonctionné comme prévu.

1> Créer un profil

2> Sélectionnez le dossier source et le dossier de destination

3> Cliquez sur "Choisir les sous-répertoires et les fichiers".

4> Cliquez sur le côté gauche "Changer le filtre".

5> Ajoutez l'extension de fichier ("*.lib") et "*\". (pour la structure du dossier)

enter image description here

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X