79 votes

La liste d'exclusion dans PowerShell Copy-Item ne semble pas fonctionner

J'ai le snippet suivant de PowerShell script :

$source = 'd:\t1\*'
$dest = 'd:\t2'
$exclude = @('*.pdb','*.config')
Copy-Item $source $dest -Recurse -Force -Exclude $exclude

Ce qui fonctionne pour copier tous les fichiers et dossiers de t1 à t2, mais il n'exclut la liste d'exclusion que dans le dossier "Root"/"premier niveau" et pas dans les sous-dossiers.

Comment faire pour qu'il exclue la liste d'exclusion dans tous les dossiers ?

107voto

landyman Points 1084

Je pense que le meilleur moyen est d'utiliser Get-ChildItem et d'insérer la commande Copy-Item.

J'ai trouvé que cela fonctionnait :

$source = 'd:\t1'
$dest = 'd:\t2'
$exclude = @('*.pdb','*.config')
Get-ChildItem $source -Recurse -Exclude $exclude | Copy-Item -Destination {Join-Path $dest $_.FullName.Substring($source.length)}

En gros, ce qui se passe ici, c'est que vous passez en revue les fichiers valides un par un, puis vous les copiez vers le nouveau chemin. L'instruction "Join-Path" à la fin permet de conserver les répertoires lors de la copie des fichiers. Cette partie prend le répertoire de destination et le joint au répertoire situé après le chemin source.

J'ai eu l'idée de aquí et l'a modifié un peu pour l'adapter à cet exemple.

J'espère que ça marchera !

1 votes

C'est justement la solution que j'allais poster :) J'ai constaté que -Include et -Exclude ne fonctionnent pas correctement pour Select-String, Copy-Item, et certaines autres commandes. Cela fonctionne bien pour Get-ChildItem (dir).

0 votes

Si vous consultez le fichier d'aide de ces cmdlets, vous constaterez que ces paramètres ne fonctionnent pas comme prévu. Expédier, c'est choisir.

3 votes

Notez que si la $source est un objet chemin, alors vous devez écrire "$source.chemin.longueur" pour obtenir la longueur.

7voto

Shrike Points 2594

Comme les commentaires formatent mal le code je vais poster comme réponse mais c'est juste un complément à la réponse de @landyman. Le script proposé a un inconvénient - il créera des dossiers doublement imbriqués. Par exemple, pour 'd : \t1\sub1 il créera un répertoire vide 'd : \t2\sub1\sub1 '. Cela est dû au fait que Copy-Item pour les répertoires attend le nom du répertoire parent dans la propriété -Destination et non le nom du répertoire lui-même. Voici une solution de contournement que j'ai trouvée :

Get-ChildItem -Path $from -Recurse -Exclude $exclude | Copy-Item -Force -Destination {
  if ($_.GetType() -eq [System.IO.FileInfo]) {
    Join-Path $to $_.FullName.Substring($from.length)
  } else {
    Join-Path $to $_.Parent.FullName.Substring($from.length)
  }
}

1 votes

Merci ! J'ai rencontré exactement le même problème.

5voto

danglund Points 1006

Le paramètre exclude ne fonctionne pas avec les répertoires. Une variante du script de Bo fait l'affaire :

$source = 'c:\tmp\foo'
$dest = 'c:\temp\foo'
$exclude = '\.bak'
Get-ChildItem $source -Recurse  | where {$_.FullName -notmatch $exclude} | 
    Copy-Item -Destination {Join-Path $dest $_.FullName.Substring($source.length)}

1 votes

Votre clause 'where' va en fait 'notmatch' sur l'expression régulière ".bak", c'est-à-dire "[any character]bak". Votre expression régulière doit être ' \.bak ou vous devriez utiliser '-notlike' si vous voulez une correspondance directe entre les chaînes de caractères.

3voto

Robert Cohn Points 11

Je cherchais un moyen de copier les fichiers modifiés après une certaine date/heure afin de les archiver. De cette façon, je pourrais sauvegarder exactement les fichiers sur lesquels j'ai travaillé (en supposant que je sache quand j'ai commencé). (Oui, je sais que c'est à cela que sert SCM, mais il y a des fois où je veux juste faire un instantané de mon travail sans l'enregistrer).

En utilisant le conseil de Landyman, et des trucs que j'ai trouvés ailleurs, j'ai trouvé que ça marchait :

$source = 'c:\tmp\foo'
$dest = 'c:\temp\foo'
$exclude = @('*.pdb', '*.config')
Get-ChildItem $source -Recurse -Exclude $exclude |  
    where-object {$_.lastwritetime -gt "8/24/2011 10:26 pm"} | 
    Copy-Item -Destination {Join-Path $dest $_.FullName.Substring($source.length)}

0voto

bernd_k Points 3684

J'ai eu un problème similaire en l'étendant un peu. Je veux une solution qui fonctionne pour des sources comme

$source = "D:\scripts\*.sql"

aussi. J'ai trouvé cette solution :

function Copy-ToCreateFolder
{
    param(
        [string]$src,
        [string]$dest,
        $exclude,
        [switch]$Recurse
    )

    # The problem with Copy-Item -Rec -Exclude is that -exclude effects only top-level files
    # Copy-Item $src $dest    -Exclude $exclude       -EA silentlycontinue -Recurse:$recurse
    # http://stackoverflow.com/questions/731752/exclude-list-in-powershell-copy-item-does-not-appear-to-be-working

    if (Test-Path($src))
    {
        # Nonstandard: I create destination directories on the fly
        [void](New-Item $dest -itemtype directory -EA silentlycontinue )
        Get-ChildItem -Path $src -Force -exclude $exclude | % {

            if ($_.psIsContainer)
            {
                if ($Recurse) # Non-standard: I don't want to copy empty directories
                {
                    $sub = $_
                    $p = Split-path $sub
                    $currentfolder = Split-Path $sub -leaf
                    #Get-ChildItem $_ -rec -name  -exclude $exclude -Force | % {  "{0}    {1}" -f $p, "$currentfolder\$_" }
                    [void](New-item $dest\$currentfolder -type directory -ea silentlycontinue)
                    Get-ChildItem $_ -Recurse:$Recurse -name  -exclude $exclude -Force | % {  Copy-item $sub\$_ $dest\$currentfolder\$_ }
                }
            }
            else
            {

                #"{0}    {1}" -f (split-path $_.fullname), (split-path $_.fullname -leaf)
                Copy-Item $_ $dest
            }
        }
    }
}

0 votes

Il y a des problèmes avec le dernier élément de copie qui ne fonctionne pas si vous êtes dans un dossier imbriqué.

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