Skip to content

Instantly share code, notes, and snippets.

@lafleurh
Last active April 6, 2024 02:45
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lafleurh/a3877a8604758892637c3612f76bc0e3 to your computer and use it in GitHub Desktop.
Save lafleurh/a3877a8604758892637c3612f76bc0e3 to your computer and use it in GitHub Desktop.
PowerShell script to do a two-way sync of Windows folders
Param (
[string]$LeftFolder,
[string]$RightFolder
)
function CreateFolderStructure([string]$Path)
{
if (-not [string]::IsNullOrWhiteSpace($Path))
{
if (-not (Test-Path $Path))
{
$ParentPath = Split-Path $Path -Parent
CreateFolderStructure -Path $ParentPath
New-Item -Path $Path -ItemType Directory
}
}
}
function SyncFolders([string]$FldrL, [string]$FldrR)
{
Write-Host "Preparing to copy $($FldrL) to $($FldrR)"
$LeftItems = Get-ChildItem -Recurse -Path $FldrL
$RightItems = Get-ChildItem -Recurse -Path $FldrR
$Result = Compare-Object -ReferenceObject $LeftItems -DifferenceObject $RightItems -IncludeEqual
foreach ($Folder in $Result) {
$CopyFile = $false
$CopyLeft = $false
$CopyRight = $false
if ($Folder.SideIndicator -eq "==")
{
$LeftPath = $Folder.InputObject.FullName
$RightPath = $Folder.InputObject.FullName.Replace($FldrL, $FldrR)
if (Test-Path $LeftPath)
{
if (Test-Path $RightPath)
{
$LeftDate = [datetime](Get-ItemProperty -Path $LeftPath -Name LastWriteTime).LastWriteTime
$RightDate = [datetime](Get-ItemProperty -Path $RightPath -Name LastWriteTime).LastWriteTime
if ((Get-Item $LeftPath).GetType().Name -eq "FileInfo")
{
if ($LeftDate -gt $RightDate)
{
$SourcePath = $LeftPath
$TargetPath = $RightPath
$CopyFile = $true
}
if ($RightDate -gt $LeftDate)
{
$SourcePath = $RightPath
$TargetPath = $LeftPath
$CopyFile = $true
}
}
} else {
$CopyLeft = $true
}
} else {
if (Test-Path $RightPath)
{
$CopyRight = $true
}
}
}
if ($Folder.SideIndicator -eq "<=" -or $CopyLeft) {
$SourcePath = $Folder.InputObject.FullName
$TargetPath = $Folder.InputObject.FullName.Replace($FldrL, $FldrR)
$CopyFile = $true
}
if ($Folder.SideIndicator -eq "=>" -or $CopyRight) {
$SourcePath = $Folder.InputObject.FullName
$TargetPath = $Folder.InputObject.FullName.Replace($FldrR, $FldrL)
$CopyFile = $true
}
if ($CopyFile -And (Test-Path $SourcePath))
{
Write-Host "$($Folder.SideIndicator) Copying $($SourcePath) to $($TargetPath)"
$ParentPath = Split-Path $TargetPath -Parent
CreateFolderStructure -Path $ParentPath
if ((Get-Item $SourcePath).GetType().Name -eq "DirectoryInfo")
{
New-Item -Path $TargetPath -ItemType Directory
}
else
{
Copy-Item -Path $SourcePath -Destination $TargetPath
}
}
}
}
SyncFolders -FldrL (Get-Item -Path $LeftFolder).FullName -FldrR (Get-Item -Path $RightFolder).FullName
@lafleurh
Copy link
Author

lafleurh commented Aug 18, 2019

Fixed issue creating parent folders. Need to recursively create parent folders before creating files in a child folder.

Also, try this for long file name issues (this worked for me on Windows 10):

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"LongPathsEnabled"=dword:00000001

@johnlee2019
Copy link

Hi,
Can i know the sample of setting folder path?

@lafleurh
Copy link
Author

lafleurh commented Jul 2, 2020

Hi,
Can i know the sample of setting folder path?

You just do:

PS > SyncFolders.ps1 C:\temp C:\temp2

And it will make C:\temp and C:\temp2 the same.

There may be a residual bug or two in this script.

@GayanSandaruwan
Copy link

In "<=" and '=>"you have to check the LastWriteTime other wise it will be wrong

@lafleurh
Copy link
Author

In "<=" and '=>"you have to check the LastWriteTime other wise it will be wrong

When you see <= or =>, it means that the file is in one folder but not the other, so the action is to copy it to where it is missing.

@Silloky
Copy link

Silloky commented Oct 8, 2022

Thanks so much for this script ! I've been scouring the Internet for something like this for the last hour, and now I find this wonderful piece of code ! Thanks 🙏🏼

@Silloky
Copy link

Silloky commented Oct 8, 2022

Arr ! No, for some reason it creates a folder for the file when it copies the file from folder a to b.
image

@lafleurh
Copy link
Author

lafleurh commented Oct 8, 2022

@Silloky yes, it has a few issues that I never finished troubleshooting, but I used it quite a bit for even large folders. I think it's because your a and b have the same parent folder. I wrote this for copying across a network, so try much different paths.

@lafleurh
Copy link
Author

lafleurh commented Oct 8, 2022

@Silloky Fixed the issue and also fixed the recursion creating folders which was inefficient. I've learned a lot about PowerShell since I wrote this a long time ago.

@Silloky
Copy link

Silloky commented Oct 9, 2022

Great, thanks ! But I might try to code something similar to this myself for learning purposes...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment