Peter Hinchley

Learning in Public

✪ How to Install Microsoft Edge Chromium without Creating a Desktop Shortcut

Microsoft recently released the Chromium-based version of Microsoft Edge. Although various properties of the browser can be configured via group policy, it wasn’t obvious how I could prevent the creation of a desktop shortcut during installation.

I decided to look into the MSI (MicrosoftEdgeEnterpriseX64.msi) by cracking it open with Orca. This revealed a BuildInstallCommand action in the CustomAction table. This action specified the command line used during the installation of the browser. The command is shown below:

/silent /install "[ProductTag]" /installsource enterprisemsi[OptOmahaArgs] /appargs "appguid={56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}&installerdata=%7B%22distribution%22%3A%7B%22msi%22%3Atrue%2C%22system_level%22%3Atrue%2C%22verbose_logging%22%3Atrue%2C%22msi_product_id%22%3A%228061116E-DD27-34F8-A5C9-3361222BD2C8%22%2C%22allow_downgrade%22%3Afalse%7D%7D"

If you look carefully, you will notice that the installerdata property is set to a URL encoded JSON document. When decoded it looks like this:

{
  "distribution": {
    "msi": true,
    "system_level": true,
    "verbose_logging": true,
    "msi_product_id": "8061116E-DD27-34F8-A5C9-3361222BD2C8",
    "allow_downgrade": false
  }
}

This corresponds with the file that gets created at the following location during installation: C:\Program Files (x86)\Microsoft\Edge\Application\master_preferences

I already knew that the do_not_create_desktop_shortcut property could be added to the master_preferences file to prevent the creation of the desktop shortcut, but now it became clear how to easily update this configuration file during the installation of the browser.

The first step was to update the JSON configuration to include the do_not_create_desktop_shortcut property:

{
  "distribution": {
    "msi": true,
    "system_level": true,
    "verbose_logging": true,
    "msi_product_id": "8061116E-DD27-34F8-A5C9-3361222BD2C8",
    "allow_downgrade": false,
    "do_not_create_desktop_shortcut": true
  }
}

The second step was to remove all spaces from the file, and URL encode the result:

%7B%22distribution%22%3A%7B%22msi%22%3Atrue%2C%22system_level%22%3Atrue%2C%22verbose_logging%22%3Atrue%2C%22msi_product_id%22%3A%228061116E-DD27-34F8-A5C9-3361222BD2C8%22%2C%22allow_downgrade%22%3Afalse%2C%22do_not_create_desktop_shortcut%22%3Atrue%7D%7D

The third step was to update the BuildInstallCommand string to include the new encoded configuration:

/silent /install "[ProductTag]" /installsource enterprisemsi[OptOmahaArgs] /appargs "appguid={56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}&installerdata=%7B%22distribution%22%3A%7B%22msi%22%3Atrue%2C%22system_level%22%3Atrue%2C%22verbose_logging%22%3Atrue%2C%22msi_product_id%22%3A%228061116E-DD27-34F8-A5C9-3361222BD2C8%22%2C%22allow_downgrade%22%3Afalse%7D%7D"

And the final step was to create an MSI transform that would add that new command to the installer. To simplify this process, I wrote the following PowerShell script. The script assumes the MSI is located under C:\Temp, and when run, it will generate a transform in the same folder named MicrosoftEdgeEnterpriseX64.mst. It is then possible to install Edgium using the following command:

msiexec /i MicrosoftEdgeEnterpriseX64.msi /q TRANSFORMS=MicrosoftEdgeEnterpriseX64.mst

The result: no desktop shortcut!!

$installer = "C:\Temp\MicrosoftEdgeEnterpriseX64.msi"
$transform = "C:\Temp\MicrosoftEdgeEnterpriseX64.mst"

if (test-path $transform) { remove-item $transform -force }

$backup = "$installer.bak"

copy-item $installer $backup -force

$cmd = '/silent /install "[ProductTag]" /installsource enterprisemsi[OptOmahaArgs] /appargs "appguid={56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}&installerdata=%7B%22distribution%22%3A%7B%22msi%22%3Atrue%2C%22system_level%22%3Atrue%2C%22verbose_logging%22%3Atrue%2C%22msi_product_id%22%3A%228061116E-DD27-34F8-A5C9-3361222BD2C8%22%2C%22allow_downgrade%22%3Afalse%2C%22do_not_create_desktop_shortcut%22%3Atrue%7D%7D"'

$msi = New-Object -ComObject WindowsInstaller.Installer

$db1 = $msi.OpenDatabase($installer, 0)
$db2 = $msi.OpenDatabase($backup, 1)

$view = $db2.OpenView("UPDATE CustomAction SET Target = '$cmd' WHERE Action = 'BuildInstallCommand'")
$view.Execute()
$view.Close()
$view = $null

$db2.Commit()

$db2.GenerateTransform($db1, $transform) | out-null

$db2.CreateTransformSummaryInfo($db1, $transform, 0, 0)

$db1 = $null
$db2 = $null
$msi = $null

[GC]::Collect()

start-sleep -seconds 2

remove-item $backup -force