我需要将所有*.doc
个文件(但不是名称与*.doc
匹配的文件夹)从网络文件夹\\server\source
(包括所有嵌套文件夹中的文件)复制到本地文件夹{{ 1}}不保留嵌套文件夹层次结构(即所有文件应直接进入C:\destination
,并且不应在C:\destination
中创建嵌套文件夹。如果C:\destination
的不同子文件夹中存在多个具有相同名称的文件,则只应复制第一个文件并且永远不会覆盖 - 之后发现的所有冲突文件都应该被跳过(可能有很多这样的情况,并且跳过的文件不应该通过网络传输,否则需要花费太多时间)。这是我尝试在PowerShell中实现它:
\\server\source
此命令至少存在两个问题:
cp \\server\source\* -Recurse -Include *.doc -Container:$false -Destination C:\destination
匹配的文件夹。你能建议如何解决这些问题吗?
我们也欢迎使用*.doc
,copy
,xcopy
,robocopy
或cscript
,*.bat
的实施方案。
本地操作系统是 Windows 8 ,文件系统是NTFS。
答案 0 :(得分:15)
我会先生成文件列表,然后在列表中进行验证。
这样的事情:
$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)
};
}
因此,使用Get-ChildItem
列出与过滤器匹配的源文件夹中的文件,通过where-object
管道以删除目录。
然后遍历foreach
循环中的每个文件,并使用Exists
.NET类的system.io.file
方法检查目标中是否存在文件名(不是Fullname)。
如果没有,请仅使用原始文件名(删除原始路径)进行复制。
在测试时使用副本上的-whatif
选项,因此只显示它会执行的操作,以防结果不符合您的要求:-)
答案 1 :(得分:6)
以前的答案对我来说似乎过于复杂,除非我误解了一些事情。这应该有效:
Get-ChildItem "\\server\source\" *.doc -Recurse | ?{-not ($_.PSIsContainer -or (Test-Path "C:\Destination\$_"))} | Copy-Item -Destination "C:\Destination"
没有任何内置命令 - copy,xcopy或robocopy - 可以自己做你想做的事情,但有一个名为xxcopy的实用程序可以在http://www.xxcopy.com方便地使用。它有许多内置选项,专门用于将目录树展平为单个目录。以下将按照您的描述进行操作:
xxcopy "\\server\source\*.doc" "C:\Destination" /SGFO
但是,xxcopy有多种其他处理重复文件名的选项,而不仅仅是复制遇到的第一个文件名,例如将源目录名添加到文件名中,或者向除第一个之外的所有文件添加顺序数字标识,或者除了最新的文件之外的所有文件都添加顺序数字标识。或最古老的。有关详细信息,请参阅此页:http://www.xxcopy.com/xxcopy16.htm
答案 2 :(得分: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
答案 3 :(得分:1)
为什么在已有管道的情况下使用foreach?获胜的计算属性!
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
答案 4 :(得分: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" };
第一行读取每个* .doc文件和* .doc? (因此它也考虑Office 2010 .docx格式),不包括目录和重复文件
第二行将每个项目从目标复制到源(文件夹C:\ destination必须已存在)
一般情况下,我建议你将命令分成多行,因为它更容易生成代码(在这种情况下,第一个任务是:获取文件,第二个任务:复制文件)。