15

I want to be able to deploy Google Chrome for Business in my organization without any extra shortcuts being created and without any first-run prompts. The Chrome for Business installer is a Windows Installer file (MSI), but it is just a wrapper around an executable installer. It does not have properties such as CreateDesktopShortcut that could be set at the msiexec command line like a lot of MSI installers do. How can I customize my installation? I would prefer not to write and maintain an installation script.

Jay Michaud
  • 3,947
  • 4
  • 21
  • 36

2 Answers2

27

Google Chrome stores the default user preferences in a master_preferences file. This is a text file in JSON format, and it includes a distribution object containing settings that will be read during installation. Editing this file in an existing Chrome installation does not solve the problem because the installation has obviously already occurred at that point. The solution is to integrate a customized master_preferences file into the Windows Installer installation process by using a transformation file. Take the following steps to accomplish this.

Gather the Required Installers and Tools

  1. Google Chrome for Business installer.
    I’ll download the 64-bit version to E:\Chrome for Business 38 (64-bit).
  2. Microsoft Windows Software Development Kit (SDK) for Windows 8.1.
    I’ll download this to E:\WindowsSDK8.1.
  3. Install the Windows SDK: E:\WindowsSDK8.1.\sdksetup.exe.
  4. Install Orca (the Windows Installer database editor):
    msiexec /package "C:\Program Files (x86)\Windows Kits\8.1\bin\x86\Orca-x86_en-us.msi".

