Add GoToMeeting as a macOS and Windows FMA - #46264
Conversation
Introduce GoToMeeting to maintained apps: add homebrew and winget input manifests, darwin and windows output metadata (with installers, checksums, and install/uninstall script refs), and frontend icon asset. Include Windows install/uninstall PowerShell scripts (MSI machine-wide install and uninstall via hard-coded UpgradeCode) and macOS DMG install/uninstall refs and scripts. Update ee/maintained-apps/outputs/apps.json to register GoToMeeting for darwin and windows. Also adjust Windows validation logic to special-case GoToMeeting version checks: winget reports a package version (10.19.0.19950) that contains an extra ".0" segment compared to the installed MSI/registry version (10.19.19950), so the validator falls back to existence-only validation and logs the difference.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #46264 +/- ##
==========================================
- Coverage 66.84% 66.83% -0.01%
==========================================
Files 2761 2762 +1
Lines 220853 220861 +8
Branches 10879 11010 +131
==========================================
- Hits 147626 147621 -5
- Misses 59860 59869 +9
- Partials 13367 13371 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Remove the ad-hoc GoToMeeting version-format special-case from Windows validation and instead rely on an explicit exists_query in the winget input. Update the winget input to use an exists_query (matching program DisplayName) and remove fuzzy_match_name/publisher constraints. Replace the simple MSI-related uninstall script with a robust PowerShell uninstall that locates the app's uninstall registry entry (HKLM/HKLM\WOW6432Node/HKCU), prefers QuietUninstallString, stops related processes, parses the uninstall command, adds silent switches when needed, and returns appropriate exit codes. Update the outputs to relax the publisher requirement for existence/patch checks and point to the new uninstall script ref.
Script Diff Resultsee/maintained-apps/outputs/gotomeeting/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/gotomeeting/windows.json=== Install Script (no changes) ===
=== Uninstall // da9b7854 -> 9ac6e58a ===
--- /tmp/old.v7ZS93 2026-05-27 17:35:14.218392471 +0000
+++ /tmp/new.rkTV9L 2026-05-27 17:35:14.219392464 +0000
@@ -1,26 +1,116 @@
-# Fleet uninstalls app by finding all related product codes for the specified upgrade code.
-# GoToMeeting's winget manifest does not expose the UpgradeCode, so it is hard-coded
-# here from the MSI's UpgradeCode property.
-$inst = New-Object -ComObject "WindowsInstaller.Installer"
-$timeoutSeconds = 300 # 5 minute timeout per product
-
-foreach ($product_code in $inst.RelatedProducts('{BF62CF5F-6CB1-4010-8F05-F7EBB182D3EA}')) {
- $process = Start-Process msiexec -ArgumentList @("/quiet", "/x", $product_code, "/norestart") -PassThru
-
- # Wait for process with timeout
- $completed = $process.WaitForExit($timeoutSeconds * 1000)
-
- if (-not $completed) {
- Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
- Exit 1603 # ERROR_UNINSTALL_FAILURE
+# Best-effort uninstall for GoToMeeting.
+#
+# The winget installer is the GoToMeeting "Setup" bootstrapper (ARPSYSTEMCOMPONENT=1,
+# so it hides itself from Programs and Features). It installs the actual GoToMeeting
+# app, which self-registers a separate, visible uninstall entry (DisplayName like
+# "GoToMeeting <version>"). We therefore can't uninstall via the bootstrapper's
+# UpgradeCode; instead we locate the app's own registry entry and run its
+# uninstaller. We search HKLM, the 32-bit hive, and HKCU because the app may be
+# registered per-machine or per-user.
+
+$softwareNameLike = "GoToMeeting*"
+
+$paths = @(
+ 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',
+ 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall',
+ 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'
+)
+
+$exitCode = 0
+
+try {
+
+[array]$uninstallKeys = Get-ChildItem `
+ -Path $paths `
+ -ErrorAction SilentlyContinue |
+ ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue }
+
+$selected = $null
+foreach ($key in $uninstallKeys) {
+ if ($key.DisplayName -and $key.DisplayName -like $softwareNameLike) {
+ $selected = $key
+ break
}
+}
+
+if (-not $selected) {
+ Write-Host "Uninstall entry not found for $softwareNameLike"
+ Exit 1
+}
+
+# Best-effort: stop running GoToMeeting processes so the uninstaller doesn't
+# fail on locked files.
+foreach ($proc in @("g2mstart", "g2mlauncher", "g2mcomm", "g2muicore", "GoToMeeting", "GoTo")) {
+ Stop-Process -Name $proc -Force -ErrorAction SilentlyContinue
+}
+
+# Prefer QuietUninstallString (it already includes the correct silent switches).
+$useQuiet = $false
+if ($selected.QuietUninstallString) {
+ $uninstallCommand = $selected.QuietUninstallString
+ $useQuiet = $true
+} elseif ($selected.UninstallString) {
+ $uninstallCommand = $selected.UninstallString
+} else {
+ Write-Host "Selected entry has no UninstallString: $($selected.DisplayName)"
+ Exit 1
+}
- # If the uninstall failed, bail
- if ($process.ExitCode -ne 0) {
- Write-Output "Uninstall for $($product_code) exited $($process.ExitCode)"
- Exit $process.ExitCode
+# Split the uninstall string into exe + args. Handle quoted paths, unquoted
+# paths that may contain spaces (capture through .exe), and a bare token.
+$exePath = ""
+$existingArgs = ""
+if ($uninstallCommand -match '^\s*"([^"]+)"\s*(.*)$') {
+ $exePath = $matches[1]
+ $existingArgs = $matches[2].Trim()
+} elseif ($uninstallCommand -match '(?i)^\s*(.+?\.exe)\s*(.*)$') {
+ $exePath = $matches[1]
+ $existingArgs = $matches[2].Trim()
+} elseif ($uninstallCommand -match '^\s*(\S+)\s*(.*)$') {
+ $exePath = $matches[1]
+ $existingArgs = $matches[2].Trim()
+} else {
+ Throw "Could not parse uninstall string: $uninstallCommand"
+}
+
+# If we fell back to UninstallString (no quiet variant), add a silent switch.
+if (-not $useQuiet) {
+ if ($exePath -match '(?i)msiexec') {
+ if ($existingArgs -notmatch '/quiet' -and $existingArgs -notmatch '/qn') {
+ $existingArgs = ("$existingArgs /quiet /norestart").Trim()
+ }
+ } elseif ($existingArgs -notmatch '/S\b' -and $existingArgs -notmatch '/silent' -and $existingArgs -notmatch '/quiet') {
+ # Custom uninstaller: GoTo's uninstaller honors /S for silent operation.
+ $existingArgs = ("$existingArgs /S").Trim()
}
}
-# All uninstalls succeeded; exit success
-Exit 0
+Write-Host "Selected entry DisplayName: $($selected.DisplayName)"
+Write-Host "Uninstall command: $exePath"
+Write-Host "Uninstall args: $existingArgs"
+
+$processOptions = @{
+ FilePath = $exePath
+ PassThru = $true
+ Wait = $true
+}
+
+if ($existingArgs -ne '') {
+ $processOptions.ArgumentList = $existingArgs
+}
+
+$process = Start-Process @processOptions
+$exitCode = $process.ExitCode
+Write-Host "Uninstall exit code: $exitCode"
+
+# Treat msiexec reboot-required success codes as success.
+if ($exitCode -eq 3010 -or $exitCode -eq 1641) {
+ Exit 0
+}
+
+Exit $exitCode
+
+} catch {
+ Write-Host "Error: $_"
+ Exit 1
+} |
Refactor the GoToMeeting uninstall PowerShell: stop additional g2mupdate process, simplify parsing to extract the uninstaller executable, and build vendor-documented silent args (/uninstall /ForAllUsers /silent) instead of relying on registry /S which G2MUninstall.exe ignores. Start-Process invocation was simplified to pass explicit ArgumentList; error messages and parsing failures were clarified. Also update outputs/windows.json to reference the new uninstall script id (uninstall_script_ref -> "cef7f8fa"). These changes make uninstalls more reliable and avoid hangs from incorrect silent switches.
Script Diff Resultsee/maintained-apps/outputs/gotomeeting/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/gotomeeting/windows.json=== Install Script (no changes) ===
=== Uninstall // 9ac6e58a -> cef7f8fa ===
--- /tmp/old.tec5xD 2026-05-27 17:50:50.023307213 +0000
+++ /tmp/new.eSOlxT 2026-05-27 17:50:50.023307213 +0000
@@ -3,10 +3,13 @@
# The winget installer is the GoToMeeting "Setup" bootstrapper (ARPSYSTEMCOMPONENT=1,
# so it hides itself from Programs and Features). It installs the actual GoToMeeting
# app, which self-registers a separate, visible uninstall entry (DisplayName like
-# "GoToMeeting <version>"). We therefore can't uninstall via the bootstrapper's
-# UpgradeCode; instead we locate the app's own registry entry and run its
-# uninstaller. We search HKLM, the 32-bit hive, and HKCU because the app may be
-# registered per-machine or per-user.
+# "GoToMeeting <version>") whose uninstaller is G2MUninstall.exe.
+#
+# We locate that entry and run G2MUninstall.exe directly. NOTE: the registry
+# QuietUninstallString uses "/S", which G2MUninstall.exe does not recognize as a
+# silent switch (it hangs waiting on UI). The vendor's documented silent switch
+# is "/silent" (see silentinstallhq.com), so we build the arguments ourselves
+# rather than trusting the registry string.
$softwareNameLike = "GoToMeeting*"
@@ -40,70 +43,48 @@
# Best-effort: stop running GoToMeeting processes so the uninstaller doesn't
# fail on locked files.
-foreach ($proc in @("g2mstart", "g2mlauncher", "g2mcomm", "g2muicore", "GoToMeeting", "GoTo")) {
+foreach ($proc in @("g2mstart", "g2mlauncher", "g2mcomm", "g2muicore", "g2mupdate", "GoToMeeting", "GoTo")) {
Stop-Process -Name $proc -Force -ErrorAction SilentlyContinue
}
-# Prefer QuietUninstallString (it already includes the correct silent switches).
-$useQuiet = $false
-if ($selected.QuietUninstallString) {
- $uninstallCommand = $selected.QuietUninstallString
- $useQuiet = $true
-} elseif ($selected.UninstallString) {
- $uninstallCommand = $selected.UninstallString
+# Extract just the uninstaller exe path from whichever registry string is
+# available; we supply the silent switches ourselves.
+$uninstallCommand = if ($selected.QuietUninstallString) {
+ $selected.QuietUninstallString
} else {
+ $selected.UninstallString
+}
+
+if (-not $uninstallCommand) {
Write-Host "Selected entry has no UninstallString: $($selected.DisplayName)"
Exit 1
}
-# Split the uninstall string into exe + args. Handle quoted paths, unquoted
-# paths that may contain spaces (capture through .exe), and a bare token.
$exePath = ""
-$existingArgs = ""
-if ($uninstallCommand -match '^\s*"([^"]+)"\s*(.*)$') {
- $exePath = $matches[1]
- $existingArgs = $matches[2].Trim()
-} elseif ($uninstallCommand -match '(?i)^\s*(.+?\.exe)\s*(.*)$') {
+if ($uninstallCommand -match '^\s*"([^"]+)"') {
+ # Quoted path
$exePath = $matches[1]
- $existingArgs = $matches[2].Trim()
-} elseif ($uninstallCommand -match '^\s*(\S+)\s*(.*)$') {
+} elseif ($uninstallCommand -match '(?i)^\s*(.+?\.exe)') {
+ # Unquoted path that may contain spaces (e.g. "C:\Program Files (x86)\...")
$exePath = $matches[1]
- $existingArgs = $matches[2].Trim()
} else {
- Throw "Could not parse uninstall string: $uninstallCommand"
+ Throw "Could not parse uninstaller path from: $uninstallCommand"
}
-# If we fell back to UninstallString (no quiet variant), add a silent switch.
-if (-not $useQuiet) {
- if ($exePath -match '(?i)msiexec') {
- if ($existingArgs -notmatch '/quiet' -and $existingArgs -notmatch '/qn') {
- $existingArgs = ("$existingArgs /quiet /norestart").Trim()
- }
- } elseif ($existingArgs -notmatch '/S\b' -and $existingArgs -notmatch '/silent' -and $existingArgs -notmatch '/quiet') {
- # Custom uninstaller: GoTo's uninstaller honors /S for silent operation.
- $existingArgs = ("$existingArgs /S").Trim()
- }
-}
+# Vendor-documented silent uninstall switches. /ForAllUsers matches the
+# machine-wide install (G2MINSTALLFORALLUSERS=1); /silent is the correct silent
+# switch (NOT /S, which G2MUninstall.exe ignores).
+$uninstallArgs = "/uninstall /ForAllUsers /silent"
Write-Host "Selected entry DisplayName: $($selected.DisplayName)"
Write-Host "Uninstall command: $exePath"
-Write-Host "Uninstall args: $existingArgs"
-
-$processOptions = @{
- FilePath = $exePath
- PassThru = $true
- Wait = $true
-}
-
-if ($existingArgs -ne '') {
- $processOptions.ArgumentList = $existingArgs
-}
+Write-Host "Uninstall args: $uninstallArgs"
-$process = Start-Process @processOptions
+$process = Start-Process -FilePath $exePath -ArgumentList $uninstallArgs -PassThru -Wait
$exitCode = $process.ExitCode
Write-Host "Uninstall exit code: $exitCode"
-# Treat msiexec reboot-required success codes as success.
+# Treat msiexec-style reboot-required success codes as success.
if ($exitCode -eq 3010 -or $exitCode -eq 1641) {
Exit 0
} |
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (9)
WalkthroughThis PR adds complete GoToMeeting managed software support for macOS and Windows. It defines platform-specific installer inputs (Homebrew for macOS, Winget for Windows), implements Windows MSI installation and registry-based uninstallation PowerShell scripts, generates platform output configurations with version metadata and detection queries, and integrates a GoToMeeting icon and registry entry into the frontend application interface. Possibly related PRs
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Introduce GoToMeeting to maintained apps: add homebrew and winget input manifests, darwin and windows output metadata (with installers, checksums, and install/uninstall script refs), and frontend icon asset.
Include Windows install/uninstall PowerShell scripts (MSI machine-wide install and uninstall via hard-coded UpgradeCode) and macOS DMG install/uninstall refs and scripts. Update ee/maintained-apps/outputs/apps.json to register GoToMeeting for darwin and windows.
Also adjust Windows validation logic to special-case GoToMeeting version checks: winget reports a package version (10.19.0.19950) that contains an extra ".0" segment compared to the installed MSI/registry version (10.19.19950), so the validator falls back to existence-only validation and logs the difference.
Summary by CodeRabbit
New Features