(feature): freefilesync batch automation example

This commit is contained in:
Maksym Sadovnychyy 2026-01-25 14:18:40 +01:00
parent f337212eee
commit 20c7419b75
6 changed files with 916 additions and 0 deletions

View File

@ -34,6 +34,7 @@ Designed for system administrators — and also for those who *feel like* system
## Scripts Examples
- [Hyper-V Backup](./examples/HyperV-Backup/README.md) - Production-ready Hyper-V VM backup solution with scheduling and retention management
- [File-Sync](./examples//File-Sync/README.md) - [FreeFileSync](https://freefilesync.org/) batch job execution
---

View File

@ -0,0 +1,388 @@
# File Sync Script
**Version:** 1.0.0
**Last Updated:** 2026-01-24
## Overview
Production-ready automated file synchronization solution using FreeFileSync with scheduling, secure credential management, and remote storage support.
## Features
- ✅ **Automated File Sync** - Executes FreeFileSync batch jobs on schedule
- ✅ **Flexible Scheduling** - Schedule sync by month, weekday, and time with interval control
- ✅ **Remote Storage Support** - Sync to UNC shares with secure credential management
- ✅ **Prerequisite Validation** - Checks FreeFileSync installation before execution
- ✅ **Process Management** - Proper cleanup of FreeFileSync process on exit
- ✅ **Detailed Logging** - Comprehensive logging with timestamps and severity levels
- ✅ **Lock Files** - Prevents concurrent execution
- ✅ **Error Handling** - Proper exit codes and error reporting
## Requirements
### System Requirements
- Windows with PowerShell 5.1 or later
- FreeFileSync installed (free download from https://freefilesync.org/)
- Network access to target share (if using UNC paths)
### Dependencies
- `SchedulerTemplate.psm1` module (located in parent directory)
- `scriptsettings.json` configuration file
- `sync.ffs_batch` FreeFileSync batch configuration file
## File Structure
```
File-Sync/
├── file-sync.bat # Batch launcher with admin check
├── file-sync.ps1 # Main PowerShell script
├── scriptsettings.json # Configuration file
├── sync.ffs_batch # FreeFileSync batch configuration
└── README.md # This file
```
## Installation
1. **Install FreeFileSync**
Download and install from https://freefilesync.org/
Default installation path: `C:\Program Files\FreeFileSync\FreeFileSync.exe`
2. **Copy Files**
```powershell
# Copy the entire File-Sync folder to your desired location
# Ensure SchedulerTemplate.psm1 is in the parent directory
```
3. **Create FreeFileSync Batch Configuration**
Use FreeFileSync GUI to:
- Configure source and destination folders
- Set synchronization settings (Mirror, Two-way, Update, etc.)
- Save as batch job: `sync.ffs_batch` in the File-Sync directory
4. **Configure Settings**
Edit `scriptsettings.json` with your environment settings:
```json
{
"schedule": {
"runMonth": [],
"runWeekday": ["Monday"],
"runTime": ["00:00"],
"minIntervalMinutes": 10
},
"freeFileSyncExe": "C:\\Program Files\\FreeFileSync\\FreeFileSync.exe",
"batchFile": "sync.ffs_batch",
"nasRootShare": "\\\\your-nas\\share",
"credentialEnvVar": "YOUR_ENV_VAR_NAME"
}
```
5. **Setup Credentials (for UNC paths)**
If syncing to a network share, create a Machine-level environment variable:
```powershell
# Create Base64-encoded credentials
$username = "DOMAIN\user"
$password = "your-password"
$creds = "$username:$password"
$encoded = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($creds))
# Set Machine-level environment variable
[System.Environment]::SetEnvironmentVariable("YOUR_ENV_VAR_NAME", $encoded, "Machine")
```
6. **Test Manual Execution**
```powershell
# Run as Administrator
.\file-sync.bat
# or
.\file-sync.ps1
```
## Configuration Reference
### Schedule Settings
| Property | Type | Description | Example |
|----------|------|-------------|---------|
| `runMonth` | array | Month names to run. Empty = every month | `["January", "June", "December"]` or `[]` |
| `runWeekday` | array | Weekday names to run. Empty = every day | `["Monday", "Friday"]` |
| `runTime` | array | UTC times to run (HH:mm format) | `["00:00", "12:00"]` |
| `minIntervalMinutes` | number | Minimum minutes between runs | `10` |
### Sync Settings
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `freeFileSyncExe` | string | Yes | Full path to FreeFileSync.exe executable |
| `batchFile` | string | Yes | FreeFileSync batch file name (must be in same directory). Configure all sync paths directly in this file. |
| `nasRootShare` | string | Yes | UNC path to NAS root share for authentication only |
| `credentialEnvVar` | string | No* | Name of Machine-level environment variable with credentials (*Required for UNC paths) |
### Version Tracking
| Property | Type | Description |
|----------|------|-------------|
| `version` | string | Configuration schema version |
| `lastModified` | string | Last modification date (YYYY-MM-DD) |
## Usage
### Manual Execution
**Using Batch File (Recommended):**
```batch
REM Right-click and select "Run as administrator"
file-sync.bat
```
**Using PowerShell:**
```powershell
# Run as Administrator
.\file-sync.ps1
# With verbose output
.\file-sync.ps1 -Verbose
```
### Automated Execution
The script supports automated execution through the UScheduler service:
```powershell
# Called by scheduler with -Automated flag
.\file-sync.ps1 -Automated -CurrentDateTimeUtc "2026-01-24 00:00:00"
```
When `-Automated` is specified:
- Schedule is enforced (month, weekday, time)
- Lock files prevent concurrent execution
- Interval checking prevents duplicate runs
- Logs are formatted for service logger (no timestamps)
## How It Works
### Sync Process Flow
1. **Initialization**
- Load SchedulerTemplate.psm1 module
- Load and validate scriptsettings.json
- Validate required settings
- Construct batch file path
2. **Pre-flight Checks**
- Verify FreeFileSync executable exists
- Check FreeFileSync version
- Verify batch configuration file exists
- Authenticate to NAS share (if UNC)
- Verify NAS reachability
3. **Sync Execution**
- Launch FreeFileSync in silent mode
- Capture stdout and stderr
- Monitor process completion
- Interpret exit code
4. **Cleanup**
- Terminate FreeFileSync if script exits
- Display sync summary
### FreeFileSync Exit Codes
| Code | Meaning | Script Action |
|------|---------|---------------|
| 0 | Success | Mark as successful, exit 0 |
| 1 | Warning (sync completed with warnings) | Mark as successful, exit 0 |
| 2 | Error | Mark as failed, exit 1 |
| 3 | Cancelled | Mark as failed, exit 1 |
### Lock and State Files
When running in automated mode, the script creates:
- `file-sync.lock` - Prevents concurrent execution
- `file-sync.lastRun` - Tracks last execution time for interval control
## Logging
### Log Levels
| Level | Description | Color (Manual) |
|-------|-------------|----------------|
| `Info` | Informational messages | White |
| `Success` | Successful operations | Green |
| `Warning` | Non-critical issues | Yellow |
| `Error` | Critical errors | Red |
### Log Format
**Manual Execution:**
```
[2026-01-24 00:00:00] [Info] FreeFileSync Process Started
[2026-01-24 00:00:01] [Success] All prerequisites passed
[2026-01-24 00:05:30] [Success] FreeFileSync completed successfully
```
**Automated Execution:**
```
[Info] FreeFileSync Process Started
[Success] All prerequisites passed
[Success] FreeFileSync completed successfully
```
## Exit Codes
| Code | Description |
|------|-------------|
| `0` | Success (including warnings) |
| `1` | Error occurred (module load, config, prerequisites, sync failure) |
## Troubleshooting
### Common Issues
**1. Module Not Found**
```
Error: Failed to load SchedulerTemplate.psm1
```
**Solution:** Ensure SchedulerTemplate.psm1 is in the parent directory (`../SchedulerTemplate.psm1`)
**2. FreeFileSync Not Found**
```
Error: FreeFileSync not found: C:\Program Files\FreeFileSync\FreeFileSync.exe
```
**Solution:**
- Install FreeFileSync from https://freefilesync.org/
- Update `freeFileSyncExe` path in scriptsettings.json if installed to custom location
**3. Batch File Not Found**
```
Error: Batch config not found
```
**Solution:**
- Create FreeFileSync batch configuration using FreeFileSync GUI
- Save as `sync.ffs_batch` in the File-Sync directory
- Update `batchFile` setting if using different name
**4. UNC Path Authentication Failed**
```
Error: Failed to connect to \\server\share
```
**Solution:**
- Verify `credentialEnvVar` is set in scriptsettings.json
- Verify environment variable exists at Machine level
- Verify credentials are Base64-encoded in format: `username:password`
- Test with: `net use \\server\share` manually
**5. Lock File Exists**
```
Guard: Lock file exists. Skipping.
```
**Solution:**
- Another instance is running, or previous run didn't complete
- Manually delete `.lock` file if stuck
- Check for hung PowerShell or FreeFileSync processes
**6. FreeFileSync Errors**
```
Error: FreeFileSync completed with errors (exit code 2)
```
**Solution:**
- Check FreeFileSync output in logs
- Verify source and destination paths are accessible
- Review FreeFileSync batch configuration
- Check file/folder permissions
### Debug Mode
Run with verbose output:
```powershell
.\file-sync.ps1 -Verbose
```
## Best Practices
1. **Test First** - Always test sync manually before scheduling
2. **Backup First** - Ensure you have backups before first sync
3. **Verify Paths** - Double-check source and destination paths in batch file
4. **Monitor Logs** - Check sync summaries regularly
5. **Secure Credentials** - Use Machine-level environment variables, never store passwords in scripts
6. **Schedule Wisely** - Run syncs during low-usage periods
7. **Review Settings** - Understand FreeFileSync sync mode (Mirror, Two-way, Update)
8. **Test Restores** - Periodically verify you can restore from synced data
## FreeFileSync Configuration
### Creating Batch Configuration
1. Launch FreeFileSync GUI
2. Configure left (source) and right (target) folders
3. Set comparison settings (File time and size, Content, File size)
4. Set filter rules (include/exclude patterns)
5. Choose sync variant:
- **Mirror**: Make right folder identical to left
- **Update**: Copy new/updated files to right
- **Two-way**: Propagate changes both ways
- **Custom**: Define custom rules
6. Click "Save as batch job"
7. Save as `sync.ffs_batch` in File-Sync directory
**Note:** All source and destination paths are configured directly in the FreeFileSync batch file. The script does not modify these paths - it only handles authentication to network shares before FreeFileSync executes.
## Security Considerations
- **Credentials** are stored Base64-encoded in Machine-level environment variables (not encryption, just encoding)
- Script requires **Administrator privileges** for network authentication
- **Network credentials** are passed to `net use` command
- Consider using **dedicated sync account** with minimal required permissions
- **Sync data** should be stored on secured network shares with appropriate ACLs
- **FreeFileSync** runs in silent mode without user interaction
## Performance Considerations
- **Sync time** depends on file count, size, and network speed
- **Network speed** is typically the bottleneck for UNC shares
- **FreeFileSync** is optimized for incremental syncs
- Use **filter rules** to exclude temporary/unnecessary files
- Consider **bandwidth throttling** in FreeFileSync settings for large syncs
- Run during **off-peak hours** to minimize network impact
## Version History
### 1.0.0 (2026-01-24)
- Initial production release
- Automated sync with scheduling
- FreeFileSync batch execution
- UNC share support with credential management
- Lock file and interval control
- Comprehensive error handling and logging
- Dynamic batch file path updates
- Prerequisite validation
## Support
For issues or questions:
1. Check the [Troubleshooting](#troubleshooting) section
2. Review script logs for error details
3. Verify all [Requirements](#requirements) are met
4. Check FreeFileSync documentation at https://freefilesync.org/manual.php
## License
See [LICENSE](../../LICENSE.md) in the root directory.
## Related Files
- `../SchedulerTemplate.psm1` - Shared scheduling and logging module
- `scriptsettings.json` - Configuration file
- `file-sync.bat` - Batch launcher
- `file-sync.ps1` - Main script
- `sync.ffs_batch` - FreeFileSync batch configuration
## Additional Resources
- **FreeFileSync Official Site:** https://freefilesync.org/
- **FreeFileSync Manual:** https://freefilesync.org/manual.php
- **FreeFileSync Forum:** https://freefilesync.org/forum/

View File

@ -0,0 +1,74 @@
@echo off
setlocal EnableDelayedExpansion
REM ============================================================================
REM File Sync Launcher
REM VERSION: 1.0.0
REM DATE: 2026-01-24
REM DESCRIPTION: Batch file launcher for file-sync.ps1 with admin check
REM ============================================================================
echo.
echo ============================================
echo File Sync Automated Launcher
echo ============================================
echo.
REM Check for Administrator privileges
net session >nul 2>&1
if %errorLevel% NEQ 0 (
echo [ERROR] This script must be run as Administrator!
echo.
echo Please right-click and select "Run as administrator"
echo.
pause
exit /b 1
)
echo [OK] Running with Administrator privileges
echo.
REM Get script directory
set "SCRIPT_DIR=%~dp0"
set "PS_SCRIPT=%SCRIPT_DIR%file-sync.ps1"
REM Check if PowerShell script exists
if not exist "%PS_SCRIPT%" (
echo [ERROR] PowerShell script not found: %PS_SCRIPT%
echo.
pause
exit /b 1
)
echo [OK] Found PowerShell script: %PS_SCRIPT%
echo.
echo ============================================
echo Starting sync process...
echo ============================================
echo.
REM Execute PowerShell script
REM Note: Logging is handled by UScheduler service
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%PS_SCRIPT%"
REM Capture exit code
set "EXIT_CODE=%ERRORLEVEL%"
echo.
echo ============================================
echo Sync process completed
echo Exit Code: %EXIT_CODE%
echo ============================================
echo.
if %EXIT_CODE% EQU 0 (
echo [SUCCESS] Sync completed successfully
) else (
echo [ERROR] Sync completed with errors
)
echo.
pause
endlocal
exit /b %EXIT_CODE%

View File

@ -0,0 +1,373 @@
[CmdletBinding()]
param (
[switch]$Automated,
[string]$CurrentDateTimeUtc
)
#Requires -RunAsAdministrator
<#
.SYNOPSIS
FreeFileSync Automated Backup Script
.DESCRIPTION
Production-ready file synchronization solution with scheduling and secure credential management.
.VERSION
1.0.0
.DATE
2026-01-24
.NOTES
- Requires FreeFileSync installed
- Requires SchedulerTemplate.psm1 module
- Requires sync.ffs_batch configuration file
#>
# Script Version
$ScriptVersion = "1.0.0"
$ScriptDate = "2026-01-24"
try {
Import-Module "$PSScriptRoot\..\SchedulerTemplate.psm1" -Force -ErrorAction Stop
}
catch {
Write-Error "Failed to load SchedulerTemplate.psm1: $_"
exit 1
}
# Load Settings ============================================================
$settingsFile = Join-Path $PSScriptRoot "scriptsettings.json"
if (-not (Test-Path $settingsFile)) {
Write-Error "Settings file not found: $settingsFile"
exit 1
}
try {
$settings = Get-Content $settingsFile -Raw | ConvertFrom-Json
Write-Verbose "Loaded settings from $settingsFile"
}
catch {
Write-Error "Failed to load settings from $settingsFile : $_"
exit 1
}
# Process Settings =========================================================
# Validate required settings
$requiredSettings = @('freeFileSyncExe', 'batchFile', 'nasRootShare')
foreach ($setting in $requiredSettings) {
if (-not $settings.$setting) {
Write-Error "Required setting '$setting' is missing or empty in $settingsFile"
exit 1
}
}
$FreeFileSyncExe = $settings.freeFileSyncExe
$FfsBatchFile = Join-Path $PSScriptRoot $settings.batchFile
$NasRootShare = $settings.nasRootShare
$CredentialEnvVar = $settings.credentialEnvVar
# Schedule Configuration
$Config = @{
RunMonth = $settings.schedule.runMonth
RunWeekday = $settings.schedule.runWeekday
RunTime = $settings.schedule.runTime
MinIntervalMinutes = $settings.schedule.minIntervalMinutes
}
# End Settings =============================================================
# Global variables
$script:SyncStats = @{
StartTime = Get-Date
EndTime = $null
Success = $false
ExitCode = $null
ErrorMessage = $null
}
# Global reference to the process so that the exit handler can see it
$global:FFS_Process = $null
# Helper Functions =========================================================
function Test-Prerequisites {
param([switch]$Automated)
Write-Log "Checking prerequisites..." -Level Info -Automated:$Automated
# Check if FreeFileSync executable exists
if (-not (Test-Path -LiteralPath $FreeFileSyncExe)) {
Write-Log "FreeFileSync not found: $FreeFileSyncExe" -Level Error -Automated:$Automated
Write-Log "Please install FreeFileSync or update the path in scriptsettings.json" -Level Error -Automated:$Automated
return $false
}
# Verify FreeFileSync version
try {
$ffsVersion = (Get-Item $FreeFileSyncExe).VersionInfo.FileVersion
Write-Log "FreeFileSync version: $ffsVersion" -Level Info -Automated:$Automated
}
catch {
Write-Log "Warning: Could not determine FreeFileSync version" -Level Warning -Automated:$Automated
}
# Check if batch file exists
if (-not (Test-Path -LiteralPath $FfsBatchFile)) {
Write-Log "Batch config not found: $FfsBatchFile" -Level Error -Automated:$Automated
Write-Log "Please create sync.ffs_batch configuration file" -Level Error -Automated:$Automated
return $false
}
Write-Log "All prerequisites passed" -Level Success -Automated:$Automated
return $true
}
function Connect-NasShare {
param(
[string]$SharePath,
[switch]$Automated
)
# Check if path is UNC
if (-not $SharePath.StartsWith("\\")) {
Write-Log "NAS path is local, no authentication needed" -Level Info -Automated:$Automated
return $true
}
Write-Log "Authenticating to NAS share: $SharePath" -Level Info -Automated:$Automated
# Validate credential environment variable name is configured
if (-not $CredentialEnvVar) {
Write-Log "credentialEnvVar is not configured in settings for UNC path authentication" -Level Error -Automated:$Automated
return $false
}
try {
# Retrieve credentials from environment variable
$creds = Get-CredentialFromEnvVar -EnvVarName $CredentialEnvVar -Automated:$Automated
if (-not $creds) {
return $false
}
# Check if already connected
$existingConnection = net use | Select-String $SharePath
if ($existingConnection) {
Write-Log "Already connected to $SharePath" -Level Info -Automated:$Automated
return $true
}
# Connect to share
$netUseResult = cmd /c "net use $SharePath $($creds.Password) /user:$($creds.Username) 2>&1"
if ($LASTEXITCODE -ne 0) {
Write-Log "Failed to connect to $SharePath : $netUseResult" -Level Error -Automated:$Automated
return $false
}
Write-Log "Successfully authenticated to $SharePath" -Level Success -Automated:$Automated
return $true
}
catch {
Write-Log "Error connecting to share: $_" -Level Error -Automated:$Automated
return $false
}
}
function Test-NasReachability {
param(
[string]$SharePath,
[switch]$Automated
)
if (-not (Test-Path $SharePath)) {
Write-Log "NAS share $SharePath is not reachable after authentication" -Level Warning -Automated:$Automated
return $false
}
Write-Log "NAS share is reachable: $SharePath" -Level Success -Automated:$Automated
return $true
}
function Start-FreeFileSyncProcess {
param([switch]$Automated)
Write-Log "Starting FreeFileSync batch synchronization..." -Level Info -Automated:$Automated
Write-Log " EXE: $FreeFileSyncExe" -Level Info -Automated:$Automated
Write-Log " BATCH: $FfsBatchFile" -Level Info -Automated:$Automated
# Ensure FreeFileSync is killed if PowerShell exits gracefully
Register-EngineEvent PowerShell.Exiting -Action {
if ($global:FFS_Process -and -not $global:FFS_Process.HasExited) {
try {
$global:FFS_Process.Kill()
}
catch {
}
}
} | Out-Null
try {
# Use ProcessStartInfo to ensure that no window is shown
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $FreeFileSyncExe
$psi.Arguments = "`"$FfsBatchFile`""
$psi.WorkingDirectory = [System.IO.Path]::GetDirectoryName($FreeFileSyncExe)
$psi.UseShellExecute = $false
$psi.CreateNoWindow = $true
$psi.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$proc = [System.Diagnostics.Process]::Start($psi)
$global:FFS_Process = $proc
# Capture FFS console output
$stdOut = $proc.StandardOutput.ReadToEnd()
$stdErr = $proc.StandardError.ReadToEnd()
$proc.WaitForExit()
$exitCode = $proc.ExitCode
if ($stdOut) {
Write-Log "FreeFileSync STDOUT:" -Level Info -Automated:$Automated
Write-Log $stdOut.TrimEnd() -Level Info -Automated:$Automated
}
if ($stdErr) {
Write-Log "FreeFileSync STDERR:" -Level Warning -Automated:$Automated
Write-Log $stdErr.TrimEnd() -Level Warning -Automated:$Automated
}
# Store exit code
$script:SyncStats.ExitCode = $exitCode
# Interpret exit code
switch ($exitCode) {
0 {
Write-Log "FreeFileSync completed successfully (exit code 0)" -Level Success -Automated:$Automated
$script:SyncStats.Success = $true
return $true
}
1 {
Write-Log "FreeFileSync completed with warnings (exit code 1)" -Level Warning -Automated:$Automated
$script:SyncStats.Success = $true
return $true
}
2 {
Write-Log "FreeFileSync completed with errors (exit code 2)" -Level Error -Automated:$Automated
$script:SyncStats.ErrorMessage = "FreeFileSync reported errors"
return $false
}
3 {
Write-Log "FreeFileSync was cancelled (exit code 3)" -Level Warning -Automated:$Automated
$script:SyncStats.ErrorMessage = "FreeFileSync was cancelled"
return $false
}
default {
Write-Log "FreeFileSync exited with unexpected code $exitCode" -Level Error -Automated:$Automated
$script:SyncStats.ErrorMessage = "Unexpected exit code: $exitCode"
return $false
}
}
}
catch {
Write-Log "Failed to execute FreeFileSync: $_" -Level Error -Automated:$Automated
$script:SyncStats.ErrorMessage = "Execution failed: $_"
return $false
}
finally {
if ($global:FFS_Process -and -not $global:FFS_Process.HasExited) {
Write-Log "PowerShell is stopping. Killing FreeFileSync process (PID $($global:FFS_Process.Id))..." -Level Warning -Automated:$Automated
try {
$global:FFS_Process.Kill()
}
catch {
Write-Log "Failed to kill FreeFileSync process: $_" -Level Error -Automated:$Automated
}
}
}
}
function Write-SyncSummary {
param([switch]$Automated)
$script:SyncStats.EndTime = Get-Date
$duration = $script:SyncStats.EndTime - $script:SyncStats.StartTime
Write-Log "" -Level Info -Automated:$Automated
Write-Log "========================================" -Level Info -Automated:$Automated
Write-Log "SYNC SUMMARY" -Level Info -Automated:$Automated
Write-Log "========================================" -Level Info -Automated:$Automated
Write-Log "Start Time : $($script:SyncStats.StartTime.ToString('yyyy-MM-dd HH:mm:ss'))" -Level Info -Automated:$Automated
Write-Log "End Time : $($script:SyncStats.EndTime.ToString('yyyy-MM-dd HH:mm:ss'))" -Level Info -Automated:$Automated
Write-Log "Duration : $($duration.Hours)h $($duration.Minutes)m $($duration.Seconds)s" -Level Info -Automated:$Automated
Write-Log "Status : $(if ($script:SyncStats.Success) { 'SUCCESS' } else { 'FAILED' })" -Level $(if ($script:SyncStats.Success) { 'Success' } else { 'Error' }) -Automated:$Automated
Write-Log "Exit Code : $($script:SyncStats.ExitCode)" -Level Info -Automated:$Automated
if ($script:SyncStats.ErrorMessage) {
Write-Log "Error : $($script:SyncStats.ErrorMessage)" -Level Error -Automated:$Automated
}
Write-Log "========================================" -Level Info -Automated:$Automated
}
# Main Business Logic ======================================================
function Start-BusinessLogic {
param([switch]$Automated)
Write-Log "========================================" -Level Info -Automated:$Automated
Write-Log "FreeFileSync Process Started" -Level Info -Automated:$Automated
Write-Log "Script Version: $ScriptVersion ($ScriptDate)" -Level Info -Automated:$Automated
Write-Log "========================================" -Level Info -Automated:$Automated
# Check prerequisites
if (-not (Test-Prerequisites -Automated:$Automated)) {
Write-Log "Prerequisites check failed. Aborting sync." -Level Error -Automated:$Automated
exit 1
}
# Connect to NAS share
if (-not (Connect-NasShare -SharePath $NasRootShare -Automated:$Automated)) {
Write-Log "Failed to connect to NAS share. Aborting sync." -Level Error -Automated:$Automated
exit 1
}
# Verify NAS reachability
if (-not (Test-NasReachability -SharePath $NasRootShare -Automated:$Automated)) {
Write-Log "NAS share is not reachable. Continuing anyway..." -Level Warning -Automated:$Automated
}
# Execute FreeFileSync
$syncResult = Start-FreeFileSyncProcess -Automated:$Automated
# Print summary
Write-SyncSummary -Automated:$Automated
# Exit with appropriate code
if (-not $syncResult) {
exit 1
}
}
# Entry Point ==============================================================
if ($Automated) {
if (Get-Command Invoke-ScheduledExecution -ErrorAction SilentlyContinue) {
Invoke-ScheduledExecution `
-Config $Config `
-Automated:$Automated `
-CurrentDateTimeUtc $CurrentDateTimeUtc `
-ScriptBlock { Start-BusinessLogic -Automated:$Automated }
}
else {
Write-Log "Invoke-ScheduledExecution not available. Execution aborted." -Level Error -Automated:$Automated
exit 1
}
}
else {
Write-Log "Manual execution started" -Level Info -Automated:$Automated
Start-BusinessLogic -Automated:$Automated
}

View File

@ -0,0 +1,31 @@
{
"$schema": "https://json-schema.org/draft-07/schema",
"title": "File Sync Script Settings",
"description": "Configuration file for file-sync.ps1 script using FreeFileSync",
"version": "1.0.0",
"lastModified": "2026-01-24",
"schedule": {
"runMonth": [],
"runWeekday": ["Monday"],
"runTime": ["00:00"],
"minIntervalMinutes": 10
},
"freeFileSyncExe": "C:\\Program Files\\FreeFileSync\\FreeFileSync.exe",
"batchFile": "sync.ffs_batch",
"nasRootShare": "\\\\nassrv0001.corp.maks-it.com\\data-1",
"credentialEnvVar": "nassrv0001",
"_comments": {
"version": "Configuration schema version",
"lastModified": "Last modification date (YYYY-MM-DD)",
"schedule": {
"runMonth": "Array of month names (e.g. 'January', 'June', 'December') to run sync. Empty array = every month.",
"runWeekday": "Array of weekday names (e.g. 'Monday', 'Friday') to run sync. Empty array = every day.",
"runTime": "Array of UTC times in HH:mm format when sync should run.",
"minIntervalMinutes": "Minimum minutes between sync runs to prevent duplicate executions."
},
"freeFileSyncExe": "Full path to FreeFileSync.exe executable. Typically 'C:\\Program Files\\FreeFileSync\\FreeFileSync.exe'",
"batchFile": "FreeFileSync batch configuration file name (must be in same directory as script). Configure sync paths directly in the .ffs_batch file using FreeFileSync GUI.",
"nasRootShare": "UNC path to NAS root share for authentication. This is only used for connecting to the share, not for modifying batch file paths.",
"credentialEnvVar": "Name of Machine-level environment variable containing Base64-encoded 'username:password' for NAS authentication"
}
}

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<FreeFileSync XmlType="BATCH" XmlFormat="23">
<Notes/>
<Compare>
<Variant>TimeAndSize</Variant>
<Symlinks>Exclude</Symlinks>
<IgnoreTimeShift/>
</Compare>
<Synchronize>
<Differences LeftOnly="right" LeftNewer="right" RightNewer="right" RightOnly="right"/>
<DeletionPolicy>RecycleBin</DeletionPolicy>
<VersioningFolder Style="Replace"/>
</Synchronize>
<Filter>
<Include>
<Item>*</Item>
</Include>
<Exclude>
<Item>\System Volume Information\</Item>
<Item>\$Recycle.Bin\</Item>
<Item>\RECYCLE?\</Item>
<Item>\Recovery\</Item>
<Item>*\thumbs.db</Item>
</Exclude>
<SizeMin Unit="None">0</SizeMin>
<SizeMax Unit="None">0</SizeMax>
<TimeSpan Type="None">0</TimeSpan>
</Filter>
<FolderPairs>
<Pair>
<Left>E:\Users\maksym\source</Left>
<Right>\\nassrv0001.corp.maks-it.com\data-1\Users\maksym\source</Right>
</Pair>
<Pair>
<Left/>
<Right/>
</Pair>
</FolderPairs>
<Errors Ignore="true" Retry="0" Delay="5"/>
<PostSyncCommand Condition="Completion"/>
<LogFolder/>
<EmailNotification Condition="Always"/>
<GridViewType>Action</GridViewType>
<Batch>
<ProgressDialog Minimized="true" AutoClose="true"/>
<ErrorDialog>Show</ErrorDialog>
<PostSyncAction>None</PostSyncAction>
</Batch>
</FreeFileSync>