Long story short: It's plain boring with traps all along the road but it's doable !!
As there are many ways to migrate I won't post a ready to use script, but just pieces of code for the trickiest steps.
What to migrate?
This article describes the item that you can migrate. Most people should be satisfied with their bookmaks. Those are located in the Firefox user profil in %APPDATA%\Mozilla\Firefox\Profiles\ <GUID>\Places.sqlite.
How to migrate is a no brainer as you simply have to copy the files corresponding to the settings you want to save. Simply store them in a place you are sure to reach once you’ll be in the restore phase.
Why it’s painful?
- If you come from a bare-metal deployment scenario. Restoring data to a never opened before Firefox is not possible. It must be opened one time to generate à user profile.
- The profile folder has a part of its name randomly generated, so the folder where you grabbed your settings files and the folder where you will restore them will have different names that you’ll have to guess.
- Firefox has its own behavior, when you launch it, it can’t be minimized like a standard application. It also can’t be terminated as standard apps otherwise the state of the profile will be tagged as corrupt and your imported settings will be ignored.
- Even if you ask politely Firefox to close, it will prompt you to make sure you want to close it which will break the closing process.
- User settings operate in the user context (Surpprised!!), something you’ll have to deal with if your migration script is running from MEMCM under system context or if it is running from an administartor account..
Now all the problem are identified, let’s solve them one by one:
Launching Firefox.
This step is required to create a new profile. You can use GPO to set up the app to launch when the user opens his session (startup script, scheduled task...), you can also use Runonce registry key. The only thing you should care about is being sure it runs in the user context otherwise the profile will be created for the local administrator and that’s definitely not what we want!
Now if for some reason, you must launch Firefox while you are in the administrator or system context, the profile will not be created for the current user. To overcome this shortcoming you can launch Firefox from a scheduled Task with the current logged on user using this piece of code:
$action = New-ScheduledTaskAction -Execute “C:\Program Files\Mozilla Firefox\firefox.exe”
$trigger = New-ScheduledTaskTrigger -AtLogOn
$principal = New-ScheduledTaskPrincipal -UserId (Get-CimInstance –ClassName Win32_ComputerSystem | Select-Object -expand UserName)
$Settings = New-ScheduledTaskSettingsSet -MultipleInstances Parallel
$task = New-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -Settings $Settings
Register-ScheduledTask 'Firefox-FirstRun' -InputObject $task|Out-Null
Start-ScheduledTask -TaskName 'Firefox-FirstRun'
Minimizing Firefox.
Firefox is a "different" animal and it can't be launched minimized, also the regular tricks like Start /MIN or Wscript.Run with hidden parameters don’t work. So to make the user experience a bit cleaner we will have to minimize it after he launched (not that great, but i didn’ find any better solution):
$MainWindowHandle = (Get-Process -Name "firefox"|Where {$_.MainWindowHandle -ne 0}).MainWindowHandle
$Win32ShowWindowAsync = Add-Type –memberDefinition @”
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
“@ -name “Win32ShowWindowAsync” -namespace Win32Functions –passThru
$Win32ShowWindowAsync::ShowWindowAsync($MainWindowHandle, 11) | Out-Null
This section is borrowed to Bob McCoy, thanks to him!
Grabbing the profile folder.
this one is easy and can be used both for identifying the source and destination folder
$CurrentUser = (((((quser) -replace '\s{2,}',',')|where {$_.startswith(">")}) -split ",")[0]).replace(">","")$Path = "C:\Users\$CurrentUser\Appdata\Roaming\Mozilla\Firefox\Profiles\*-release"
$Path = (Resolve-Path $Path).path
Write-host $Path
I’ve heard that the development team likes to change the profile location from time to time, I didn’t have to deal with that but i had to manage classic version and ESR as they name the user profile differently (<GUID>-release and <GUID>-reselase-esr respectively)
If you need to manage both version, you can identify them using their uninstall registry information
$FFVersion = (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*|where displayname -like '*Firefox*'|select displayname).DisplayNameIf ([string]::IsNullOrWhiteSpace($FFVersion))
If ($FFVersion -like "*ESR*"){$FFProfile = '*-esr'} Else {$FFProfile = '*-release'}
Shutting Down Firefox.
As i said before, Firefox is not you regular standard application. If you use a .Kill() method to stop it, the profile will break, you’ll have to use the .CloseMainWindow() methode to make it happy (Helge Klein to the rescue. Thanks a million!)
But it won’t be enough, if nothing is set, FireFox will show up a confirmation prompt before closing:

For this one, a local GPO must be set to disable the window prompt. All together, the closing process look like this:
# Disable close Tab Promptif((Test-Path -LiteralPath "HKLM:\SOFTWARE\Policies\Mozilla\Firefox\Preferences") -ne $true) { New-Item "HKLM:\SOFTWARE\Policies\Mozilla\Firefox\Preferences" -force -ea SilentlyContinue|Out-Null }
New-ItemProperty -LiteralPath 'HKLM:\SOFTWARE\Policies\Mozilla\Firefox\Preferences' -Name 'browser.tabs.warnOnClose' -Value 0 -PropertyType DWord -Force -ea SilentlyContinue|Out-Null
Get-Process -Name "firefox"|Foreach{$_.CloseMainWindow()}|Out-Null
Restoring settings.
Holy cow, after all those steps, we are now ready to restore the settings we’ve grabbed earlier. So files like places.sqlite, favicons.sqlite, key4.db, extensions folder can be copied back to the profile path with a -force option to overwrite the default one. everything was tested successfully with standard and ESR version using System and admin accounts.