Write a customized master_preferences file

  1. Review the available distribution settings. These are properties of a distribution object, which is contained within the anonymous object in the master_preferences file. The following list of settings was compiled by combining two Chromium source files: master_preferences_constants.h and master_preferences_constants.cc in /trunk/src/chrome/installer/util/. Note that the following is not valid JSON because no values are included for the properties. An example is shown further below.
{
  "distribution" : {
    // All the preferences below are expected to be inside the JSON "distribution"
    // block (as shown here). Some of them also have equivalent command line option. 
    // If same option is specified in master preference as well as command line, 
    // the command line value takes precedence.

    // Boolean. Use alternate text for the shortcut. Cmd line override present.
    "alternate_shortcut_text"

    // Boolean. Whether to instruct the installer to auto-launch chrome on computer
    // startup. The default (if not provided) is |false|.
    "auto_launch_chrome"

    // Boolean. This is to be a Chrome install. (When using MultiInstall)
    "chrome"

    // Boolean. This is to be a Chrome App Host install.
    "app_host"  // TODO(huangs): Remove by M27.

    // Boolean. This is to be a Chrome App Launcher install.
    "app_launcher"

    // Integer. Icon index from chrome.exe to use for shortcuts.
    "chrome_shortcut_icon_index"

    // Boolean. This is a legacy preference and should no longer be used; it is
    // kept around so that old master_preferences which specify
    // "create_all_shortcuts":false still enforce the new
    // "do_not_create_(desktop|quick_launch)_shortcut" preferences. Setting this to
    // true no longer has any impact.
    "create_all_shortcuts"

    // Boolean pref that disables all logging.
    "disable_logging"

    // Name of the dictionary that holds the distribution values.
    "distribution"

    // Boolean pref that triggers silent import of the default browser bookmarks.
    "import_bookmarks"

    // String pref that triggers silent import of bookmarks from the html file at
    // given path.
    "import_bookmarks_from_file"

    // Boolean pref that triggers silent import of the default browser history.
    "import_history"

    // Boolean pref that triggers silent import of the default browser homepage.
    "import_home_page"

    // Boolean pref that triggers silent import of the default search engine.
    "import_search_engine"

    // Integer. RLZ ping delay in seconds.
    "ping_delay"

    // String of Chrome version for which the "set as default browser" infobar will
    // never be shown.
    "suppress_default_browser_prompt_for_version"

    // Boolean. Do not show first run bubble, even if it would otherwise be shown.
    "suppress_first_run_bubble"

    // Boolean. Prevent creation of all shortcuts to chrome, including the
    // desktop, quick launch, taskbar and the start menu shortcuts.
    "do_not_create_any_shortcuts"

    // Boolean. Prevent creation of the Desktop shortcut on install (and later on
    // Active Setup for each user on a system-level install).
    "do_not_create_desktop_shortcut"

    // Boolean. Prevent creation of the Quick Launch shortcut on install (and later
    // on Active Setup for each user on a system-level install).
    "do_not_create_quick_launch_shortcut"

    // Boolean. Prevent creation of the Taskbar (since Windows 7) shortcut on
    // install (and later on Active Setup for each user on a system-level install).
    "do_not_create_taskbar_shortcut"

    // Boolean. Do not launch Chrome after first install. Cmd line override present.
    "do_not_launch_chrome"

    // Boolean. Do not register with Google Update to have Chrome launched after
    // install. Cmd line override present.
    "do_not_register_for_update_launch"

    // String.  Specifies the file path to write logging info to.
    "log_file"

    // Boolean. Register Chrome as default browser. Cmd line override present.
    "make_chrome_default"

    // Boolean. Register Chrome as default browser for the current user.
    "make_chrome_default_for_user"

    // Boolean. Expect to be run by an MSI installer. Cmd line override present.
    "msi"

    // Boolean. Support installing multiple products at once.
    "multi_install"

    // Boolean. Show EULA dialog before install.
    "require_eula"

    // Boolean. Indicates that the first-run 'set-as-default' dialog should not be
    // shown. Relevant in Windows 8+ context only. If this is true, the standard
    // 'set default browser' prompt on the butter-bar will appear during the first
    // run.
   "suppress_first_run_default_browser_prompt"

    // Boolean. Install Chrome to system wise location. Cmd line override present.
    "system_level"

    // Boolean. Run installer in verbose mode. Cmd line override present.
    "verbose_logging"

    // Name of the block that contains the extensions on the master preferences.
    "extensions.settings"
  }
}
  1. Review the available non-distribution settings. These settings go outside of the distribution object in the JSON. They are applied to the user profile when a user runs Chrome for the first time. The full list of settings is available in the Chromium source files pref_names.h and pref_names.cc in /trunk/src/chrome/common/. The list is rather lengthy, so only a subset is shown here.
{
// *************** PROFILE PREFS ***************
// These are attached to the user profile

// A string property indicating whether default apps should be installed
// in this profile.  Use the value "install" to enable defaults apps, or
// "noinstall" to disable them.  This property is usually set in the
// master_preferences and copied into the profile preferences on first run.
// Defaults apps are installed only when creating a new profile.
"default_apps"

// If set to true profiles are created in ephemeral mode and do not store their
// data in the profile folder on disk but only in memory.
"profile.ephemeral_mode"

// A boolean specifying whether the New Tab page is the home page or not.
"homepage_is_newtabpage"

// This is the URL of the page to load when opening new tabs.
"homepage"

// An integer pref. Holds one of several values:
// 0: (deprecated) open the homepage on startup.
// 1: restore the last session.
// 2: this was used to indicate a specific session should be restored. It is
//    no longer used, but saved to avoid conflict with old preferences.
// 3: unused, previously indicated the user wants to restore a saved session.
// 4: restore the URLs defined in kURLsToRestoreOnStartup.
// 5: open the New Tab Page on startup.
"session.restore_on_startup"

// The URLs to restore on startup or when the home button is pressed. The URLs
// are only restored on startup if kRestoreOnStartup is 4.
"session.startup_urls"

// Boolean that is true when SafeBrowsing is enabled.
"safebrowsing.enabled"

// Boolean that tell us whether malicious download feedback is enabled.
"safebrowsing.extended_reporting_enabled"

/* Might be useful for highly-secure workstations. */
// Enum that specifies whether Incognito mode is:
// 0 - Enabled. Default behaviour. Default mode is available on demand.
// 1 - Disabled. Used cannot browse pages in Incognito mode.
// 2 - Forced. All pages/sessions are forced into Incognito.
"incognito.mode_availability"

// Boolean that is true when Suggest support is enabled.
"search.suggest_enabled"

// A boolean pref set to true if a Home button to open the Home pages should be
// visible on the toolbar.
"browser.show_home_button"

// Boolean that indicates whether we should check if we are the default browser
// on start-up.
"browser.check_default_browser"

// Policy setting whether default browser check should be disabled and default
// browser registration should take place.
"browser.default_browser_setting_enabled"

// Boolean that specifies whether to import bookmarks from the default browser
// on first run.
"import_bookmarks"

// Boolean that specifies whether to import the browsing history from the
// default browser on first run.
"import_history"

// Boolean that specifies whether to import the homepage from the default
// browser on first run.
"import_home_page"

// Boolean that specifies whether to import the search engine from the default
// browser on first run.
"import_search_engine"

// Boolean that specifies whether to import the saved passwords from the default
// browser on first run.
"import_saved_passwords"

// Boolean that specifies if the sign in promo is allowed to show on first run.
// This preference is specified in the master preference file to suppress the
// sign in promo for some installations.
"sync_promo.show_on_first_run_allowed"

// *************** LOCAL STATE ***************
// These are attached to the machine/installation

// Note: Both settings included below are for Windows only.

// Whether downloaded PDFs should be opened in Adobe Acrobat Reader.
"download.open_pdf_in_adobe_reader"

// Preference to be used while relaunching Chrome. This preference dictates if
// Chrome should be launched in Metro or Desktop mode.
// For more info take a look at ChromeRelaunchMode enum.
"relaunch.mode"

// Boolean that specifies if the sign in promo is allowed to show on first run.
// This preference is specified in the master preference file to suppress the
// sign in promo for some installations.
"sync_promo.show_on_first_run_allowed";

// Boolean that specifies if we should show a bubble in the new tab page.
// The bubble is used to confirm that the user is signed into sync.
"sync_promo.show_ntp_bubble";

// As part of the master preferences an optional section indicates the tabs
// to open during first run. An example is the following:
"first_run_tabs": [
  "http://google.com/f1",
  "https://google.com/f2"
]
// Note that the entries are usually urls but they don't have to be.
  1. Choose the settings you want, and write your own custom master_preferences text file. Here is the one that is built into the Windows Installer file (expanded to multiple lines for readability):
{
  "distribution" : 
  {
    "msi" : true,
    "system_level" : true,
    "verbose_logging" : true
  }
}

You must include all of these properties as shown in your master_preferences file in order for the installer to work correctly. Therefore, you should start with this and add to it. My file is shown below. The only way I found to stop Chrome from asking the user to configure a Google account was to set first_run_tabs property.

{
  "browser" : {
    "check_default_browser" : false
  },
  "distribution" : {
    "import_bookmarks" : false,
    "import_history" : false,
    "import_home_page" : false,
    "import_search_engine" : false,
    "suppress_first_run_bubble" : true,
    "do_not_create_desktop_shortcut" : true,
    "do_not_create_quick_launch_shortcut" : true,
    "do_not_create_taskbar_shortcut" : true,
    "do_not_launch_chrome" : true,
    "do_not_register_for_update_launch" : true,
    "make_chrome_default" : false,
    "make_chrome_default_for_user" : false,
    "msi" : true,
    "require_eula" : false,
    "suppress_first_run_default_browser_prompt" : true,
    "system_level" : true,
    "verbose_logging" : true
  },
  "first_run_tabs" : [
    "chrome://newtab"
  ],
  "homepage" : "chrome://newtab",
  "homepage_is_newtabpage" : true,
  "sync_promo" : {
    "show_on_first_run_allowed" : false
  }
}
  1. Browse to http://jslint.com/, copy your JSON into the Source box, and click the JSLint button. This will verify that you have good JSON. This is important, because feeding malformed JSON to the installer will yield unexpected and/or undesired results. Save the verified file for future reference.

  2. Make a copy of your verified JSON, and remove all of the spaces and new lines. The Chrome installer cannot handle newlines; including newlines will result in a corrupted installation that has to be removed via registry surgery and manual deletion of files. Removing spaces may not be necessary, but it matches what the setup authors did with the default JSON. Mine is shown below.

{"browser":{"check_default_browser":false},"distribution":{"import_bookmarks":false,"import_history":false,"import_home_page":false,"import_search_engine":false,"suppress_first_run_bubble":true,"do_not_create_desktop_shortcut":true,"do_not_create_quick_launch_shortcut":true,"do_not_create_taskbar_shortcut":true,"do_not_launch_chrome":true,"do_not_register_for_update_launch":true,"make_chrome_default":false,"make_chrome_default_for_user":false,"msi":true,"require_eula":false,"suppress_first_run_default_browser_prompt":true,"system_level":true,"verbose_logging":true},"first_run_tabs":["chrome://newtab"],"homepage":"chrome://newtab","homepage_is_newtabpage":true,"sync_promo":{"show_on_first_run_allowed":false}}
  1. Run the new JSON without spaces through JSLint to ensure that you did not introduce any errors.

  2. Copy the verified JSON without spaces or newlines into a URL encoder. I used URL Encode/Decode Online. Save the encoded JSON for use in the installer and for future reference. My encoded JSON is shown below.

%7B%22browser%22%3A%7B%22check_default_browser%22%3Afalse%7D%2C%22distribution%22%3A%7B%22import_bookmarks%22%3Afalse%2C%22import_history%22%3Afalse%2C%22import_home_page%22%3Afalse%2C%22import_search_engine%22%3Afalse%2C%22suppress_first_run_bubble%22%3Atrue%2C%22do_not_create_desktop_shortcut%22%3Atrue%2C%22do_not_create_quick_launch_shortcut%22%3Atrue%2C%22do_not_create_taskbar_shortcut%22%3Atrue%2C%22do_not_launch_chrome%22%3Atrue%2C%22do_not_register_for_update_launch%22%3Atrue%2C%22make_chrome_default%22%3Afalse%2C%22make_chrome_default_for_user%22%3Afalse%2C%22msi%22%3Atrue%2C%22require_eula%22%3Afalse%2C%22suppress_first_run_default_browser_prompt%22%3Atrue%2C%22system_level%22%3Atrue%2C%22verbose_logging%22%3Atrue%7D%2C%22first_run_tabs%22%3A%5B%22chrome%3A%2F%2Fnewtab%22%5D%2C%22homepage%22%3A%22chrome%3A%2F%2Fnewtab%22%2C%22homepage_is_newtabpage%22%3Atrue%2C%22sync_promo%22%3A%7B%22show_on_first_run_allowed%22%3Afalse%7D%7D

Write a Windows Installer Transformation

  1. Start Orca.
  2. Open the downloaded Chrome for Business MSI file as read-only. (I suppose you could edit the actual file, but I like using transforms so I always have the vendor-supplied file as a baseline if things go awry.) I downloaded Chrome for Business 38 64-bit, and the filename was googlechromestandaloneenterprise64.msi.
  3. On the Transform menu, select New Transform. Now all of the Windows Installer database tables are editable because you are editing a new transform file.
  4. Select the Property table.
  5. Right-click in the Property column and click "Add Row". Set the Property to MASTER_PREFERENCES, and set the Value to your URL-encoded JSON. This code will be applied during deployment and saved as the installation’s master_preferences file by the installer.
  6. Select the CustomAction table, and locate the BuildInstallCommand action.
  7. Double-click the Target cell for the BuildInstallCommand action to make it editable.
  8. Near the end of the text, delete the existing encoded JSON following installerdata= and replace it with the new property name in brackets. Be sure to retain the closing quotation mark. It should look like this: installerdata=[MASTER_PREFERENCES]"
  9. Press Enter to finish editing the cell.
  10. On the Transform menu, click Generate Transform… and save the new MST file. I saved mine as E:\Chrome for Business 38 (64-bit)\MasterPreferences.mst.
  11. Exit Orca.

Note: It is necessary to use a property rather than insert the JSON directly into the custom action because the custom action Target field is only 255 characters long. The schema of that table cannot be changed, and most custom JSON would take the total length of that field over the limit. Using a property avoids the length limitation, as there is no practical limit to the length of a property value.

Install Chrome with your Transformation

  1. Open a Command Prompt window with Administrative privileges.
  2. Install Google Chrome with your transformation by setting the TRANSFORMS property to its filename. Turn on logging to help you find anything wrong. Using my example folders and assuming that you are logged in as Administrator: msiexec /package "E:\Chrome for Business 38 (64-bit)\googlechromestandaloneenterprise64.msi" TRANSFORMS="E:\Chrome for Business 38 (64-bit)\MasterPreferences.mst" /l*v "C:\Users\Administrator\Desktop\ChromeInstallationLog.txt"
  3. If Chrome installs without error, try running it as a different, non-administrative user to ensure that the settings are propagating correctly.
  4. Finally, configure your deployment system with the installer and transformation file. I use System Center Configuration Manager 2012 R2. My command line for this Application is similar to the following: msiexec /package "googlechromestandaloneenterprise64.msi" /quiet TRANSFORMS="MasterPreferences.mst" /l*v "%TEMP%\ChromeInstallationLog.txt" This gives my users an app-store-like experience with Configuration Manager’s Software Center application, leaves control of the desktop and taskbar icons solely with the user, and avoids annoying first-run experiences. This is my preferred user experience generally, but it is especially useful for public-facing computers, such as in a computer lab, where hard drive changes are lost on each restart, and so every logon is the "first" logon.

Notes

See also Google's documentation on the master_preferences file, which covers a subset of the available settings, but does not tell you how to get the settings onto the machine during installation.

Thanks to grt@chromium.org for pointing out the MSI customization possibility. My goal here was to expand on that information to provide a comprehensive explanation and example solution. I hope it is helpful.

Jay Michaud
  • 3,947
  • 4
  • 21
  • 36
0

I don't have enough rep to post a comment. I was using Jay's guide to help with a problem getting a a downloaded file type to run automatically. And this appears to the only way to do it at the moment:

https://bugs.chromium.org/p/chromium/issues/detail?id=476668

-This link refers to a bug which AFAIK isn't fixed. The reporter would like to be able to set specific file types to run automatically on d/l via a GPO. The use case for this is limited given the security implications, but necessary sometimes in enterprise deployments. It can be achieved using Jay's technique in an .mst with master_preferences. (edit in response to Chick's comment)

I agree with you Tomtom, there should be an easier way. In the most part Google's .admx is sufficient.

  • Regardless of how much rep you have: a link-only answer is likely to get deleted. Can you make this make sense as an answer on its own and just reference the link for those that want to verify what you're saying or dig deeper. http://serverfault.com/help/how-to-answer – chicks Aug 24 '16 at 21:30