Created
October 10, 2025 19:10
-
-
Save birdstream/d29b4b36537f928682c5586b62bfde42 to your computer and use it in GitHub Desktop.
Egde backup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
Backup or restore Microsoft Edge profiles locally (no account sync). | |
.DESCRIPTION | |
- BACKUP: Save Bookmarks only or full profile(s) to a chosen folder as ZIP files. | |
- RESTORE: Restore Bookmarks or full profile(s) from a file/folder/ZIP. | |
Works for the current Windows user only. | |
.PARAMETER Mode | |
backup | restore (default: backup) | |
.PARAMETER Dest | |
Backup destination folder (default: Desktop\EdgeBackup) | |
.PARAMETER Profile | |
Profile name, e.g. "Default", "Profile 1" (default: Default) | |
.PARAMETER AllProfiles | |
Include all profiles under Edge's User Data path. | |
.PARAMETER OnlyBookmarks | |
Operate on Bookmarks file only (Bookmars JSON). | |
.PARAMETER Source | |
For restore: path to a Bookmarks file, a ZIP, or an extracted profile folder. | |
.EXAMPLE | |
.\edge_backup.ps1 -Mode backup -AllProfiles -OnlyBookmarks | |
Backs up Bookmarks JSON for all profiles to Desktop\EdgeBackup | |
.EXAMPLE | |
.\edge_backup.ps1 -Mode backup -Profile "Default" -Dest D:\Backups | |
Full-profile ZIP backup of "Default" to D:\Backups | |
.EXAMPLE | |
.\edge_backup.ps1 -Mode restore -OnlyBookmarks -Profile "Default" -Source .\Edge-Bookmarks-Default.json | |
Restores only Bookmarks to the Default profile | |
.EXAMPLE | |
.\edge_backup.ps1 -Mode restore -Source .\Edge-Profile-Default.zip | |
Restores full "Default" profile from ZIP | |
#> | |
[CmdletBinding()] | |
param( | |
[ValidateSet('backup','restore')][string]$Mode = 'backup', | |
[string]$Dest = "$(Join-Path $env:USERPROFILE 'Desktop\EdgeBackup')", | |
[string]$Profile = 'Default', | |
[switch]$AllProfiles, | |
[switch]$OnlyBookmarks, | |
[string]$Source | |
) | |
$ErrorActionPreference = 'Stop' | |
function Ensure-EdgeClosed { | |
$p = Get-Process -Name "msedge" -ErrorAction SilentlyContinue | |
if ($p) { | |
Write-Host "Microsoft Edge is running. Attempting to close..." -ForegroundColor Yellow | |
$p | ForEach-Object { $_.CloseMainWindow() | Out-Null } | |
Start-Sleep -Seconds 2 | |
$p = Get-Process -Name "msedge" -ErrorAction SilentlyContinue | |
if ($p) { | |
Write-Host "Forcing Edge to close..." -ForegroundColor Yellow | |
$p | Stop-Process -Force | |
} | |
} | |
} | |
function Get-EdgeBase { | |
$base = Join-Path $env:LOCALAPPDATA 'Microsoft\Edge\User Data' | |
if (-not (Test-Path $base)) { throw "Edge User Data path not found: $base" } | |
return $base | |
} | |
function Get-Profiles([string]$base) { | |
$dirs = Get-ChildItem -LiteralPath $base -Directory -ErrorAction SilentlyContinue | | |
Where-Object { $_.Name -match '^(Default|Profile \d+)$' } | |
return $dirs | |
} | |
function Backup-Bookmarks([System.IO.DirectoryInfo[]]$profiles, [string]$dest) { | |
New-Item -ItemType Directory -Force -Path $dest | Out-Null | |
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss' | |
foreach ($prof in $profiles) { | |
$src = Join-Path $prof.FullName 'Bookmarks' | |
if (Test-Path $src) { | |
$out = Join-Path $dest ("Edge-Bookmarks-{0}-{1}.json" -f $prof.Name, $stamp) | |
Copy-Item -LiteralPath $src -Destination $out -Force | |
Write-Host "Saved: $out" | |
} else { | |
Write-Warning "No Bookmarks file in $($prof.Name)" | |
} | |
} | |
} | |
function Backup-Full([System.IO.DirectoryInfo[]]$profiles, [string]$dest) { | |
New-Item -ItemType Directory -Force -Path $dest | Out-Null | |
foreach ($prof in $profiles) { | |
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss' | |
$zip = Join-Path $dest ("Edge-Profile-{0}-{1}.zip" -f $prof.Name, $stamp) | |
Write-Host "Creating archive: $zip" | |
# Collect files excluding heavy cache dirs | |
$files = Get-ChildItem -LiteralPath $prof.FullName -Recurse -File | | |
Where-Object { $_.FullName -notmatch '\\(Cache|Code Cache|GPUCache|DawnCache)\\' } | |
if ($files.Count -eq 0) { | |
Write-Warning "No files to archive in $($prof.FullName)" | |
continue | |
} | |
if (Test-Path $zip) { Remove-Item $zip -Force } | |
Compress-Archive -Path $files.FullName -DestinationPath $zip -CompressionLevel Optimal | |
Write-Host "Saved: $zip" | |
} | |
} | |
function Restore-Bookmarks([string]$source, [string]$targetProfilePath) { | |
$dst = Join-Path $targetProfilePath 'Bookmarks' | |
if (-not (Test-Path $source)) { throw "Bookmarks source not found: $source" } | |
if (-not (Test-Path $targetProfilePath)) { New-Item -ItemType Directory -Force -Path $targetProfilePath | Out-Null } | |
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss' | |
if (Test-Path $dst) { | |
Copy-Item -LiteralPath $dst -Destination ($dst + ".bak-$stamp") -Force | |
} | |
Copy-Item -LiteralPath $source -Destination $dst -Force | |
Write-Host "Restored Bookmarks to: $dst" | |
} | |
function Restore-Full([string]$source, [string]$base) { | |
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss' | |
$temp = Join-Path ([System.IO.Path]::GetTempPath()) ("EdgeRestore-$stamp") | |
New-Item -ItemType Directory -Force -Path $temp | Out-Null | |
if ((Test-Path $source) -and (Get-Item $source).PSIsContainer) { | |
Write-Host "Using extracted folder as source: $source" | |
$root = $source | |
} elseif ($source -and (Test-Path $source) -and ($source -like '*.zip')) { | |
Write-Host "Expanding ZIP: $source" | |
Expand-Archive -LiteralPath $source -DestinationPath $temp -Force | |
$root = $temp | |
} else { | |
throw "Provide -Source as a ZIP file or extracted profile folder containing 'Default' / 'Profile X'." | |
} | |
$profileDirs = Get-ChildItem -LiteralPath $root -Directory -Recurse | | |
Where-Object { $_.Name -match '^(Default|Profile \d+)$' } | |
if (-not $profileDirs) { throw "No profile folders found in restore source." } | |
foreach ($p in $profileDirs) { | |
$dest = Join-Path $base $p.Name | |
if (Test-Path $dest) { | |
$bak = "$dest.bak-$stamp" | |
Write-Host "Backing up existing: $dest -> $bak" | |
Rename-Item -LiteralPath $dest -NewName (Split-Path -Leaf $bak) | |
} | |
Write-Host "Restoring profile: $($p.Name)" | |
Copy-Item -LiteralPath $p.FullName -Destination $dest -Recurse -Force | |
} | |
Write-Host "Restore complete." | |
} | |
try { | |
Ensure-EdgeClosed | |
$base = Get-EdgeBase | |
$profiles = @() | |
if ($AllProfiles) { | |
$profiles = Get-Profiles -base $base | |
if (-not $profiles) { throw "No profiles found under $base" } | |
} else { | |
$path = Join-Path $base $Profile | |
if (-not (Test-Path $path)) { throw "Profile not found: $path" } | |
$profiles = ,(Get-Item $path) | |
} | |
if ($Mode -eq 'backup') { | |
if ($OnlyBookmarks) { | |
Backup-Bookmarks -profiles $profiles -dest $Dest | |
} else { | |
Backup-Full -profiles $profiles -dest $Dest | |
} | |
} else { | |
if ($OnlyBookmarks) { | |
if (-not $Source) { throw "Provide -Source path to a Bookmarks JSON to restore." } | |
Restore-Bookmarks -source $Source -targetProfilePath $profiles[0].FullName | |
} else { | |
if (-not $Source) { throw "Provide -Source path to a ZIP or extracted folder to restore." } | |
Restore-Full -source $Source -base $base | |
} | |
} | |
} catch { | |
Write-Error $_.Exception.Message | |
exit 1 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment