Install Google Chrome Extensions using Microsoft Intune in 3 different ways (Powershell, ADMX ingestion and MSI)

Introduction

I have previously covered the approach on how to install Google Chrome extensions using System Center Configuration Manager. Find my post here: https://www.imab.dk/forcefully-deploy-the-windows-defender-google-chrome-extension-using-configuration-manager/

Then it came to my attention that Microsoft released another and new extension for Chrome last week. It’s called Microsoft Web Activities. This made me go through the approach again, and figured I wanted to cover the methods on how to install Google Chrome Extensions using Microsoft Intune.

Method 1: Powershell Script

I know this is covered a lot of times on other blogs, and scripts for this purpose exists in various editions. No excuse though – this is my edition, which I believe does it a tad differently. 🙂

The script does following in details:

  • Creates registry path for the ExtensionInstallForcelist if it doesn’t exist. If extensions are added to the device by other means such as GPO or MDM, chances are this path exist already
    • If extensions are added by other means, there will exist registry key properties with unique consecutive numbers in the path. You don’t want to re-use a number in that case, which is why I loop through existing extensions prior to adding any new. Great!
    • If no extensions already added, we skip doing something complicated and just add the extensions as the first one
  • If the extension is not added already, the script adds it
    • An extension is defined by an unique ID and the Google URL. Example: eiipeonhflhoiacfbniealbdjoeoglid;https://clients2.google.com/service/update2/crx
  • Writing to host in case shit happens – I know real Powershell pros oppose this approach, but I’m just a newbie script kiddie 😀
<#   
.DESCRIPTION
    Adds the Microsoft Web Activities Google Chrome extension to the forced install list.
    Can be used for forcing installaiton of any Google Chrome extension.
    Takes existing extensions into account which might be added by other means, such as GPO and MDM.
    Assuming a maximum of possible installed extensions never exceeds a count of 20 - this can be changed as well. (who has more than 20 forced extensions added to Chrome? :-D)

.NOTES
    Filename: Install-GoogleChromeExtensions
    Version: 1.0
    Author: Martin Bengtsson
    Blog: www.imab.dk
    Twitter: @mwbengtsson
    
#>

# Function to enumerate registry values
Function Get-RegistryValues {
    param(
        [Parameter(Mandatory=$true)]
        [string]$Path
    )

    Push-Location
    Set-Location -Path $Path
    Get-Item . | Select-Object -ExpandProperty property | ForEach-Object {
        New-Object psobject -Property @{“Property”=$_;“Value” = (Get-ItemProperty -Path . -Name $_).$_}
    }
    Pop-Location
} 

# Registry path for the ExtensionInstallForcelist
$RegistryPath = "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist"
$KeyType = "String"

# Microsoft Web Activities Extension. This can be any extension. Modify to suit any needs
$ExtensionID = "eiipeonhflhoiacfbniealbdjoeoglid;https://clients2.google.com/service/update2/crx"

# Registry path does not exist. Creating the path
if (-not(Test-Path -Path $RegistryPath)) {
    Write-Host -ForegroundColor Red "Registry patch on $RegistryPath does not exist - trying to create it"
    try {
        New-Item -Path $RegistryPath -Force
    }
    catch {
        Write-Host -ForegroundColor Red "Failed to create registry path"
    }
}

# Loop through the existing values and properties in the registry
$InstalledExtensionsProperties = Get-RegistryValues -Path $RegistryPath | Select-Object Property
$InstalledExtensions = Get-RegistryValues -Path $RegistryPath | Select-Object Value

# Assuming that the list of forced extensions will never exceed a count of 20
$Values = 1..20

# If no registry key properties found, continue do something. No need to do something complicated, if no extensions exists already.
if ($InstalledExtensionsProperties -ne $null) { 
    
    # Finding next available number for use in KeyName
    $NextNumber = Compare-Object $InstalledExtensionsProperties.Property $Values | Select-Object -First 1
    $KeyName = $NextNumber.InputObject
    
    # If the extension is not installed already, install it
    if ($InstalledExtensions -match $ExtensionID) {
        Write-Host -ForegroundColor Green "$ExtensionID is already added. Doing nothing :-)"
        
    }
    # else try to add the extension please
    else {
        Write-Host -ForegroundColor Red "The extenion $ExtensionID is not found. Adding it."
        try {
            New-ItemProperty -Path $RegistryPath -Name $KeyName -PropertyType $KeyType -Value $ExtensionID
        }
        catch {
            Write-Host -ForegroundColor Red "Failed to create registry key"   
        }    
    }
}
# Else just add the extension as the first extension
else {
    
    Write-Host -ForegroundColor Red "No extensions already added. Adding the extensions as the first one"
    try {
        New-ItemProperty -Path $RegistryPath -Name 1 -PropertyType $KeyType -Value $ExtensionID
    }
    catch {
        Write-Host -ForegroundColor Red "Failed to create registry key"   
    }
}

Running the script

This is my computer prior to running the script. I have extensions added by ConfigMgr.

The real treat here is, that the extension added through above script automatically picks the next available number. Any other available method dictates that you are aware of existing extensions.

And after the script is run:

Put to use in Intune

This part is self explanatory, but for good measures head into the Microsoft 365 Device Management Portal at https://devicemanagement.microsoft.com and browse your way to Device Configuration -> Powershell scripts.

Add the script from above and assign it to your devices/users. Voila. Extensions for Chrome incoming.

Method 2: ADMX Ingestion

Regardless of whatever method you prefer, I think this is considered the most complicated. I will try to cover the basics in the most sensible way I can. If you want some deep dive details, please read Michael Mardahl’s excellent post here: https://www.iphase.dk/silent-configure-outlook-with-intune/

