Using Powershell to get installed Edge and Chrome extensions

I want to start off with acknowledging that I know, but don’t have the ability, to manage Google Chrome in an organizational setting through Google Cloud which produces nice reports of extensions installed — and this can even be done with M365 Defender. My dilemma is that for some networks I do not have the ability to do this, so I needed an alternative way. This is what I’m developing.

I found an article on Spiceworks that someone created a PowerShell script already while I was trying to find the original article I got the inspiration from. I learned a little about how Chrome extensions use manifest.json and that “name” key doesn’t always, as of Manifest V2, give the actual extension name.

Reading through Chrome.18n documentation on how the manifest is laid out and internationalization structure, I was able to figure out a way to programmatically look things up.

In manifest.json the following keys are required:

default_locale is required. It can be any value, really, but standards are en_US, en, ru, etc.

name is required. It can be the actual name of the extension, but in Manifest V3, it is the string to translate which is preceded by __MSG_ and ends with __ (two underscores). The value between could be anything, for example __MSG_name__ or __MSG_AppName__.

So my thought is to look up the name key, check for __MSG_ and also the default_locale if the name key matches. This then lets me find messages.json which I can use the __MSG_name__ to find the actual extension name.

Disclaimer: This is my script so far; my PowerShell sucks. But it works for me. I do know I need to handle and log errors (unavailable computers, etc.) and not rely on -ErrorAction SilentlyContinue.

October 2024: I just realized this does not capture Developer mode unpacked/packed extensions that may be installed.

# Ensure necessary modules are loaded
Import-Module ActiveDirectory

# Define an array to store the extensions
$extensions = @()

# Define a hash table of browsers/paths
$browsers = @{
    "Edge" = "AppData\Local\Microsoft\Edge\User Data\Default\Extensions"
    "Chrome" = "AppData\Local\Google\Chrome\User Data\Default\Extensions"
}

Clear-Host

# Get a list of AD computers (handling domain and local environments)
try {
    $computers = Get-ADComputer -Filter * -Credential (Get-Credential)
} catch {
    Write-Host "Could not retrieve AD computers. Running on local machine."
    $computers = @([pscustomobject]@{ Name = $env:COMPUTERNAME })
}

foreach ($computer in $computers) {
    $computerName = $computer.Name
    $computerPath = "\\$computerName\c$\Users"

    Write-Host "******************** $computerName **********************"

    # Get a list of users excluding 'Public' and 'Default'
    try {
        $users = Get-ChildItem -Path $computerPath -ErrorAction SilentlyContinue |
                 Where-Object { $_.PSIsContainer -and $_.Name -notmatch '^(Public|Default|All Users|Default User|defaultuser0|WDAGUtilityAccount)$' }
    } catch {
        Write-Host "Failed to access users on $computerName. Skipping."
        continue
    }

    foreach ($user in $users) {
        $userName = $user.Name
        Write-Host "Checking $userName : $computerName`n"

        foreach ($browser in $browsers.Keys) {
            $browserPath = $browsers[$browser]
            $extensionPath = Join-Path -Path $computerPath -ChildPath "$userName\$browserPath"

            # Check if the Extensions folder exists
            if (Test-Path -Path $extensionPath -ErrorAction SilentlyContinue) {
                $manifestFiles = Get-ChildItem -Path $extensionPath -Filter manifest.json -Recurse -ErrorAction SilentlyContinue

                foreach ($manifestFile in $manifestFiles) {
                    $extDir = $manifestFile.DirectoryName
                    $extID = $manifestFile.Directory.Parent.Name
                    $manifestData = Get-Content -Path $manifestFile.FullName | ConvertFrom-Json

                    $extensionName = if ($manifestData.name -like "*__MSG_*") {
                        $msgJSON = Join-Path -Path $extDir -ChildPath "_locales\$($manifestData.default_locale)\messages.json"
                        $extNameKey = $manifestData.name -replace "__MSG_", "" -replace "__", ""
                        (Get-Content -Encoding UTF8 -Path $msgJSON | ConvertFrom-Json).$extNameKey.message
                    } else {
                        $manifestData.name
                    }

                    $extensions += [PSCustomObject]@{
                        ComputerName  = $computerName
                        UserName      = $userName
                        ExtensionName = $extensionName
                        ExtensionID   = $extID
                        Browser       = $browser
                    }
                    Write-Host "[$browser]: $extensionName ($extID)"
                }
                Write-Host "`n"
            }
        }
    }
}

# Export the extensions to a CSV file
$extensions | Export-Csv -Path "browser_extension_report.csv" -Encoding UTF8 -NoTypeInformation

Once it is done, a report should be created as a CSV. Here’s an example. It lists each extension installed for every user per machine scanned.

Managing Extensions in Google Chrome

What I’m working on now is a way to uninstall these after I review installed extensions and determine which ones I want to remove and block from re-installation. This is still a work in progress, here are some of my notes.

This is for removing an app, not an extension. See: Extension and App Types

"C:\Program Files\Google\Chrome\Application\chrome.exe" --profile-directory=Default --uninstall-app-id=EXTENSION_ID;

