2013-07-05 11 views
11

Ho bisogno di copiare tutti i file *.doc (ma non le cartelle i cui nomi corrispondono a *.doc) da una cartella di rete \\server\source (inclusi i file in tutte le cartelle nidificate) a una cartella locale C:\destination senza preservare la gerarchia delle cartelle nidificate (ovvero tutti i file devono andare direttamente in C:\destination e nessuna cartella nidificata dovrebbe essere creata in C:\destination). Nel caso ci siano diversi file con lo stesso nome da diverse sottocartelle di \\server\source, solo il primo dovrebbe essere copiato e mai sovrascritto - tutti i file in conflitto trovati in seguito dovrebbero essere saltati (potrebbero esserci molti casi come questo, e i file saltati dovrebbero non essere trasferito sulla rete, altrimenti ci vorrebbe troppo tempo). Qui è il mio tentativo di attuarlo in PowerShell:Come copiare determinati file (senza gerarchia di cartelle), ma non sovrascrivere i file esistenti?

cp \\server\source\* -Recurse -Include *.doc -Container:$false -Destination C:\destination 

Ci sono almeno due problemi con questo comando:

  • Si copia di cartelle i cui nomi corrispondono *.doc troppo.
  • In caso di nomi in conflitto, qualsiasi file trovato successivamente viene trasferito sulla rete e sovrascrive quello precedente.

Potete suggerire come risolvere questi problemi?
Implementazioni utilizzando copy, xcopy, robocopy, cscript o *.bat, *.cmd sono anche benvenute.
Il sistema operativo locale è Windows 8 e il file system è NTFS.

+0

Qual è il comportamento previsto se lo script viene eseguito due volte? Dovrebbe ancora copiare tutto una volta? O dovrebbe copiare nulla? –

+1

@splatteredbits Si può presumere che la directory di destinazione sia inizialmente vuota. Se questa precondizione fallisce, il comportamento dello script potrebbe essere indefinito. –

risposta

14

Vorrei produrre la lista dei file prima e convalidare mentre si passa attraverso l'elenco.

Qualcosa di simile a questo:

$srcdir = "\\server\source\"; 
$destdir = "C:\destination\"; 
$files = (Get-ChildItem $SrcDir -recurse -filter *.doc | where-object {-not ($_.PSIsContainer)}); 
$files|foreach($_){ 
    if (!([system.io.file]::Exists($destdir+$_.name))){ 
       cp $_.Fullname ($destdir+$_.name) 
    }; 
} 

Quindi, utilizzare Get-ChildItem per elencare i file nella cartella di origine corrispondenti al filtro, tubo attraverso where-object mettere a nudo le directory fuori.

passare poi attraverso ogni file in un ciclo foreach e verificare se il nome del file (non Fullname) esiste nella destinazione utilizzando il metodo della classe .NET system.io.fileExists.

In caso contrario, copiare, utilizzando solo il nome file originale (eliminare il percorso originale).

Utilizzare l'opzione -whatif sulla copia quando si prova, in modo da visualizzare solo quello che avrebbe fatto, in conseguenza caso non è quello che si voleva :-)

+1

staffetta persa –

+0

Invece di '[system.io.file] :: Exists', dovresti anche essere in grado di usare' Test-File' – jessehouwing

2
# Get all *.doc files under \\server\source 
Get-ChildItem -Path \\server\source *.doc -Recurse | 
    # Filter out directores 
    Where-Object { -not $_.PsIsContainer } | 
    # Add property for destination 
    Add-Member ScriptProperty -Name Destination -Value { Join-Path 'C:\destination' $this.Name } -PassThru | 
    # Filter out files that exist on the destination 
    Where-Object { -not (Test-Path -Path $_.Destination -PathType Leaf } | 
    # Copy. 
    Copy-Item 
0
$docFiles = Get-ChildItem -Path "\\server\source" -Recurse | Where-Object {$_.Attributes.ToString() -notlike "*Directory*" -and ($_.Name -like "*.doc" -or $_.Name -like "*.doc?")} | Sort-Object -Unique; 
$docFiles | ForEach-Object { Copy-Item -Path $_.fullname -Destination "C:\destination" }; 

Prima linea letto ogni *. file doc e * .doc? (quindi considera anche il formato .docx di Office 2010), escluse le directory e i file duplicati.
Seconda riga copia ogni elemento dalla destinazione alla fonte (la cartella C: \ destinazione deve già esistere).
In generale, suggerisco di dividere il comando su più righe perché è più semplice produrre codice (in questo caso prima attività: recupera i file, seconda attività: copia i file).

6

Le risposte precedenti mi sembrano piuttosto complicate, a meno che non stia fraintendendo qualcosa. Questo dovrebbe funzionare:

Get-ChildItem "\\server\source\" *.doc -Recurse | ?{-not ($_.PSIsContainer -or (Test-Path "C:\Destination\$_"))} | Copy-Item -Destination "C:\Destination" 

Nessuno dei comandi incorporati - copia, xcopy o robocopy - farà quello che vuoi da soli, ma c'è un'utility chiamata XXCOPY che la volontà, comodamente disponibile a http://www.xxcopy.com. Ha un certo numero di opzioni built-in appositamente per appiattire gli alberi di directory in una singola directory. Di seguito farà quello che hai descritto:

xxcopy "\\server\source\*.doc" "C:\Destination" /SGFO 

Tuttavia, XXCOPY ha varie altre opzioni per la gestione nomi di file duplicati di copiare il primo incontrato, ad esempio aggiungendo il nome della directory di origine al nome del file, o l'aggiunta di identifica numeriche sequenziali a tutti tranne il primo, o tutti tranne il più nuovo o il più vecchio. Vedi questa pagina per dettagli: http://www.xxcopy.com/xxcopy16.htm

+0

Hmmm, davvero non capisco questo downvote, a meno che qualcuno non abbia fatto eccezione a il fraseggio della prima riga. Non è stato inteso come un insulto, ho solo sentito che le risposte già pubblicate stavano attraversando ulteriori passaggi per qualcosa che può essere fatto più semplicemente. La semplicità e la concisione non sono preferibili nella codifica se non si sacrifica la chiarezza? In ogni caso, l'OP ha detto esplicitamente che accoglierebbe le soluzioni usando i comandi di copia. Ho fornito informazioni su un'utility di copia di terze parti che è stata pensata per fare esattamente ciò che vuole ottenere con un singolo switch. In che modo "non è utile"? –

+0

Provato la tua opzione (la prima) - va bene, ma appiattisce la gerarchia – Archeg

+2

Appiattire la gerarchia era l'obiettivo della domanda: "senza preservare la gerarchia delle cartelle nidificate (cioè tutti i file dovrebbero andare direttamente in C: \ destinazione e no le cartelle nidificate dovrebbero essere create in C: \ destinazione) ". –

1

Perché utilizzare foreach quando si dispone già di una pipeline? Proprietà calcolate per la vittoria!

Get-ChildItem -Recurse -Path:\\Server\Path -filter:'*.doc' | 
    Where { -not $_.PSIsContainer } | 
    Group Name | 
    Select @{Name='Path'; Expression={$_.Group[0].FullName}},@{Name='Destination'; Expression={'C:\Destination\{0}' -f $_.Name}} | 
    Copy-Item 
Problemi correlati