(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisbon

How to synchronize two folders in PowerShell: step by step

João Barros 19 de July de 2026 3 min read

Learn how to synchronize two folders in PowerShell to maintain a consistent backup and reduce unnecessary transfers. This guide shows how to compare, copy only new or changed files and log operations, useful for local backups and simple migrations.

Prerequisites

  • PowerShell 5.1 or PowerShell 7+ installed.
  • Read permissions on the source folder and write permissions on the destination folder.
  • Sufficient free disk space on the destination folder.

Step 1: Basic structure and variables

Start by defining paths and options. Use a variable $WhatIf to run a dry-run without copying files — very useful for testing.

$Source = 'C:\Fonte'
$Destination = 'D:\Backup'
$LogFile = 'C:\Backup\sync.log'
$WhatIf = $true   # Mudar para $false para executar a cópia

# Garantir que a pasta destino existe
if (-not (Test-Path $Destination)) {
    New-Item -ItemType Directory -Path $Destination -Force | Out-Null
}

Step 2: Script to synchronize two folders (incremental copy)

The principle is simple: enumerate files in $Source, compute the relative path and compare with the corresponding file in $Destination. Copy only when the file does not exist or has changed (size or date).

$sourceFiles = Get-ChildItem -Path $Source -File -Recurse
foreach ($s in $sourceFiles) {
    $rel = $s.FullName.Substring($Source.Length).TrimStart('\')
    $destPath = Join-Path $Destination $rel
    $destDir = Split-Path $destPath -Parent

    if (-not (Test-Path $destDir)) {
        if ($WhatIf) { Write-Output "Would create folder: $destDir" }
        else { New-Item -ItemType Directory -Path $destDir -Force | Out-Null }
    }

    $copy = $true
    if (Test-Path $destPath) {
        $d = Get-Item $destPath
        if ($s.Length -eq $d.Length -and $s.LastWriteTime -le $d.LastWriteTime) { $copy = $false }
    }

    if ($copy) {
        if ($WhatIf) { Write-Output "Would copy: $rel" }
        else { Copy-Item -Path $s.FullName -Destination $destPath -Force }
    }
}

Step 3: Logging and error handling

Logging operations helps audit the process. Add Try/Catch to capture failures and write entries to the log file.

foreach ($s in $sourceFiles) {
    $rel = $s.FullName.Substring($Source.Length).TrimStart('\')
    $destPath = Join-Path $Destination $rel
    $destDir = Split-Path $destPath -Parent

    try {
        if (-not (Test-Path $destDir)) {
            if ($WhatIf) { Write-Output "Would create folder: $destDir" }
            else { New-Item -ItemType Directory -Path $destDir -Force | Out-Null }
        }

        $copy = $true
        if (Test-Path $destPath) {
            $d = Get-Item $destPath
            if ($s.Length -eq $d.Length -and $s.LastWriteTime -le $d.LastWriteTime) { $copy = $false }
        }

        if ($copy) {
            if ($WhatIf) { Write-Output "Would copy: $rel" }
            else {
                Copy-Item -Path $s.FullName -Destination $destPath -Force
                $entry = "{0} COPIED {1}" -f (Get-Date -Format s), $rel
                Add-Content -Path $LogFile -Value $entry
            }
        }
    }
    catch {
        $err = "{0} ERROR {1} - $_" -f (Get-Date -Format s), $rel
        Add-Content -Path $LogFile -Value $err
    }
}

Step 4: Optional — remove files that disappeared from the source

If you want the destination to exactly mirror the source (this example is not a two-way sync), remove files in the destination that no longer exist in the source. Always do a dry-run first.

# Cuidado: esta ação apaga ficheiros no destino
$destFiles = Get-ChildItem -Path $Destination -File -Recurse
foreach ($d in $destFiles) {
    $rel = $d.FullName.Substring($Destination.Length).TrimStart('\')
    $sourcePath = Join-Path $Source $rel
    if (-not (Test-Path $sourcePath)) {
        if ($WhatIf) { Write-Output "Would remove: $rel" }
        else { Remove-Item -Path $d.FullName -Force }
    }
}

Verify the result

To confirm the synchronization worked: 1) run the script with $WhatIf = $true and check the messages; 2) run with $WhatIf = $false on a small set of files; 3) check the $LogFile for copy/error records; 4) validate sizes and dates between $Source and $Destination with Get-ChildItem.

Conclusion

Synchronizing two folders in PowerShell is a simple, controllable solution for local backups and migrations. From this skeleton you can add filters by extension, parallelism with Start-Job or integration with compression tools. Tip: always test with $WhatIf = $true before deleting files in production — do you prefer to keep old versions or a backup history?