I’m also seeing some references to registry locations.

HKEY_USERS\Group Policy Objects\Machine\Software\Policies\Google\Chrome\ExtensionInstallForcelist
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist

Looks like I need to add the extension to the ExtensionInstallForceList and then remove it.

Add ForceInstall

New-ItemProperty -Path "HKLM\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist " -Name "1" -Value EXTENSION_ID

Remove ForceInstall

Note: Need to specify the same value that was added in the Add step. This does not actually remove the extension if it is installed.

Remove-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist" -Name "EXTENSION_NAME"

Remove (uninstall) the Extension

Could it be as simple as deleting the actual extension folder? sigh

Remove-Item -Path "C:\users\username\appdata\local\google\chrome\user data\default\extension\EXTENSION_ID" -Recurse

Block Extension

Use * for the EXTENSION_NAME and value of 1 to block all extension installations.

Note: -Name is an integer value being placed in the registry. To add another blocked extension, make sure to increment to the another value.

New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallBlocklist" -Name "1" -Value EXTENSION_ID;

Allow Extension

New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallAllowlist" -Name "1" -Value EXTENSION_ID;

I’ll end up doing this by Group Policy instead of per-computer in Active Directory environments. I’ll block all, and permit only approved extensions.

Group Policy (Google Policy Templates): Computer Configuration > Administrative Templates > Class Administrative Templates > Google > Chrome > Extensions

16 million failed SIP registrations in 24 hours from 1 host

I recently stood up a Bicom PBXware virtual machine to do some testing. I noticed that there were a few thousand SIP registration failures a couple hours later as the box sat idle.

Today, I hopped on the box to begin some configuration for my testing environment and noticed the failed SIP registrations now sat at 16 million, or about 185/sec.

Investigating only from the dashboard, I noticed that they were all from the same IP address 167.x.x.255, which is a Digital Ocean IP. If I disable the PBXware Proxy service, it brings the failed SIP registrations to a screeching halt.

Tomorrow I’ll investigate this more. For now, I’ve disabled the PBXware Service from the web administration.

Detecting if SIP ALG is enabled on network

In trying to determine on a network that I don’t manage whether the network is “SIP Aware” (SIP ALG), I used the following method to quickly test.

Client Network

LAN192.168.1.1/24
WAN11.22.33.44
SIP Phone192.168.1.60

Remote Network

SIP Server4.49.115.30

I configured my phone to point to my linux server at 4.49.115.30 as the SIP server and started up a capture using tcpdump.

tcpdump -i ens192 -w sip_alg.pcap

I ran it for a few seconds to capture traffic from my phone.

Packet Showing Network With ALG

If the network is SIP aware and using ALG, the Contact: portion of the packet header message will show the public IP of the client’s network.

REGISTER sip:4.49.115.30:5060 SIP/2.0
Via: SIP/2.0/UDP 11.22.33.44:22501;branch=z9hG4bK738593727
From: "200" <sip:200@4.49.115.30:5060>;tag=738463962
To: "200" <sip:200@4.49.115.30:5060>
Call-ID: 0_738583021@192.168.1.60
CSeq: 1 REGISTER
Contact: <sip:200@11.22.33.44:22501>
Allow: INVITE, INFO, PRACK, ACK, BYE, CANCEL, OPTIONS, NOTIFY, REGISTER, SUBSCRIBE, REFER, PUBLISH, UPDATE, MESSAGE
Max-Forwards: 70
User-Agent: Yealink SIP-T33G 124.86.0.40 805e0cxxxxxx
Expires: 3600
Allow-Events: talk,hold,conference,refer,check-sync
Content-Length: 0

Packet Showing Network Without ALG

If the network is not SIP aware and using ALG, the Contact: portion of the packet header message will show the RFC 1918 IP address on the client’s network.

REGISTER sip:4.49.115.30:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.60:5060;branch=z9hG4bK735305753
From: "200" <sip:702200@4.49.115.30:5060>;tag=735174715
To: "200" <sip:702200@4.49.115.30:5060>
Call-ID: 0_735247007@192.168.1.60
CSeq: 1 REGISTER
Contact: <sip:200@192.168.1.60:5060>
Allow: INVITE, INFO, PRACK, ACK, BYE, CANCEL, OPTIONS, NOTIFY, REGISTER, SUBSCRIBE, REFER, PUBLISH, UPDATE, MESSAGE
Max-Forwards: 70
User-Agent: Yealink SIP-T33G 124.86.0.40 805e0cxxxxxx
Expires: 3600
Allow-Events: talk,hold,conference,refer,check-sync
Content-Length: 0

Disable SIP ALG

Here are some ways to disable SIP ALG on various devices I’ve had experience with.

Cisco ASA

ciscoasa> enable
Password:
ciscoasa# config terminal
ciscoasa(config)# policy-map global_policy
ciscoasa(config-pmap)# class inspection_default
ciscoasa(config-pmap-c)# no inspect sip

Windows Resource Protection could not perform the requested operation.

Running an sfc /scannow on a Windows Server 2019 Standard server, at about 76% it failed with the following message.

