├── LICENSE ├── README.md ├── EDGEProfiles.psm1 ├── EDGEProfiles.psd1 └── Public ├── Restore-EdgeProfiles.ps1 └── Backup-EdgeProfiles.ps1 /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 MSEndpointMgr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EdgeProfiles 2 | PowerShell module to handle backup and restore of Edge browser profiles for the current user. 3 | 4 | ## Installation 5 | Install-Module EdgeProfiles 6 | 7 | ## Works/tested on 8 | - Windows 10 20H2 and newer 9 | - Windows 11 Preview and newer 10 | - All Edge Chromium versions should theoretically be supported. 11 | 12 | # Help 13 | 14 | **.Synopsis** 15 | 16 | Allows for easy backup and restore of Microsoft Edge (Anaheim) Profiles. 17 | EDGE MUST BE CLOSED DURING! 18 | 19 | **.Description** 20 | 21 | Will backup all Edge "User Data" for the current user. This data contains all the "Profiles" within the browser, and the corresponding registry keys will also be saved alongside the backup. 22 | Backups are zipped to allow for easy storage on locations like OneDrive. 23 | Before archiving the backup, all profiles have their Cache emptied. 24 | 25 | Restore will replace the current users Edge data. The command requires that the user choose how to handle existing data. 26 | 27 | NB: Authentication tokens can't be exported, so users will have to sign-in again to services using modern authentication. 28 | 29 | **.Example** 30 | 31 | Backup the current users Edge Profiles to the \_EdgeProfilesBackup folder in the users own OneDrive. 32 | 33 | *Backup-EdgeProfiles* 34 | 35 | **.Example** 36 | 37 | Backup the current users Edge Profiles to the users own TEMP folder. 38 | 39 | *Backup-EdgeProfiles -Destination $env:TEMP* 40 | 41 | **.Example** 42 | 43 | Restore a previous backup and remove existing user data. 44 | 45 | *Restore-EdgeProfiles -ZIPSource Edge-UserData30July2021-MichaelMardahl.zip -REGSource Edge-ProfilesRegistry30July2021-MichaelMardahl.reg -ExistingDataAction Remove* 46 | -------------------------------------------------------------------------------- /EDGEProfiles.psm1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Allows for easy backup and restore of Microsoft Edge (Anaheim) Profiles. 4 | Edge MUST BE CLOSED DURING! 5 | 6 | .Description 7 | Will backup all Edge "User Data" for the current user. This data contains all the "Profiles" within the browser, and the corresponding registry keys will also be saved alongside the backup. 8 | Backups are zipped to allow for easy storage on locations like OneDrive. 9 | 10 | 11 | Restore will replace the current users Edge data. The command requires that the user chooses how to handle existing data. 12 | 13 | .Example 14 | # Backup the current users Edge Profiles to the _EdgeProfilesBackup folder in the users own OneDrive. 15 | Backup-EdgeProfiles 16 | 17 | .Example 18 | # Backup the current users Edge Profiles to the users own TEMP folder. 19 | Backup-EdgeProfiles -Destination $env:TEMP 20 | 21 | .Example 22 | # Restore a previous backup and remove existing user data. 23 | Restore-EdgeProfiles -ZIPSource Edge-UserData30July2021-MichaelMardahl.zip -REGSource Edge-ProfilesRegistry30July2021-MichaelMardahl.reg -ExistingDataAction Remove 24 | 25 | .NOTES 26 | Author: Michael Mardahl 27 | Contact: @michael_mardahl 28 | Created: 2021-30-07 29 | Updated: 2021-31-07 30 | Version history: 31 | 1.0.0 - (2021-30-07) Script created 32 | 1.0.1 - (2021-31-07) Minor output fixes 33 | 1.0.2 - (2021-01-08) Changed from exit codes to breaks 34 | 1.0.3 - (2021-01-08) Changed from exit codes to breaks 35 | 1.0.4 - (2021-01-08) Default destination validation bug fix (Thanks @byteben) 36 | 1.0.5 - (2022-17-11) Move functions to separate file 37 | Rename module and functions from "Edge" to "Edge" 38 | Change cache clean to function so multiple folders can be emptied before backup 39 | Added support to close edge forcefully 40 | Added support to backup multiple channels 41 | #> 42 | [CmdletBinding()] 43 | Param() 44 | Process { 45 | # Locate all the public and private function specific files 46 | $PublicFunctions = Get-ChildItem -Path (Join-Path -Path $PSScriptRoot -ChildPath "Public") -Filter "*.ps1" -ErrorAction SilentlyContinue 47 | $PrivateFunctions = Get-ChildItem -Path (Join-Path -Path $PSScriptRoot -ChildPath "Private") -Filter "*.ps1" -ErrorAction SilentlyContinue 48 | 49 | # Dot source the function files 50 | foreach ($FunctionFile in @($PublicFunctions + $PrivateFunctions)) { 51 | try { 52 | . $FunctionFile.FullName -ErrorAction Stop 53 | } 54 | catch [System.Exception] { 55 | Write-Error -Message "Failed to import function '$($FunctionFile.FullName)' with error: $($_.Exception.Message)" 56 | } 57 | } 58 | 59 | Export-ModuleMember -Function $PublicFunctions.BaseName -Alias * 60 | } -------------------------------------------------------------------------------- /EDGEProfiles.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'EdgeProfiles' 3 | # 4 | # Generated by: Michael Mardahl @michael_mardahl 5 | # 6 | # Generated on: 2021-07-31 7 | # 8 | 9 | @{ 10 | # Script module or binary module file associated with this manifest. 11 | RootModule = 'EdgeProfiles.psm1' 12 | 13 | # Version number of this module. 14 | ModuleVersion = '1.0.6' 15 | 16 | # Supported PSEditions 17 | CompatiblePSEditions = @('Desktop', 'Core') 18 | 19 | # ID used to uniquely identify this module 20 | GUID = 'c6acd4a6-d9af-42e7-85da-816cf81f3a5f' 21 | 22 | # Author of this module 23 | Author = 'Michael Mardahl @michael_mardahl' 24 | 25 | # Company or vendor of this module 26 | CompanyName = 'MSEndpointMgr.com' 27 | 28 | # Copyright statement for this module 29 | Copyright = '(c) 2023 MSEndpointMgr.com. All rights reserved.' 30 | 31 | # Description of the functionality provided by this module 32 | Description = 'Simplifies backup and restore of Edge Browser Profiles' 33 | 34 | # Minimum version of the Windows PowerShell engine required by this module 35 | PowerShellVersion = '5.1' 36 | 37 | # Name of the Windows PowerShell host required by this module 38 | # PowerShellHostName = '' 39 | 40 | # Minimum version of the Windows PowerShell host required by this module 41 | # PowerShellHostVersion = '' 42 | 43 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 44 | # DotNetFrameworkVersion = '' 45 | 46 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 47 | # CLRVersion = '' 48 | 49 | # Processor architecture (None, X86, Amd64) required by this module 50 | # ProcessorArchitecture = '' 51 | 52 | # Modules that must be imported into the global environment prior to importing this module 53 | 54 | # Assemblies that must be loaded prior to importing this module 55 | # RequiredAssemblies = @() 56 | 57 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 58 | # ScriptsToProcess = @() 59 | 60 | # Type files (.ps1xml) to be loaded when importing this module 61 | # TypesToProcess = @() 62 | 63 | # Format files (.ps1xml) to be loaded when importing this module 64 | # FormatsToProcess = @() 65 | 66 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 67 | # NestedModules = @() 68 | 69 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 70 | FunctionsToExport = @('Backup-EdgeProfiles', 71 | 'Restore-EdgeProfiles' 72 | ) 73 | 74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 75 | CmdletsToExport = @() 76 | 77 | # Variables to export from this module 78 | VariablesToExport = '*' 79 | 80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 81 | AliasesToExport = @() 82 | 83 | # DSC resources to export from this module 84 | # DscResourcesToExport = @() 85 | 86 | # List of all modules packaged with this module 87 | # ModuleList = @() 88 | 89 | # List of all files packaged with this module 90 | # FileList = @() 91 | 92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 93 | PrivateData = @{ 94 | PSData = @{ 95 | # Tags applied to this module. These help with module discovery in online galleries. 96 | Tags = @('EdgeProfiles','EdgeBackup','EdgeExport','Edge') 97 | 98 | # A URL to the license for this module. 99 | LicenseUri = 'https://raw.githubusercontent.com/MSEndpointMgr/EDGEProfiles/main/LICENSE' 100 | 101 | # A URL to the main website for this project. 102 | ProjectUri = 'https://github.com/MSEndpointMgr/EdgeProfiles' 103 | 104 | # A URL to an icon representing this module. 105 | # IconUri = '' 106 | 107 | # ReleaseNotes of this module 108 | # ReleaseNotes = '' 109 | 110 | } # End of PSData hashtable 111 | 112 | } # End of PrivateData hashtable 113 | 114 | # HelpInfo URI of this module 115 | # HelpInfoURI = '' 116 | 117 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 118 | # DefaultCommandPrefix = '' 119 | 120 | } 121 | -------------------------------------------------------------------------------- /Public/Restore-EdgeProfiles.ps1: -------------------------------------------------------------------------------- 1 | function Restore-EdgeProfiles { 2 | <# 3 | .Synopsis 4 | Restore Microsoft Edge (Anaheim) Profiles to the current users Edge Browser. 5 | 6 | .Description 7 | Will restore all Edge "User Data" for the current user from an archive created by the Backup-EdgeProfiles function. 8 | 9 | .Parameter Verbose 10 | Enables extended output 11 | 12 | .Parameter ZIPSource 13 | (Mandatory - file path) 14 | Location of the User Data backup archive file. 15 | 16 | .Parameter REGSource 17 | (Mandatory - file path) 18 | Location of the profile data registry file. 19 | 20 | .Parameter ExistingDataAction 21 | (Mandatory - Rename/Remove) 22 | Choose wheather to have the existing User Data removed completely or just renamed. Renaming will add a datestamp to the existing USer Data folder. 23 | 24 | .Parameter CloseEdge 25 | (optional - $true/$false) 26 | Close Edge process if running. 27 | 28 | .Parameter Channel 29 | (optional - 'Stable', 'Beta', 'Dev', 'Canary') 30 | Allow to choose which version of Edge to restore. Be aware that restoring a backup from one version into another is not supported due to the registry keys being on a different path. 31 | 32 | .Example 33 | # Restore a previous backup and remove existing user data. 34 | Restore-EdgeProfiles -ZIPSource Edge-UserData30July2021-MichaelMardahl.zip -REGSource Edge-ProfilesRegistry30July2021-MichaelMardahl.reg -ExistingDataAction Remove 35 | #> 36 | 37 | #Add the -verbose parameter to commandline to get extra output. 38 | [CmdletBinding()] 39 | param ( 40 | [Parameter(Mandatory = $true, HelpMessage = "Source of the Edge User Data profile backup archive")][string]$ZIPSource, 41 | [Parameter(Mandatory = $true, HelpMessage = "Source of the Edge Registry profile backup file")][string]$REGSource, 42 | [Parameter(Mandatory = $true, HelpMessage = "How to handle the existing profiles? Options are Backup or Remove")][ValidateSet('Rename', 'Remove')][string]$ExistingDataAction, 43 | [Parameter(Mandatory = $false, HelpMessage = "Force close all instances of Edge")][bool]$CloseEdge, 44 | [Parameter(Mandatory = $false, HelpMessage = "Choose which version of Edge to restore. (defaults to Stable)")][ValidateSet('Stable', 'Beta', 'Dev', 'Canary')][String]$Channel = "Stable" 45 | 46 | ) 47 | 48 | #region Execute 49 | 50 | #Verify that the entered sources exits and have the right fileextention 51 | if (-not ((Test-Path $ZIPSource) -or (-not ($ZIPSource -ilike "*.zip")))) { 52 | Write-Error "The entered source file could not be validated ($ZIPSource)" 53 | break 54 | } 55 | if (-not ((Test-Path $REGSource) -or (-not ($REGSource -ilike "*.reg")))) { 56 | Write-Error "The entered source file could not be validated ($REGSource)" 57 | break 58 | } 59 | 60 | $EdgeRunning = Get-Process msEdge -ErrorAction SilentlyContinue 61 | if ($EdgeRunning) { 62 | if ($CloseEdge) { Stop-Process -Name msEdge } 63 | else { 64 | Write-Error "Edge is still running, please close any open Edge Browsers and try again." 65 | break 66 | } 67 | } 68 | 69 | Write-Host "Starting Edge $channel profiles restore for $($env:USERNAME) - (DON'T OPEN Edge!) please wait..." -ForegroundColor Green 70 | Write-Verbose "Source archive : $ZIPSource" 71 | Write-Verbose "Source registry : $REGSource" 72 | 73 | 74 | #Define location of Edge Profile for current user 75 | if ($channel -eq "Stable") 76 | { 77 | $EdgeProfilesPath = (Join-Path -Path $env:LOCALAPPDATA -ChildPath "\Microsoft\Edge") 78 | } 79 | else { 80 | $EdgeProfilesPath = (Join-Path -Path $env:LOCALAPPDATA -ChildPath "\Microsoft\Edge $channel") 81 | } 82 | 83 | #Handle existing User Data 84 | $UserData = (Join-Path -Path $EdgeProfilesPath -ChildPath "\User Data") 85 | if (Test-Path $UserData) { 86 | Write-Verbose "Existing User Data folder found in $EdgeProfilesPath" 87 | if ($ExistingDataAction -eq "Rename") { 88 | $renameFolder = "$($UserData)-$((get-date -Format ddMMMMyyyy-HHmmss).ToString())" 89 | Write-Verbose "Rename parameter set - Renaming folder to '$renameFolder'" 90 | Rename-Item $UserData $renameFolder 91 | } 92 | else { 93 | Write-Verbose "Remove parameter set - Deleting existing data." 94 | Remove-Item $UserData -Recurse -Force 95 | } 96 | } 97 | 98 | #Import registry key 99 | Write-Verbose "Importing Registry backup from $REGSource" 100 | Invoke-Command { reg import "$REGSource" *>&1 | Out-Null} 101 | 102 | #Import user data 103 | # 104 | Write-Verbose "Decompressing '$ZIPSource' to $EdgeProfilesPath" 105 | try { 106 | Expand-Archive -Path $ZIPSource -DestinationPath $EdgeProfilesPath -Force 107 | Write-Host "Edge $channel Profile import completed to: $UserData" -ForegroundColor Green 108 | } 109 | catch { 110 | #Error out and cleanup 111 | Write-Error $_ 112 | Remove-Item $zipBackupDestination -Force -ErrorAction SilentlyContinue 113 | Remove-Item $regBackupDestination -Force -ErrorAction SilentlyContinue 114 | Write-Error "Edge import failed, did you forget to keep Edge closed?!" 115 | break 116 | } 117 | #endregion Execute 118 | } -------------------------------------------------------------------------------- /Public/Backup-EdgeProfiles.ps1: -------------------------------------------------------------------------------- 1 | function Backup-EdgeProfiles { 2 | <# 3 | .Synopsis 4 | Backup current users Microsoft Edge (Anaheim) Profiles. 5 | 6 | .Description 7 | Will backup all Edge "User Data" for the current user. 8 | 9 | .Parameter Verbose 10 | Enables extended output 11 | 12 | .Parameter Destination 13 | (optional) 14 | Location in which to save the backup ZIP and REG files 15 | Defaults to the users OneDrive 16 | 17 | .Parameter AddDate 18 | (optional - $true/$false) 19 | Applies a date stamp to the filenames. 20 | Defaults to $true 21 | 22 | .Parameter CloseEdge 23 | (optional - $true/$false) 24 | Close Edge process if running. 25 | 26 | .Parameter Channel 27 | (optional - 'Stable', 'Beta', 'Dev', 'Canary') 28 | Allow to choose which version of Edge to backup. 29 | 30 | .Parameter FoldersToClean 31 | (optional - Any folder within the profile) 32 | Allow to choose any folders which will be emptied on the profile before start compressing. This will destruct content within the current environment, use with caution. 33 | 34 | .Example 35 | # Backup the current users Edge Profiles to the _EdgeProfilesBackup folder in the users own OneDrive. 36 | Backup-EdgeProfiles 37 | 38 | .Example 39 | # Backup the current users Edge Profiles to the users own TEMP folder. 40 | Backup-EdgeProfiles -Destination $env:TEMP 41 | #> 42 | 43 | [CmdletBinding()] 44 | param ( 45 | [Parameter(Mandatory = $false, HelpMessage = "Destination of the Edge profile backup (Defaults to OneDrive root \_EdgeProfilesBackup)")][string]$Destination = (Join-Path -Path $env:OneDrive -ChildPath "\_EdgeProfilesBackup"), 46 | [Parameter(Mandatory = $false, HelpMessage = "Append the current date to the backup (Defaults to true)")][bool]$AddDate = $true, 47 | [Parameter(Mandatory = $false, HelpMessage = "Add option to exclude folders from the backup (Defaults to exclude 'Code Cache', 'Service Worker' and 'Cache' folders)")][String[]]$FoldersToClean = @("Cache"), 48 | [Parameter(Mandatory = $false, HelpMessage = "Force close all instances of Edge")][bool]$CloseEdge, 49 | [Parameter(Mandatory = $false, HelpMessage = "Choose which version od Edge to backup (defaults to Stable)")][ValidateSet('Stable', 'Beta', 'Dev', 'Canary')][String[]]$Channel = @("Stable") 50 | ) 51 | 52 | #region Execute 53 | 54 | #Verify that the entered destination exists 55 | if ((-not (Test-Path $Destination) -and ($Destination -eq (Join-Path -Path $env:OneDrive -ChildPath "\_EdgeProfilesBackup")))) { 56 | #Create default destination 57 | New-Item -ItemType Directory -Path $Destination -Force | Out-Null 58 | } 59 | elseif (-not (Test-Path $Destination)) { 60 | Write-Warning "The entered destination path could not be validated ($Destination)" 61 | break 62 | } 63 | 64 | #Verify Edge is closed 65 | $EdgeRunning = Get-Process msEdge -ErrorAction SilentlyContinue 66 | if ($EdgeRunning) { 67 | if ($CloseEdge) { Stop-Process -Name msEdge } 68 | else { 69 | Write-Error "Edge is still running, please close any open Edge Browsers and try again." 70 | break 71 | } 72 | } 73 | 74 | foreach ($chan in $Channel) { 75 | Write-Host "Starting Edge $chan profiles backup for $($env:USERNAME) to ($Destination) - DON'T OPEN Edge! and please wait..." -ForegroundColor Green 76 | Write-Verbose "Destination root : $Destination" 77 | Write-Verbose "Append date : $AddDate" 78 | 79 | #Date name addition check 80 | if ($AddDate) { 81 | $dateName = (get-date -Format ddMMMMyyyy).ToString() 82 | } 83 | else { 84 | $dateName = "" 85 | } 86 | 87 | if ($chan -eq "stable") { 88 | $EdgeProfilesPath = (Join-Path -Path $env:LOCALAPPDATA -ChildPath "\Microsoft\Edge") 89 | $EdgeProfilesRegistry = "HKCU\Software\Microsoft\Edge\PreferenceMACs" 90 | 91 | } 92 | else { 93 | $EdgeProfilesPath = (Join-Path -Path $env:LOCALAPPDATA -ChildPath "\Microsoft\Edge $chan") 94 | $EdgeProfilesRegistry = "HKCU\Software\Microsoft\Edge $chan\PreferenceMACs" 95 | 96 | } 97 | 98 | 99 | #Export registry key 100 | $regBackupDestination = (Join-Path -Path $Destination -ChildPath "\Edge$chan-ProfilesRegistry$($dateName)-$($env:USERNAME).reg") 101 | Write-Verbose "Exporting Registry backup to $regBackupDestination" 102 | #Remove any existing destination file, else the export will stall. 103 | if (($regBackupDestination -ilike "*.reg") -and (Test-Path $regBackupDestination)) { 104 | Remove-Item $regBackupDestination -Force -ErrorAction SilentlyContinue 105 | } 106 | Invoke-Command { reg export "$EdgeProfilesRegistry" "$regBackupDestination" *>&1 | Out-Null} 107 | 108 | #Export user data 109 | 110 | #Cleaning cache 111 | Write-Verbose "Cleaning up folders before export." 112 | if (Test-Path $edgeProfilesPath) { 113 | $cacheFolders = Get-ChildItem -Path $edgeProfilesPath -r | Where-Object { $_.PsIsContainer -and $_.Name -in $FoldersToClean } 114 | Foreach ($folder in $cacheFolders) { 115 | $rmPath = Join-Path -Path $folder.fullname -ChildPath "\*" 116 | Write-Verbose "Emptying $rmPath" 117 | Remove-Item $rmPath -Recurse -Force 118 | } 119 | Write-Verbose "Cleanup completed." 120 | } 121 | else { 122 | Write-Error "Edge user data folder missing - terminating!" 123 | break 124 | } 125 | 126 | #Creating ZIP Archive 127 | $zipBackupDestination = (Join-Path -Path $Destination -ChildPath "\Edge$chan-UserData$($dateName)-$($env:USERNAME).zip") 128 | Write-Verbose "Exporting user data backup to $zipBackupDestination" 129 | #Remove any existing destination file, else the export will fail. 130 | if (($zipBackupDestination -ilike "*.zip") -and (Test-Path $zipBackupDestination)) { 131 | Remove-Item $zipBackupDestination -Force -ErrorAction SilentlyContinue 132 | } 133 | #Compressing data to backup location 134 | try { 135 | Get-ChildItem -Path $edgeProfilesPath | Compress-Archive -DestinationPath $zipBackupDestination -CompressionLevel Fastest 136 | Write-Host "Edge $chan Profile export completed to: $Destination" -ForegroundColor Green 137 | } 138 | catch { 139 | #Error out and cleanup 140 | Write-Error $_ 141 | Remove-Item $zipBackupDestination -Force -ErrorAction SilentlyContinue 142 | Remove-Item $regBackupDestination -Force -ErrorAction SilentlyContinue 143 | Write-Error "Edge $chan Backup failed, did you forget to keep Edge closed?!" 144 | break 145 | } 146 | #endregion Execute 147 | } 148 | 149 | } --------------------------------------------------------------------------------