The first thing you need to do is to download the Google Chrome Administrative Templates. This is done from this link: https://cloud.google.com/chrome-enterprise/browser/download/

Once that is done, the file of interest is chrome.admx.

With that in hand, head into the Microsoft 365 Device Management Portal once again and browse to Device configurationProfiles and Create a profile.

In the new profile:

  • Name: Give it a suitable name like ADMX Ingestion – Google Chrome
  • Platform: Windows 10 and later
  • Profile type: Custom
  • Click Add

In the Edit Row blade:

  • Name: ADMX Ingestion – chrome.admx
  • OMA-URI: ./Device/Vendor/MSFT/Policy/ConfigOperations/ADMXInstall/Chrome/Policy/ChromeAdmx
  • Data type: String
  • Value: Copy / paste ALL the content from the chrome.admx file you downloaded earlier. That’s currently 2400-something lines of XML formatted awesomeness. Yes, it all fits into the text box.

Assign the Device Configuration Profile to a group consisting of devices similar to below example:

NEXT! Create another custom Windows 10 Device Configuration Profile with the same options as the first profile.

  • Name: ADMX Config – Google Chrome Extensions
  • Platform: Windows 10 and later
  • Profile type: Custom
  • Click Add

Again, in the Edit Row blade:

  • Name: ExtensionInstallForcelist
  • OMA-URI: ./Device/Vendor/MSFT/Policy/Config/Chrome~Policy~googlechrome~Extensions/ExtensionInstallForcelist
  • Data type: String
  • Value: <enabled/>
    <data id=”ExtensionInstallForcelistDesc” value=”1&#xF000;bkbeeeffjjeopflfhgeknacdieedcoml;https://clients2.google.com/service/update2/crx&#xF000;2&#xF000;eiipeonhflhoiacfbniealbdjoeoglid;https://clients2.google.com/service/update2/crx”/>

NOTE: Here you will see the requirement to specify the consecutive numbering manually. I’m adding 2 extensions in this profile and they are added as number 1 and 2, both highlighted in above code. This will potentially be a conflict if existing extensions are added by other means and 1 and 2 already exists on the device.

Assign this Device Configuration Profile as well to the same group consisting of devices. See my example below:

The result is the 2 entries in the registry being added:

Method 3: Packaged as MSI

Last but not least. A pragmatic approach is to simply package the registry entries into a MSI file.

Below is an example from Advanced Installer. This can be done with the free license.

This will obviously be registered with the Windows installer and thus appear from the Programs and features list.

The initial advantage here is also that the installation can be tracked with the Enrollment Status Page with AutoPilot – awesome stuff 🙂

End result

Regardless of whatever method you  prefer, the end result is the same. Delicious extensions in Google Chrome are added automatically!

Enjoy 🙂

15 thoughts on “Install Google Chrome Extensions using Microsoft Intune in 3 different ways (Powershell, ADMX ingestion and MSI)”

    • Absolutely! For most, the actual extension ID is found in the Google Web Store when browsing the extension in your browser. It’s a part of the URL. You can also find the extension id when browsing a local PC where the extension is installed already: AppData\Local\Google\Chrome\User Data\Default\Extensions. Hope that helps 🙂

      Reply
  1. Hello,

    Thank you for awesome article. I have 2 questions in regards to method 2:
    1) Any good way to remove these extension via Intune as well? I have tested both with altering XML with “” and running PS ”script” via Intune to remove RegKey “ExtensionInstallForcelistDesc”. But both have caused some issues, as seems its no longer possible to re-publish the same extensions after removed with script and XML way did not allow to install additional extensions.
    2) Whats the best way to add multiple extensions? Just keep going with same XML or create new Intune Profile and keep track of numbers?

    Reply
  2. hi
    the admx part is not working for me.
    “remediation failed”….
    Don’t know what’s wrong.
    i try to change the number of the extensions (from 1 to 2, to 3, to 4,….) but no !

    Reply
      • We all copy and pasted. That’s the problem. The code on the examples about the admx and forcing extensions contains curly quotes or smart quotes. This causes remediation to fail on that part of the configuration profile, but not the code straight from the admx template. This part: <data id=”ExtensionInstallForcelistDesc” is curly quotes, not straight double quotes. These do not play nice with code. I used notepad and noticed the problem, and had a PowerShell flashback. I think the code needs to be "code" type snippet in WordPress, but I'm not 100% sure if that will use the correct quotes. Being that I'm replying to a post over a year the chances are that you fixed it. Maybe the site owner will update his post. Great info here!

        Reply
  3. This works great for extensions using the .crx but the extension I’m trying to install is .exe. Is there a way to auto run this without having to get the using to click on the extension.exe once it’s downloaded in Chrome?

    Reply
  4. Hi Sir, Great article if you don’t mind telling me the detailed steps to have a Chrome Extension installed as a MSI file ?
    I downloaded Advanced Installer but don’t see the REGEDIT settings tab
    Please advise

    Reply
    • Advanced installer has a registry portion. Not sure if this requires a paid version of advanced installer, but I wouldn’t expect so. If you create a simple advanced installer project, there should be a registry portion in the menu to the left.

      Reply
  5. Hello!
    So I followed your instruction step by step for method 2 but it didn’t work….wondering if the users have to be signed in to Chrome in order to install…and the registry key is not showing anything after Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google so what’s the solution here?

    Reply
  6. Your script doesn’t work. It fails on the last ELSE after the # Else just add the extension as a first extension.

    else : The term ‘else’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check
    the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:1
    + else {
    + ~~~~
    + CategoryInfo : ObjectNotFound: (else:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.