Windows Resource Protection could not perform the requested operation.
Edit

Looking through %Windir%\Windows\Logs\CBS.log I see the following:

2023-08-17 15:34:41, Error                 CSI    00004fa8 (F) c0000011 [Error,Facility=(system),Code=17 (0x0011)] #38088700# from Windows::Rtl::SystemImplementation::DirectFileSystemProvider::SysReadFile(h = cd4 ('\Device\HarddiskVolume2\Windows\WinSxS\amd64_windows-defender-management-powershell_31bf3856ad364e35_10.0.17763.831_none_5892c02f26f780e5\MSFT_MpComputerStatus.cdxml'), evt = 0, apcr = NULL, apcc = NULL, iosb = @0x45dec7c050, data = {l:0 b:}, byteoffset = (null), key = (null))
[gle=0xd0000011]
2023-08-17 15:34:41, Error                 CSI    00004fa9@2023/8/17:19:34:41.397 (F) onecore\base\wcp\sil\ntsystem.cpp(3610): Error c0000011 [Error,Facility=(system),Code=17 (0x0011)] originated in function Windows::Rtl::SystemImplementation::DirectFileSystemProvider::SysReadFile expression: (null)
[gle=0x80004005]
2023-08-17 15:34:41, Info                  CBS    Could not get active session for current session file logging [HRESULT = 0x80004003 - E_POINTER]
2023-08-17 15:34:41, Info                  CBS    Could not get file name for current session file logging [HRESULT = 0x80004003 - E_POINTER]
2023-08-17 15:34:41, Info                  CBS    Added C:\Windows\Logs\CBS\CBS.log to WER report.

Event Viewer details three events:

Fault bucket 1793356441015391089, type 5
Event Name: WindowsWcpOtherFailure3
Response: Not available
Cab Id: 0

Problem signature:
P1: 10.0.17763.4640:3
P2: wcp\sil\ntsystem.cpp
P3: Windows::Rtl::SystemImplementation::DirectFileSystemProvider::SysReadFile
P4: 3610
P5: c0000011
P6: 0x435f651d
P7:
P8:
P9:
P10:

Attached files:
\\?\C:\Windows\Logs\CBS\CBS.log
\\?\C:\Windows\Logs\CBS\CbsPersist_20230817123621.log
\\?\C:\Windows\Logs\CBS\CbsPersist_20230816233716.log
\\?\C:\Windows\Logs\CBS\CbsPersist_20230815183505.log
\\?\C:\Windows\Logs\CBS\CbsPersist_20230814052711.log
\\?\C:\Windows\Logs\CBS\CbsPersist_20230812022642.cab
\\?\C:\Windows\servicing\Sessions\Sessions.xml
\\?\C:\Windows\WinSxs\poqexec.log
\\?\C:\Windows\Logs\Cbs\FilterList.log
\\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WERB67.tmp.WERInternalMetadata.xml
\\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WERBA6.tmp.xml
\\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WERC42.tmp.csv
\\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WERC62.tmp.txt
\\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WERC92.tmp.mdmp
\\?\C:\ProgramData\Microsoft\Windows\WER\ReportQueue\Critical_10.0.17763.4640__7ecf3189d0be67147e71f883985df1bed431e6e_00000000_cab_17b40ef1\memory.hdmp
\\?\C:\Windows\Temp\WEREF4.tmp.WERDataCollectionStatus.txt

These files may be available here:
\\?\C:\ProgramData\Microsoft\Windows\WER\ReportArchive\Critical_10.0.17763.4640__7ecf3189d0be67147e71f883985df1bed431e6e_00000000_10e8155a

Analysis symbol:
Rechecking for solution: 0
Report Id: b33a6f7e-74bf-456a-a60e-9af2f5c88c59
Report Status: 268435456
Hashed bucket: 8f95577d69101277c8e3482e76619371
Cab Guid: 0

Slow Performance VMware Workstation 17.0.x – Windows 10 / Windows 11

Noticed horrible performance using VMware Workstation 17 on my system. I was running Hyper-V side-by-side, so I decided to nuke Hyper-V and the subsystems from that.

  1. Removed the Hyper-V, Virtual Machine Platform, and Windows Hypervisor Platform from Windows Features.
  2. Checked to see if Memory Core Isolation was disabled, and it was. Start > Core Isolation
  3. Disabled power throttling for the VMware process:
powercfg /powerthrottling disable /path "C:\Program Files (x86)\VMware\VMware Workstation\x64\vmware-vmx.exe"
  1. Turned off ULM/Hyper-V mode
bcdedit /set hypervisorlaunchtype off
  1. Disabled Accelerated 3D Graphics in the VM settings in VMware Workstation 17.0.2.

Step 5 was the winner, for me.

I had noticed before that my GPU (Intel UHD 630 Graphics) was pegged 80%+ when attempting to work with a VMware Workstation 17.0.x virtual machine. I never put the two together. You can add the following configuration value, mks.enable3d = "FALSE", to your .vmx file, or you can edit the VM and uncheck Accelerate 3D Graphics in the Display portion of the VM configuration in VMware Workstation.