Skip to content

Instantly share code, notes, and snippets.

@iamrobert
Last active January 17, 2025 12:03
Show Gist options
  • Save iamrobert/1524d7e626bb1367b58123eae38eaf17 to your computer and use it in GitHub Desktop.
Save iamrobert/1524d7e626bb1367b58123eae38eaf17 to your computer and use it in GitHub Desktop.
A PowerShell script to monitor and sync changes between source and destination directories.
# Define the project name variable
$projectName = "jy"
# Define source and destination paths
$templateSrc = "D:\2025-laragon\www\$projectName\templates\iamrobert4"
$templateDst = "D:\bitbucket\$projectName"
$mediaSrc = "D:\2025-laragon\www\$projectName\media\templates\site\iamrobert4"
$mediaDst = "D:\bitbucket\$projectName\media\templates\site\iamrobert4"
# Function to compare and sync files
function Sync-Files {
param (
[string]$sourcePath,
[string]$destPath,
[bool]$isTemplate = $false
)
# First, remove any unauthorized items from destination
Write-Host "Checking for unauthorized items in destination..." -ForegroundColor Yellow
if (Test-Path $destPath) {
$destItems = Get-ChildItem -Path $destPath -Recurse -Force -ErrorAction SilentlyContinue
foreach ($destItem in $destItems) {
# Skip .git directory and its contents
if ($destItem.FullName -like "*\.git*") {
continue
}
$relativePath = $destItem.FullName.Replace($destPath, "")
$sourceItem = Join-Path $sourcePath $relativePath
if (!(Test-Path $sourceItem)) {
Write-Host "Removing unauthorized item: $($destItem.FullName)" -ForegroundColor Red
Remove-Item -Path $destItem.FullName -Force -Recurse
}
}
}
# Get all files from source
$sourceFiles = Get-ChildItem -Path $sourcePath -Recurse -File
foreach ($sourceFile in $sourceFiles) {
# Calculate destination path
if ($isTemplate) {
$relativePath = $sourceFile.FullName.Replace($templateSrc, "")
$destFile = Join-Path $templateDst $relativePath
} else {
$relativePath = $sourceFile.FullName.Replace($mediaSrc, "")
$destFile = Join-Path $mediaDst $relativePath
}
# Check if destination file exists
if (Test-Path $destFile) {
$destFileInfo = Get-Item $destFile
# Compare last write time and size
if ($sourceFile.LastWriteTime -ne $destFileInfo.LastWriteTime -or
$sourceFile.Length -ne $destFileInfo.Length) {
# Files are different, copy the source file
Write-Host "Updating: $destFile" -ForegroundColor Yellow
$destFolder = Split-Path -Parent $destFile
if (!(Test-Path $destFolder)) {
New-Item -ItemType Directory -Path $destFolder -Force | Out-Null
}
Copy-Item -Path $sourceFile.FullName -Destination $destFile -Force
}
} else {
# Destination file doesn't exist, copy it
Write-Host "Creating new file: $destFile" -ForegroundColor Green
$destFolder = Split-Path -Parent $destFile
if (!(Test-Path $destFolder)) {
New-Item -ItemType Directory -Path $destFolder -Force | Out-Null
}
Copy-Item -Path $sourceFile.FullName -Destination $destFile -Force
}
}
}
# Perform initial sync
Write-Host "Performing initial sync..." -ForegroundColor Cyan
Sync-Files -sourcePath $templateSrc -destPath $templateDst -isTemplate $true
Sync-Files -sourcePath $mediaSrc -destPath $mediaDst -isTemplate $false
Write-Host "Initial sync completed" -ForegroundColor Cyan
# Define the action to perform on file changes
$action = {
# Get the changed item and calculate its destination
$changedItem = $Event.SourceEventArgs.FullPath
# Different replacement logic for template and media files
if ($changedItem.Contains("\templates\iamrobert4")) {
# For template files, copy to root
$destination = $changedItem -replace [regex]::Escape("D:\2025-laragon\www\$projectName\templates\iamrobert4"), "D:\bitbucket\$projectName"
# Re-run sync to clean up unauthorized items
Sync-Files -sourcePath $templateSrc -destPath $templateDst -isTemplate $true
} else {
# For media files, maintain structure
$destination = $changedItem -replace [regex]::Escape("D:\2025-laragon\www\$projectName"), "D:\bitbucket\$projectName"
# Re-run sync to clean up unauthorized items
Sync-Files -sourcePath $mediaSrc -destPath $mediaDst -isTemplate $false
}
Write-Host "Change detected: $changedItem" -ForegroundColor Yellow
# Check if the changed item exists (file or folder)
if (Test-Path $changedItem) {
# Ensure the parent folder exists at the destination
$destinationParent = Split-Path -Parent $destination
if (!(Test-Path $destinationParent)) {
New-Item -ItemType Directory -Path $destinationParent | Out-Null
}
# Copy the changed file or folder to the destination
Write-Host "Copying $changedItem to $destination" -ForegroundColor Green
Copy-Item -Path $changedItem -Destination $destination -Recurse -Force
} else {
# Handle deleted items
if (Test-Path $destination) {
Write-Host "Deleting $destination as it no longer exists in source" -ForegroundColor Red
Remove-Item -Path $destination -Recurse -Force
} else {
Write-Host "Item $changedItem no longer exists and was not found in destination" -ForegroundColor DarkYellow
}
}
}
# Set up the FileSystemWatcher for the templates folder
$templateWatcher = New-Object System.IO.FileSystemWatcher
$templateWatcher.Path = $templateSrc
$templateWatcher.IncludeSubdirectories = $true
$templateWatcher.EnableRaisingEvents = $true
# Set up the FileSystemWatcher for the media folder
$mediaWatcher = New-Object System.IO.FileSystemWatcher
$mediaWatcher.Path = $mediaSrc
$mediaWatcher.IncludeSubdirectories = $true
$mediaWatcher.EnableRaisingEvents = $true
# Register the event handlers for templates
Register-ObjectEvent $templateWatcher Changed -Action $action
Register-ObjectEvent $templateWatcher Created -Action $action
Register-ObjectEvent $templateWatcher Deleted -Action $action
Register-ObjectEvent $templateWatcher Renamed -Action $action
# Register the event handlers for media
Register-ObjectEvent $mediaWatcher Changed -Action $action
Register-ObjectEvent $mediaWatcher Created -Action $action
Register-ObjectEvent $mediaWatcher Deleted -Action $action
Register-ObjectEvent $mediaWatcher Renamed -Action $action
# Keep the script running
Write-Host "Monitoring folders for changes... Press Ctrl+C to stop." -ForegroundColor Cyan
Write-Host "Project being monitored: $projectName" -ForegroundColor Cyan
while ($true) { Start-Sleep -Seconds 1 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment