Jak skopiować określone pliki (bez hierarchii folderów), ale nie nadpisać istniejących plików?

Muszę skopiować wszystkie pliki *.doc (ale nie foldery, których nazwy pasują do *.doc) z folderu sieciowego \\server\source (w tym pliki we wszystkich zagnieżdżonych folderach) do folderu lokalnego C:\destination bez zachowania hierarchii zagnieżdżonych folderów (tzn. wszystkie pliki powinny iść bezpośrednio do C:\destination, A żadne zagnieżdżone foldery nie powinny być tworzone w C:\destination). W przypadku, gdy istnieje kilka plików o tej samej nazwie z różnych podfolderów \\server\source, tylko pierwszy z nich powinien być skopiowany i nigdy nie nadpisany - wszystkie sprzeczne pliki znalezione później powinny być pomijane (może być wiele takich przypadków, a pomijane pliki nie powinny być przesyłane przez sieć, w przeciwnym razie zajęłoby to zbyt dużo czasu). Oto moja próba zaimplementowania go w PowerShell:

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

IstniejÄ… co najmniej dwa problemy z tÄ… komendÄ…:

  • kopiuje foldery, których nazwy pasujÄ… *.doc.
  • W przypadku sprzecznych nazw każdy plik znaleziony później jest przesyÅ‚any przez Sieć i nadpisuje poprzedni jeden.

Czy możesz zasugerować, jak rozwiązać te problemy?
Wdrożenia z wykorzystaniem copy, xcopy, robocopy, cscript lub *.bat, *.cmd są również mile widziane.
Lokalny system operacyjny to Windows 8, a system plików to NTFS.

Author: Vladimir Reshetnikov, 2013-07-06

5 answers

Najpierw sporządziłbym listę plików i zatwierdził ją podczas przeglądania listy.

CoÅ› takiego:

$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)
    };
}

Więc użyj Get-ChildItem, Aby wyświetlić listę plików w folderze źródłowym pasujących do filtra, Przełącz where-object, aby usunąć katalogi.

Następnie przejrzyj każdy plik w pętli foreach i sprawdź, czy nazwa pliku (nie pełna) istnieje w miejscu docelowym, używając metody Exists klasy system.io.file. NET.

Jeśli nie, skopiuj, używając tylko oryginalnej nazwy pliku (upuszczając oryginał ścieżka).

Użyj opcji -whatif na kopii podczas testowania, więc wyświetla tylko to, co zrobi, na wypadek, gdyby wynik nie był tym, czego chciałeś: -)

 14
Author: Graham Gold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-23 12:01:00

Poprzednie odpowiedzi wydają mi się zbyt skomplikowane, chyba że coś źle zrozumiałem. Powinno działać:

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

Żadne z wbudowanych poleceń-copy, xcopy lub robocopy-nie zrobi tego, co chcesz na własną rękę, ale istnieje narzędzie o nazwie xxcopy, które będzie, wygodnie dostępne na http://www.xxcopy.com . posiada wiele wbudowanych opcji specjalnie do spłaszczania drzew katalogów w jeden katalog. Następujące rzeczy zrobią to, co Ty opisany:

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

Jednak xxcopy ma wiele innych opcji obsługi zduplikowanych nazw plików niż tylko kopiowanie pierwszej napotkanej, takich jak dodawanie nazwy katalogu źródłowego do nazwy pliku lub dodawanie sekwencyjnych identyfikatorów numerycznych do wszystkich oprócz pierwszej, lub wszystkich oprócz najnowszej lub najstarszej. Szczegóły na tej stronie: http://www.xxcopy.com/xxcopy16.htm

 6
Author: Adi Inbar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-09 18:32:42
# 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
 2
Author: Aaron Jensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-09 08:04:31

Po co używać foreach, skoro masz już rurociąg? Obliczone właściwości na wygraną!

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
 1
Author: Eris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-13 01:55:27
$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" };

Pierwsza linijka czyta każdy*.plik doc i *.doktorze? (rozważa więc również Office 2010 .format docx), z wyłączeniem katalogów i duplikatów plików.
Druga linia kopiuje każdy element z miejsca docelowego do źródła (folder C:\destination musi już istnieć).
Ogólnie proponuję podzielić polecenie na kilka linii, ponieważ łatwiej jest wyprodukować kod (w tym przypadku pierwsze zadanie: get files, drugie zadanie: copy files).

 0
Author: Naigel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-09 10:03:54