A PowerShell + Python tool to back up, restore, verify, compare, schedule, and export browser profiles across Chromium and Gecko browsers on Windows 10/11.
_ _ ____ _
| | | | ___ _ __ ___ | __ ) __ _ _ __ __ _ _ __ ___ (_)_ __
| | | |/ _ \| '_ \ / _ \| _ \ / _` | '__/ _` | '_ ` _ \| | '_ \
| |_| | (_) | | | | (_) | |_) | (_| | | | (_| | | | | | | | | | |
\___/ \___/|_| |_|\___/|____/ \__,_|_| \__,_|_| |_| |_|_|_| |_|
Browser backup · restore · verify · schedule
- Auto-detection of every Chromium and Gecko browser installed locally — Chrome, Edge, Firefox, Brave, Vivaldi, Opera, Arc, Floorp, Zen, Thorium, Ladybird and 20 + more
- Multi-profile — back up individual profiles or every profile at once
- Multi-browser select — tick several browsers in the GUI and back them all up in one click
- Two GUI front-ends — native WPF dark-theme (PowerShell) and PySide6 (Python); both produce identical backups
- Full PowerShell + Python CLI — same flags on both runtimes:
--list,--backup,--restore,--verify,--all-profiles,--exclude-cache, etc. - Integrity verification — SHA-256 checksums of every critical file stored in
manifest.json - Backup comparison — diff two backups; see exactly which files were added, removed or modified
- Profile export / import — zip an entire profile for transport, restore the zip on another machine
- Scheduled backups — interval-based automatic backups driven by QTimer (Python GUI)
- Rollback protection — automatic snap-shot before restore; one-click rollback on failure
- Smart exclusions — skips cache, thumbnails, service workers, shader caches, local storage, IndexedDB by default
- Structured logging with rotation (default 30 files)
- Cancelable — long-running operations can be cancelled from the GUI
- Cross-runtime — Windows PowerShell 5.1, PowerShell 7+ (
pwsh), Python 3.11+
- Quick Start
- Detailed Usage
- How Backups Work
- How Restore Works
- How Verification Works
- How Comparison Works
- How Schedule Works
- How Export / Import Works
- Project Structure
- Configuration
- CLI Reference
- Testing
- Troubleshooting
- Requirements
- License
:: 1. Install Python deps (only needed for the Python GUI / CLI)
setup.bat
:: 2a. Launch the WPF GUI (no Python needed)
UniversalBrowserBackup.bat
:: 2b. Or launch the Python GUI (richer features)
python main.py
:: 2c. Or use the CLI directly
python main.py --listThat's it — no installer, no admin rights, no service registration.
Double-click UniversalBrowserBackup.bat, or from PowerShell:
.\UniversalBrowserBackup.ps1The WPF window appears:
| Region | Purpose |
|---|---|
| Left panel | Detected browsers with profile count + size. Select one or more. |
| Right panel | Activity log + destination folder picker + Start/Cancel button. |
| Top radio | Switch between Backup and Restore modes. |
When you click Start Backup the long-running copy is dispatched to a separate runspace so the UI never freezes; click Cancel to abort.
python main.pyThe Python GUI has seven tabs:
| # | Tab | What it does |
|---|---|---|
| 1 | Backup | Pick 1+ browsers → pick profiles → choose destination → start. Shows progress bar and live status. |
| 2 | Restore | Pick the target browser + profile → pick a backup folder → start. Rolls back automatically on failure. |
| 3 | Verify | Pick any backup folder → SHA-256 re-hash is run and the result is printed in the log. |
| 4 | Backups | List every backup produced. Compare Two opens a file-level added/removed/modified diff between any two folders. |
| 5 | Schedule | Set an interval (in minutes) and a destination; backups of every detected browser run on schedule. |
| 6 | Export / Import | Zip a profile and save anywhere; paste a .zip later to re-hydrate it under %LOCALAPPDATA%\Imported_Browser_Backups. |
| 7 | Logs | Live tail of backup_YYYYMMDD_HHMMSS.log with a button to open the log folder. |
Refresh is right next to the browser list — click it whenever you install or remove a browser.
List everything that's detected:
.\UniversalBrowserBackup.ps1 -ListBack up one profile:
.\UniversalBrowserBackup.ps1 -Backup -Browser "Chrome" -Destination "D:\Backups"Back up every profile of a browser:
.\UniversalBrowserBackup.ps1 -Backup -Browser "Chrome" -Destination "D:\Backups" -AllProfiles -ExcludeCacheRestore:
.\UniversalBrowserBackup.ps1 -Restore -Browser "Chrome" -Source "D:\Backups\Chrome_Default_20260702_141522"Preview without changes (PowerShell -WhatIf propagates to the modules):
.\UniversalBrowserBackup.ps1 -Backup -Browser "Chrome" -Destination "D:\Backups" -WhatIfForce-snap the browser if it's running:
.\UniversalBrowserBackup.ps1 -Backup -Browser "Chrome" -Destination "D:\Backups" -ForceThe CLI uses sensible exit codes (0 = success, 3 = not found, 5 = operation failed, etc.) so you can chain it in scripts or scheduled tasks.
python main.py --version
python main.py --logs
python main.py --list
python main.py --backup --browser Chrome --destination "D:\Backups" --all-profiles --exclude-cache
python main.py --restore --browser Chrome --source "D:\Backups\Chrome_Default_20260702_141522"
python main.py --verify --source "D:\Backups\Chrome_Default_20260702_141522"
python main.py --no-gui --backup --browser Edge --destination "D:\Backups" --forceRun python main.py --help for the full flag list.
- The tool scans your browser fingerprints from
Config\browsers.jsonand theprocessNamesmap. - For each selected (browser, profile):
- If the browser process is running and you didn't pass
-Forcethe backup is refused (can't robocopy a moving target). - If
-Forceis on, the process is killed viataskkill /F /IM <exe>. - A timestamped folder
<Browser>_<Profile>_<YYYYMMDD_HHMMSS>is created in the destination. robocopy /MIR /NP /BYTES /NDL /NFL /NC /NS /MT:4mirrors the profile into that folder.- Anything in
excludeFromBackup(cache, thumbnails, etc.) is skipped via/XD. manifest.jsonis written with stats, browser info, robocopy exit code and SHA-256 checksums of the critical files (Bookmarks, History, Login Data, Cookies, …).
- If the browser process is running and you didn't pass
- Success and a one-line summary are returned (or printed).
A backup is therefore three things:
<destination>/
└── Chrome_Default_20260702_141522/
├── Bookmarks
├── Bookmarks.bak
├── History
...
└── manifest.json <- integrity evidence
- You point the tool at a backup folder.
- The tool validates
manifest.jsonis present. - A
rollback_<timestamp>snapshot of the current profile is created next to it (using robocopy with retries). - The contents of the backup folder are copied over the live profile.
- If anything fails, the snapshot is restored; otherwise the snapshot is deleted.
The -LaunchAfter flag (PowerShell) relaunches the browser once the restore is complete.
BackupEngine.verify_backup(path) (Python) / Test-BackupIntegrity (PowerShell):
- Reads
manifest.json. - Recomputes SHA-256 on every critical file listed in
checksums. - Compares the recomputed hashes to the stored ones.
- Returns
success=Trueonly when every hash matches.
A verification failure tells you the backup has been tampered with or corrupted at the block level.
BackupEngine.compare_backups(old, new) walks both folders and:
| Bucket | Meaning |
|---|---|
files_only_in_old |
Removed since the old backup |
files_only_in_new |
Added since the old backup |
files_modified |
Same relative path, different size or different SHA-256 |
files_identical |
Same size + same SHA-256 |
This is useful for:
- Spotting telemetry that has changed between snapshots.
- Verifying that a given restore didn't quietly fall back to a different version.
- Triaging "the bookmark toolbar isn't showing my imported bookmarks" type issues.
The GUI's Backups → Compare Two tab wraps this in a pretty side-by-side display.
The Python GUI exposes a Schedule tab:
- Set the destination folder.
- Set the interval in minutes (1 – 1440).
- Click Apply Schedule.
Behind the scenes a QTimer fires once per interval and runs BackupEngine.run_backup on every detected browser + profile, using your existing Config\ defaults. Status is shown in the status bar; logs go to the same Logs tab.
Click Stop Schedule to disarm it. The schedule is in-process only (closing the GUI stops it).
Export zips the entire profile (minus cache folders) into a single .zip for transport:
BackupEngine.export_profile_zip(browser, profile, "C:\\my_backup.zip")Import extracts a previously exported .zip into a managed folder under %LOCALAPPDATA%\Imported_Browser_Backups\:
BackupEngine.import_profile_zip("C:\\my_backup.zip")The GUI's Export / Import tab wires both of these to file-pickers and shows the destination on success.
UniversalBrowserBackup/
├── UniversalBrowserBackup.ps1 # PowerShell CLI entry point
├── UniversalBrowserBackup.bat # Windows launcher for the WPF GUI
├── main.py # Python GUI + CLI entry point
├── requirements.txt # PySide6, pywin32
├── setup.bat # Windows Python install helper
├── setup.sh # POSIX Python install helper
│
├── Config/
│ └── browsers.json # Browser paths, excludes, critical files, process names
│
├── Modules/ # PowerShell modules (.psm1)
│ ├── Config.psm1 # Config loader (AppData + script-dir fallback)
│ ├── BrowserDetection.psm1 # Chromium + Gecko detection w/ dedup
│ ├── Logging.psm1 # Rotating timestamped logger
│ ├── BackupEngine.psm1 # Robocopy + manifest + SHA256
│ └── RestoreEngine.psm1 # Validate + rollback + restore
│
├── GUI/ # PowerShell WPF GUI
│ ├── MainWindow.xaml # XAML dark-theme layout
│ └── App.ps1 # Runspace-based controller
│
├── core/ # Python implementation (parity with Modules/)
│ ├── config_manager.py
│ ├── detection.py
│ ├── backup.py # + verify / compare / zip export+import
│ ├── restore.py
│ └── logger.py
│
├── Tests/
│ └── BackupEngine.Tests.ps1 # Pester — 18 tests
│
├── py_tests/
│ └── test_core.py # pytest — 12 tests
│
├── CHANGELOG.md
├── LICENSE
└── README.md # ← this file
Config is loaded in order:
%APPDATA%\UniversalBrowserBackup\browsers.json(per-user override)<script>\Config\browsers.json(shipped defaults)- Built-in fallback constants
Override any field by copying Config\browsers.json to %APPDATA%\UniversalBrowserBackup\ and editing the copy. Useful keys:
| Key | Purpose |
|---|---|
defaults.backupDestination |
Where backups go by default. Supports %USERPROFILE%, %LOCALAPPDATA%. |
defaults.excludeFromBackup |
Sub-folders that robocopy /XD will skip. |
defaults.robocopyRetries |
Number of retries for locked files. |
defaults.robocopyWait |
Seconds between retries. |
defaults.maxLogFiles |
How many log files to retain. |
defaults.checksumCriticalFiles |
Files rehashed for verification. |
chromiumPaths.local |
Local-AppData folders to scan (legacy format). |
chromiumPaths.programFiles |
Program-Files folders used to find executables (legacy format). |
geckoPaths.appData |
Firefox AppData root (legacy format). |
processNames |
DisplayName → process.exe mapping for robust browser detection. |
browsers[] |
New format — 46 browser definitions with detectStrategy, profilePath, exePath, engineFamily. |
Every backup creates manifest.json with:
{
"version": "2.1.1",
"created": "2026-07-03T12:00:00Z",
"browser": "Chrome",
"profile": "Default",
"vTag": "Chrome-Default",
"selectionHash": "a1b2c3d4e5f6g7h8",
"preflight": {
"browserRunning": false,
"diskFreeGB": 45.2,
"processName": "chrome.exe"
},
"checksums": { ... }
}- vTag — short human-readable identifier (
browser-profile) - selectionHash — SHA-256 truncated to 16 chars; changes if browser/profile/destination selection changes
- preflight — snapshot of pre-backup conditions for diagnostics
-List List detected browsers and profiles, then exit.
-Backup Switch to backup mode (must provide Destination).
-Restore Switch to restore mode (must provide Source).
-Browser "<name>" Browser name (substring matches — "Chrome" matches "Google Chrome (Chromium)").
-Profile "<name>" Profile name (default "Default"). Ignored when -AllProfiles is set.
-AllProfiles Back up / restore every profile the browser exposes.
-Destination "<path>" Required for -Backup. Folder will be created if missing.
-Source "<path>" Required for -Restore. Must contain manifest.json.
-ExcludeCache Adds the configured exclude list to the robocopy call.
-Force Kills the browser process before touching the profile.
-LaunchAfter (Restore only) Opens the browser after restore.
-WhatIf PowerShell preview mode — no writes.
-ConfigPath "<path>" Use an explicit config file instead of the default discovery.
--version Print version and exit.
--logs Print log file path and exit.
--list List detected browsers and exit.
--backup Run a backup from CLI.
--restore Run a restore from CLI.
--verify Verify a backup folder from CLI.
--browser "<name>" Filter for the browser you want.
--profile "<name>" Profile name (default "Default").
--destination "<path>" Required with --backup.
--source "<path>" Required with --restore / --verify.
--all-profiles Backup every profile.
--exclude-cache Skip cache, thumbnails, etc.
--force Kill the browser process first.
--no-gui (Implicit whenever --list / --backup / --restore / --verify is used.)
Run any tool with --help for the live description.
# Pester (PowerShell)
Invoke-Pester Tests\BackupEngine.Tests.ps1# pytest (Python)
python -m pytest py_tests/ -vCurrent counts: 18 + 12 = 30 tests, all passing.
Tests cover: config loading, browser detection, profile discovery, dedup, process-name mapping, rotated logging, manifest integrity, and every Python backup-tool variant (verify / compare / zip / list).
You're on Windows PowerShell 5.1 and the XAML has been modified to contain non-ASCII characters. The shipped MainWindow.xaml uses full ARGB hex colors (#FF1E1E2E etc.) and no emoji — if you've edited it, only use ASCII glyphs.
Make sure your editor saved the file with Windows line endings (CRLF). Run .\UniversalBrowserBackup.bat from a regular cmd.exe, not from PowerShell with strict-mode Set-StrictMode -Version Latest, because the bat relies on !errorlevel! delayed expansion.
Open Task Manager → Details, sort by Image name, look for chrome.exe / msedge.exe / brave.exe etc., and end any zombie processes. The --force flag automates this.
The destination must be writable for the current user. On managed Windows machines C:\Program Files\… is often blocked; choose D:\Backups or \\nas01\backups\me instead.
This is expected when ExcludeCache is used. The default exclude list drops ~30 % of a typical profile's volume (cache, thumbnails, IndexedDB, etc.). Toggle the option off if you want a literal mirror.
maxLogFiles defaults to 30 in Config\browsers.json. Bump it down, or clear %APPDATA%\UniversalBrowserBackup\logs\ manually.
| OS | Windows 10 / 11 |
| PowerShell | Windows PowerShell 5.1 or PowerShell 7+ (pwsh) |
| Python | 3.11+ (only for the Python GUI / CLI) |
| Python deps | PySide6, pywin32 (installed by setup.bat) |
| Privileges | Standard user; no admin required |
| Internet | Not required. Tool talks to no remote endpoint. |
MIT — see LICENSE.