2011-10-25 10 views
5

Ecco lo scenario: abbiamo un server Web di produzione con alcune migliaia di file e cartelle a cui è associato un "_DATE". Vogliamo spostarli in una cartella temporanea (assicurati che non siano in uso) e in un secondo momento eliminare i file.PowerShell: copia/sposta i file in base a un valore di espressione regolare, mantenendo la struttura delle cartelle, ecc.

posso usare:

Get-ChildItem -Path W:\IIS -Recurse | Where-Object{$_.Name -match "_\d{8,10}$"} 

per ottenere un elenco di tutti i file/cartelle e le loro posizioni. Ma eliminarli tutti manualmente sembra molto lavoro, soprattutto se ciò è necessario in futuro. Ho trovato alcuni esempi che quasi fare quello che voglio:

cls 

$source = "W:\IIS" 
$destination = "C:\Temp\DevTest" 

foreach ($i in Get-ChildItem -Path $source -Recurse) 
{ 
    if ($i.Name -match "_\d{8,10}$") 
    { 
     Copy-Item -Path $i.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Trim($item.Name) 
    } 
} 

E:

cls 

$source = "W:\IIS" 
$destination = "C:\Temp\DevTest" 

$bin = Get-ChildItem -Path $source -Recurse | Where-Object{$_.Name -match "_\d{8,10}$"} 

foreach ($item in $bin) { 
    Copy-Item -Path $item.FullName -Container -Destination $item.FullName.ToString().Replace($source,$destination).Trim($item.Name) -Recurse 
} 

Il problema con questi due sono che quando li provo con un copia-voce io alla fine con un directory piatta, e ho bisogno di preservare la struttura della directory in modo che se la mossa va male posso ripristinare (preferibilmente trascinare e rilasciare tutte le cartelle nella cartella IIS) o ottengo una copia di molte cartelle/file extra che non appaiono quando eseguo il primo comando.

Modifica il mio primo comando:

Get-ChildItem -Path W:\IIS -Recurse | Where-Object{$_.Name -match "_\d{8,10}$"} | Copy-Item -Container -Destination C:\Temp\DevTest -Recurse 

copierà tutto quello che ho bisogno, ma con un albero di directory piatta, piuttosto che mantenendo la struttura ad albero (ma sostituendo la directory di origine con la destinazione).

Eventuali commenti/suggerimenti?

risposta

1

Si può giocare con la seguente, che sembra ottenere il lavoro fatto (anche se può usare un po 'di refactoring). Il core è ProcessFolder(…) che viene chiamato in modo ricorsivo.

function Log 
{ 
    param($Error) 
    if(!$script:log) 
    { 
     $script:log = join-path $dst "log$timestamp.txt" 
    } 
    $timestamp 
    $timestamp >> $script:log 
    $Error 
    $Error >> $script:log 
} 

function CopyFile 
{ 
    param($Path) 
    $tmp = join-path $dst $Path.Substring($src.Length) 
    write-host "File src: $Path" 
    write-host "File dst: $tmp" 
    Try 
    { 
     #copy the file 
     copy $Path $tmp -Force 
    } 
    Catch 
    { 
     Log "ERROR copying file $Path to $tmp`:` 
     $_" 
    } 
} 

function ProcessFolder 
{ 
    param($Path) 
    $tmp = join-path $dst $Path.Substring($src.Length) 
    write-host "Dir. src: $Path" 
    write-host "Dir. dst: $tmp" 
    Try 
    { 
     #create target directory 
     New-Item $tmp -itemtype directory -force > $null 
     #process files if they match 
     dir $Path | ?{!$_.PsIsContainer -and $_.Name -match "_\d{8,10}$" } | sort | %{ CopyFile $_.FullName } 
     #process subdirectories 
     dir $Path | ?{$_.PsIsContainer} | sort | %{ ProcessFolder $_.FullName } 
     #remove target directory if it contains no files on any level 
     if(!(dir $tmp -recurse | ?{!$_.PsIsContainer})) { del $tmp -recurse } 
    } 
    Catch 
    { 
     Log "ERROR copying folder $Path to $tmp`:` 
     $_" 
    } 
} 

cls 

$src = "W:\IIS\" 
$dst = "C:\Temp\DevTest\" 
$log = $null 
$timestamp = '{0:yyyyMMddHHmmssfffffff}' -f (Get-Date) 
ProcessFolder $src 

'' 
'DONE!' 
if($log) 
{ 
    echo "Check the log file: $log" 
} 
Read-Host 
+0

Ah, non avevo visto [risposta di manojlds ] (http://stackoverflow.com/questions/7893919/powershell-copy-move-files-based-on-a-regex-value-retaining-the-folder -structu/7895211 # 7895211) ancora:] – mousio

2

Il primo dovrebbe idealmente funzionare. Conserva la struttura della directory. Ma devi stare attento a copiare le cartelle. Supponendo che si desidera solo i file nel modello che si desidera e non si preoccupano le cartelle di essere lì, si può fare qui di seguito:

$source = "W:\IIS" 
$destination = "C:\Temp\DevTest" 

if(-not (Test-Path $destination)) { mkdir $destination | out-null} 

foreach ($i in Get-ChildItem -Path $source -Recurse) 
{ 
    if (($i.Name -notmatch "_\d{8,10}$") -and (-not $i.PsIsContainer)) 
    { 
     continue; 
    } 
    Copy-Item -Path $i.FullName -Destination $i.FullName.Replace($source,$destination).Trim($i.Name) 
} 
+0

+1 Bene il tuo codice (una spiegazione) è più chiaro del mio, ma l'ho costruito all'angolo di un tavolo. – JPBlanc

+0

@ 666jfox777 - che cosa intendi quando non prendi l'espressione regolare? – manojlds

+0

@manojlds Ha copiato quasi tutte le cartelle non solo quelle che cercavo e ho finito con molte directory vuote in più che non corrispondono alla regex (_ \ d {8,10} $). – 666jfox777

1

Per me Copy-Item è un casino si può leggere altro StackOverflow risponde this one oppure this other one. Ecco una soluzione che è una sorta di "bricolage".

$source = "W:\\IIS" # Really double \ 

Get-ChildItem -Path $source -Recurse | Where-Object{($_.Name -match ""_\d{8,10}$") -or ($_.psiscontainer)} | % {copy-item $_.fullname ($_.fullname -replace $source,'C:\Temp\DevTest') } 
Problemi correlati