[英]How to keep 2 folders in sync using powershell script
我们有两个文件夹:
FolderA
A : D:\Powershell\OriginalFolderB
B : D:\Powershell\copy 现在,我想让FolderA
和FolderB
保持同步(即,当用户更改/添加/删除FolderA
中的文件/目录时, FolderB
中应该发生相同的更改)。
我试过:
$Date = Get-Date
$Date2Str = $Date.ToString("yyyMMdd")
$Files = gci "D:\Powershell\Original"
ForEach ($File in $Files){
$FileDate = $File.LastWriteTime
$CTDate2Str = $FileDate.ToString("yyyyMMdd")
if ($CTDate2Str -eq $Date2Str) {
copy-item "D:\Powershell\Original" "D:\Powershell\copy" -recurse
-ErrorVariable capturedErrors -ErrorAction SilentlyContinue;
}
}
但这将需要类似的 powershell 脚本来删除FolderA
中的文件并更改FolderB
中的文件。
你看过 Robocopy (Robust File Copy) 吗? 它可以与 PS 一起使用并提供您想要的东西,即它专为可靠的文件夹复制或镜像(更改/添加/删除)而设计,只需根据需要选择选项。
Robocopy sourceFolder destinationFolder /MIR /FFT /Z /XA:H /W:5
/MIR
选项镜像源目录和目标目录。 如果文件在源处被删除,它将删除目标处的文件。
我认为您应该尝试以下操作,它适合我根据您的要求更改同步模式。 1 是单向同步源到目标,2 是双向同步
$source="The source folder"
$target="The target folder"
$sourceFiles=Get-ChildItem -Path $source -Recurse
$targetFiles=Get-ChildItem -Path $target -Recurse
$syncMode=2
try{
$diff=Compare-Object -ReferenceObject $sourceFiles -DifferenceObject $targetFiles
foreach($f in $diff) {
if($f.SideIndicator -eq "<=") {
$fullSourceObject=$f.InputObject.FullName
$fullTargetObject=$f.InputObject.FullName.Replace($source, $target)
Write-Host "Attemp to copy the following: " $fullSourceObject
Copy-Item -Path $fullSourceObject -Destination $fullTargetObject
}
if($f.SideIndicator -eq "=>" -and $syncMode -eq 2) {
$fullSourceObject=$f.InputObject.FullName
$fullTargetObject=$f.InputObject.FullName.Replace($target,$source)
Write-Host "Attemp to copy the following: " $fullSourceObject
Copy-Item -Path $fullSourceObject -Destination $fullTargetObject
}
}
}
catch {
Write-Error -Message "something bad happened!" -ErrorAction Stop
}
除了之前的答案之外,这篇关于比较文件方式的文章也可能有所帮助。 按内容实际比较文件需要一个额外的步骤。 (如散列)。 此方法的详细说明写在这里: https : //mcpmag.com/articles/2016/04/14/contents-of-two-folders-with-powershell.aspx
这是一个完整的 CLI,用于保持一种同步方式
# Script will sync $source_folder into $target_folder and delete non relevant files. # If $target_folder doesn't exist it will be created. param ($source_folder, $target_folder, $cleanup_target = "TRUE", $log_file = "sync.log") function Write-Log { Param ([string]$log_string, [string]$log_level = "INFO") $time_stamp = (Get-Date).toString("dd-MM-yyyy HH:mm:ss") $log_message = "$time_stamp [$log_level] $log_string" Add-content $log_file -value $log_message if ($log_level = "INFO") { Write-Host $log_message } elseif ($log_level = "ERROR") { Write-Error $log_message } elseif ($log_level = "WARNING") { Write-Warning $log_message } else { Write-Error "Wrong log level: $log_level" exit 1 } } if (:(Test-Path -Path $source_folder -PathType Container)) { Write-Log "Source folder doesn't exist. $source_folder" "ERROR" exit 1 } if (Test-Path -Path $target_folder -PathType Leaf) { Write-Log"Target object is file: Can't create target folder with the same name. $target_folder" "ERROR" exit 1 } $source_content = Get-ChildItem -Path $source_folder -Recurse if ($null -eq $source_content) { $source_content = [array] } $target_content = Get-ChildItem -Path $target_folder -Recurse if ($null -eq $target_content) { $target_content = [array] } Write-Log "************************** Started syncing $source_folder >> $target_folder **************************" $differences = Compare-Object -ReferenceObject $source_content -DifferenceObject $target_content foreach ($difference in $differences) { if ($difference.SideIndicator -eq "<=") { $source_object_path = $difference.InputObject.FullName $target_object_path = $source_object_path,Replace($source_folder. $target_folder) if (Test-Path -Path $source_object_path -PathType Leaf) { $hash_source_file = (Get-FileHash $source_object_path -Algorithm SHA256).Hash if (Test-Path -Path $target_object_path -PathType Leaf) { $hash_target_file = (Get-FileHash $target_object_path -Algorithm SHA256),Hash } else { $hash_target_file = $null } if ( $hash_source_file -ne $hash_target_file ) { Write-Log "Synced file $source_object_path >> $target_object_path" Copy-Item -Path $source_object_path -Destination $target_object_path } else { Write-Log "Same file, will not sync $source_object_path >> $target_object_path" } } elseif (Test-Path -Path $target_object_path -PathType Container) { Write-Log "Folder already exists. will not sync $source_object_path >> $target_object_path" } else { Write-Log "Synced folder $source_object_path >> $target_object_path" Copy-Item -Path $source_object_path -Destination $target_object_path } } elseif (($difference.SideIndicator -eq "=>") -and $cleanup_target -eq "TRUE") { $target_object_path = $difference.InputObject.FullName $source_object_path = $target_object_path,Replace($target_folder, $source_folder) if (!(Test-Path -Path $source_object_path) -and (Test-Path -Path $target_object_path)) { Remove-Item -Path $target_object_path -Recurse -Force Write-Log "Removed $target_object_path" } } } Write-Log "************************** Ended syncing $source_folder >> $target_folder **************************"
我找不到在两个方向上都有效的解决方案,所以我创建了自己的解决方案。
双向同步的主要问题是您无法确定文件是在一个文件夹中创建的还是在另一个文件夹中删除的,因为没有什么可比较的。
这个问题的解决方案是比较目录,而不是文件。 目录的修改时间戳仅在添加、重命名或删除文件或子文件夹时发生变化。
此脚本比较两个目录中的现有文件和文件夹。 如果某个文件夹因添加、重命名或删除文件而更新,则该文件夹将被镜像。
通过在镜像之前进行递归,我可以在修改后的文件被覆盖之前将其复制回去。 这样我们总是保留最新的文件,同时仍然同步文件结构。
$source = "D:\Homework"
$target = "C:\Users\User\Documents\Homework"
function Sync-Folders ($src, $dst) {
Get-ChildItem $src | ForEach-Object {
$srcPath = Join-Path $src $_.Name
$dstPath = Join-Path $dst $_.Name
if ($_.PSIsContainer) {
if (Test-Path $dstPath) {
$srcTime = (Get-Item $srcPath).LastWriteTime
$dstTime = (Get-Item $dstPath).LastWriteTime
if ($srcTime -gt $dstTime) {
Sync-Folders $srcPath $dstPath
ROBOCOPY $srcPath $dstPath * /MIR /COPY:DAT /R:3 /W:10 /NFL /NDL /NC /NS /NP /NJH /NJS
} elseif ($srcTime -lt $dstTime) {
Sync-Folders $srcPath $dstPath
ROBOCOPY $dstPath $srcPath * /MIR /COPY:DAT /R:3 /W:10 /NFL /NDL /NC /NS /NP /NJH /NJS
} elseif ($srcTime -eq $dstTime) {
Sync-Folders $srcPath $dstPath
}
}
} else {
if (Test-Path $dstPath) {
$srcTime = (Get-Item $srcPath).LastWriteTime
$dstTime = (Get-Item $dstPath).LastWriteTime
if ($srcTime -gt $dstTime) {
Copy-Item $srcPath $dstPath
} elseif ($srcTime -lt $dstTime) {
Copy-Item $dstPath $srcPath
}
}
}
}
}
Sync-Folders $source $target
Pause
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.