Add Microsoft Office as a Fleet-maintained app for Windows#43938
Conversation
Exclude single-segment year folders in winget version detection to avoid legacy folders (e.g. "2010") outranking semver versions; add unit test to cover this behavior. Add Microsoft Office winget input (microsoft-office.json) and PowerShell install/uninstall scripts. Update apps.json to include a Microsoft Office entry and add ee/maintained-apps/outputs/microsoft-office/windows.json with a shipped version, installer URL, script refs, and embedded script contents so the app can be installed/uninstalled via the tooling.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #43938 +/- ##
==========================================
+ Coverage 66.96% 67.15% +0.19%
==========================================
Files 2851 2908 +57
Lines 225409 226115 +706
Branches 11547 11671 +124
==========================================
+ Hits 150934 151857 +923
+ Misses 60782 60534 -248
- Partials 13693 13724 +31
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
|
Go test failure seems unrelated to this PR. |
There was a problem hiding this comment.
Pull request overview
Adds Microsoft Office (Click-to-Run) as a Fleet-maintained app for Windows, including manifests/scripts for install & uninstall, plus ingestion/validation updates to handle Click-to-Run versioning and winget manifest quirks.
Changes:
- Added Microsoft Office maintained app metadata and generated output manifest (Windows).
- Added PowerShell install/uninstall scripts for Click-to-Run.
- Updated winget ingester version-dir filtering and Windows validator logic; added a frontend icon + icon map entry.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/pages/SoftwarePage/components/icons/MicrosoftOffice.tsx | Adds Microsoft Office icon asset component. |
| frontend/pages/SoftwarePage/components/icons/index.ts | Registers the Microsoft Office icon in the software icon map. |
| ee/maintained-apps/outputs/microsoft-office/windows.json | Adds generated Windows FMA manifest for Microsoft Office (queries, URL, scripts, hash). |
| ee/maintained-apps/outputs/apps.json | Adds Microsoft Office to the maintained apps catalog list. |
| ee/maintained-apps/inputs/winget/scripts/microsoft_office_uninstall.ps1 | Adds Click-to-Run uninstall script. |
| ee/maintained-apps/inputs/winget/scripts/microsoft_office_install.ps1 | Adds Click-to-Run install script. |
| ee/maintained-apps/inputs/winget/microsoft-office.json | Adds winget input manifest for generating the Office output manifest. |
| ee/maintained-apps/ingesters/winget/ingester.go | Updates version-folder filtering logic (skips legacy year dirs). |
| ee/maintained-apps/ingesters/winget/ingester_test.go | Adds unit test for excluding year-only folders. |
| cmd/maintained-apps/validate/windows.go | Exempts Office Click-to-Run from strict version checks during validation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughThis PR adds Microsoft Office Click-to-Run support: winget input JSON and PowerShell install/uninstall scripts, outputs including a 16.0.19929.20090 version entry with script refs and SQL queries, a frontend icon and icon-map entry, a Windows validation exemption treating detected "Microsoft 365"/"Microsoft Office" Click-to-Run installs as present despite version mismatches, and a winget ingester fix + test to ignore single-segment year-only directories when enumerating version manifests. Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
ee/maintained-apps/ingesters/winget/ingester_test.go (1)
40-51: ⚡ Quick winAdd a guard test for non-year single-segment versions.
This case validates year-folder exclusion, but it doesn’t protect against accidentally excluding legitimate single-segment versions (e.g.,
1). Adding that test will lock the intended behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ee/maintained-apps/ingesters/winget/ingester_test.go` around lines 40 - 51, Add a guard unit test in ingester_test.go that uses wingetVersionManifestDirs to ensure single-segment numeric folder names that are not years (e.g., "1") are not excluded; build an input slice (using dir("1"), dir("2010"), maybe a multi-segment like dir("16.0.1")) call wingetVersionManifestDirs(in) and assert that the result still contains the "1" entry while "2010" is excluded and multi-segment versions remain present, so the test protects the intended behavior of wingetVersionManifestDirs.ee/maintained-apps/inputs/winget/scripts/microsoft_office_uninstall.ps1 (1)
90-100: 💤 Low valueConsider handling the timeout case explicitly.
If the polling timeout is reached at line 94 (OfficeClickToRun processes still running after 30 minutes), the script continues to line 100 and exits with the original uninstaller exit code. This could mask scenarios where the uninstaller reported success but processes remain running.
Consider logging a warning or adjusting the exit code if the timeout is reached, so operators can detect incomplete cleanup.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ee/maintained-apps/inputs/winget/scripts/microsoft_office_uninstall.ps1` around lines 90 - 100, The loop polling OfficeClickToRun (using Get-Process -Name 'OfficeClickToRun') currently just proceeds to Exit $exitCode even if $elapsed reaches $timeout; update the logic to detect the timeout case after the while loop and explicitly handle it by emitting a warning (e.g. Write-Warning/Write-Host) that OfficeClickToRun processes remained after $timeout seconds and set a distinct non-zero exit code (or modify $exitCode) so callers can detect incomplete cleanup; reference the variables $timeout, $elapsed, the loop using OfficeClickToRun, and the final Exit $exitCode when adding this check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ee/maintained-apps/ingesters/winget/ingester.go`:
- Around line 127-129: The guard that currently drops any folder name without a
dot (the condition using strings.Contains(name, ".") in ingester.go) is too
broad; change it to only skip names that are legacy year-only folders (e.g.,
four-digit years). Replace the unconditional no-dot skip with a check that
detects a 4-digit numeric year (for example via regexp `^\d{4}$` or parse and
range-check an int) and continue only when that match is true, leaving other
single-segment versions like "1" or "2" to be processed.
In `@ee/maintained-apps/inputs/winget/scripts/microsoft_office_uninstall.ps1`:
- Around line 42-48: The termination list in $officeProcesses currently includes
'TEAMS' and 'ONEDRIVE' which are independent apps and should not be
unconditionally killed; either remove those entries from $officeProcesses or
change the Stop-Process logic to first Get-Process -Name $proc -ErrorAction
SilentlyContinue and inspect the process executable path (e.g., the Path
property) to ensure it belongs to the Office Click-to-Run/Office install
location (look for "Office", "ClickToRun" or your known install folder) before
calling Stop-Process -Force; update the code around $officeProcesses and the
Stop-Process loop to perform this conditional check.
In `@ee/maintained-apps/outputs/microsoft-office/windows.json`:
- Line 7: The patched SQL ("patched" field) is too broad because name LIKE
'Microsoft 365 %' can match unrelated products (e.g., Teams, OneDrive) and skew
version_compare results; update the EXISTS filter used in the patched expression
to target only the specific Office product(s) you intend to check (for example
by using the exact product names or a product identifier/sku column rather than
a broad LIKE), keep publisher = 'Microsoft Corporation', and retain the
version_compare(version, '16.0.19929.20090') < 0 logic so the patched value
still means “no matching Office product has a version less than the target.”
Ensure the same narrowed filter is applied wherever the name pattern is used so
the patched boolean remains correct.
- Line 12: The hardcoded "sha256" entry in windows.json is unreliable and must
be replaced with digital-signature-based verification: remove the sha256 field
and instead implement validation that downloaded setup.exe is from official
Microsoft domains and signed by "Microsoft Corporation" (Authenticode signature
check). Update the consumer code that reads this JSON (e.g., the installer
download/verify routine) to enforce a domain whitelist for the CDN host and to
perform Authenticode signature validation against the signer name "Microsoft
Corporation" (and fail if the signature is missing/invalid), and add a JSON flag
like "require_signature": true and "trusted_signer": "Microsoft Corporation" to
document the requirement.
In `@frontend/pages/SoftwarePage/components/icons/MicrosoftOffice.tsx`:
- Around line 6-10: The SVG in the MicrosoftOffice component lacks a viewBox
which causes the embedded 32×32 <image> to be clipped when consumers resize via
props; fix by adding a viewBox="0 0 32 32" attribute to the <svg> element in
MicrosoftOffice.tsx (the root <svg> in the MicrosoftOffice component) so the
icon scales correctly when width/height props change.
---
Nitpick comments:
In `@ee/maintained-apps/ingesters/winget/ingester_test.go`:
- Around line 40-51: Add a guard unit test in ingester_test.go that uses
wingetVersionManifestDirs to ensure single-segment numeric folder names that are
not years (e.g., "1") are not excluded; build an input slice (using dir("1"),
dir("2010"), maybe a multi-segment like dir("16.0.1")) call
wingetVersionManifestDirs(in) and assert that the result still contains the "1"
entry while "2010" is excluded and multi-segment versions remain present, so the
test protects the intended behavior of wingetVersionManifestDirs.
In `@ee/maintained-apps/inputs/winget/scripts/microsoft_office_uninstall.ps1`:
- Around line 90-100: The loop polling OfficeClickToRun (using Get-Process -Name
'OfficeClickToRun') currently just proceeds to Exit $exitCode even if $elapsed
reaches $timeout; update the logic to detect the timeout case after the while
loop and explicitly handle it by emitting a warning (e.g.
Write-Warning/Write-Host) that OfficeClickToRun processes remained after
$timeout seconds and set a distinct non-zero exit code (or modify $exitCode) so
callers can detect incomplete cleanup; reference the variables $timeout,
$elapsed, the loop using OfficeClickToRun, and the final Exit $exitCode when
adding this check.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 809ea6a3-ddd5-4525-8b9f-f01c91078e1c
⛔ Files ignored due to path filters (1)
website/assets/images/app-icon-microsoft-office-60x60@2x.pngis excluded by!**/*.png
📒 Files selected for processing (10)
cmd/maintained-apps/validate/windows.goee/maintained-apps/ingesters/winget/ingester.goee/maintained-apps/ingesters/winget/ingester_test.goee/maintained-apps/inputs/winget/microsoft-office.jsonee/maintained-apps/inputs/winget/scripts/microsoft_office_install.ps1ee/maintained-apps/inputs/winget/scripts/microsoft_office_uninstall.ps1ee/maintained-apps/outputs/apps.jsonee/maintained-apps/outputs/microsoft-office/windows.jsonfrontend/pages/SoftwarePage/components/icons/MicrosoftOffice.tsxfrontend/pages/SoftwarePage/components/icons/index.ts
Stop fetching the Office deployment configuration from aka.ms at install time and instead write a pinned configuration XML to disk (fleet-office-config.xml in $env:TEMP). The installer script now generates a deterministic config (silent Display Level=None, AcceptEULA=TRUE, RemoveMSI, conditional Visio/Project installs) and writes it as UTF-8 without BOM, then passes the local file to setup.exe via /configure. Also updated the package metadata (windows.json) to reference the new install script hash.
Script Diff Resultsee/maintained-apps/outputs/microsoft-office/windows.json=== Install // 533c456c -> 7e3fc6bb ===
--- /tmp/old.rAsNwg 2026-06-03 21:48:42.640963341 +0000
+++ /tmp/new.wfl9Ui 2026-06-03 21:48:42.640963341 +0000
@@ -1,11 +1,56 @@
# Microsoft Office (Click-to-Run) bootstrap installer.
-# setup.exe is a small (~7 MB) Office Deployment Tool bootstrap; it downloads
-# the configuration XML from the URL passed with /configure, then downloads
-# and installs the full Office product set defined in that configuration.
+# setup.exe is a small (~7 MB) Office Deployment Tool bootstrap. Rather than
+# fetching the configuration XML from a Microsoft-hosted URL at install time,
+# we write a pinned configuration to disk and point setup.exe at it with
+# /configure. This makes the install behavior fully determined by this script
+# and immune to changes in the remote config (e.g. Display Level flipping to
+# Full, or the product set changing) and to that URL being unreachable.
# http://fleetdm.com/learn-more-about/exe-install-scripts
$exeFilePath = "${env:INSTALLER_PATH}"
-$configUrl = "https://aka.ms/fhlwingetconfig"
+
+# Office Deployment Tool configuration. Equivalent to the config Microsoft
+# serves at https://aka.ms/fhlwingetconfig, pinned here for deterministic,
+# offline-safe installs.
+# Display Level="None" -> fully silent, no setup UI is shown.
+# AcceptEULA="TRUE" -> license terms are accepted automatically, so the
+# user is not prompted on first launch of an Office
+# app (required for a hands-off fleet deployment).
+# RemoveMSI -> removes any pre-existing MSI (volume/perpetual)
+# Office before installing Click-to-Run.
+# Visio/Project install only when a matching MSI product is already present
+# (MSICondition), so a clean machine receives Microsoft 365 Apps only.
+$configXml = @'
+<Configuration>
+ <Add>
+ <Product ID="O365ProPlusRetail">
+ <Language ID="MatchOS"/>
+ <Language ID="MatchPreviousMSI"/>
+ <ExcludeApp ID="Groove"/>
+ <ExcludeApp ID="Lync"/>
+ </Product>
+ <Product ID="VisioProRetail" MSICondition="VisPro,VisProR">
+ <Language ID="MatchOS"/>
+ <Language ID="MatchPreviousMSI"/>
+ <ExcludeApp ID="Groove"/>
+ <ExcludeApp ID="Lync"/>
+ </Product>
+ <Product ID="ProjectProRetail" MSICondition="PrjPro,PrjProR">
+ <Language ID="MatchOS"/>
+ <Language ID="MatchPreviousMSI"/>
+ <ExcludeApp ID="Groove"/>
+ <ExcludeApp ID="Lync"/>
+ </Product>
+ </Add>
+ <RemoveMSI/>
+ <Display Level="None" AcceptEULA="TRUE"/>
+</Configuration>
+'@
+
+# Write the configuration next to the installer. Use .NET WriteAllText so the
+# file is UTF-8 without a BOM, which the Office Deployment Tool parses cleanly.
+$configPath = Join-Path $env:TEMP "fleet-office-config.xml"
+[System.IO.File]::WriteAllText($configPath, $configXml, (New-Object System.Text.UTF8Encoding $false))
$exitCode = 0
@@ -15,13 +60,13 @@
# 15-60+ minutes depending on network speed and selected products.
$processOptions = @{
FilePath = "$exeFilePath"
- ArgumentList = "/configure `"$configUrl`""
+ ArgumentList = "/configure `"$configPath`""
PassThru = $true
Wait = $true
NoNewWindow = $true
}
- Write-Host "Starting Microsoft Office setup: $exeFilePath /configure $configUrl"
+ Write-Host "Starting Microsoft Office setup: $exeFilePath /configure $configPath"
$process = Start-Process @processOptions
$exitCode = $process.ExitCode
Write-Host "setup.exe exit code: $exitCode"
=== Uninstall Script (no changes) === |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ee/maintained-apps/outputs/microsoft-office/windows.json (1)
6-7:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAlign the
exists/patchedpredicates with the Office name handling used elsewhere.These queries only inventory
Microsoft 365 %, but both the registry matchers inee/maintained-apps/inputs/winget/scripts/microsoft_office_install.ps1and the validator special-case incmd/maintained-apps/validate/windows.go:138-151treatMicrosoft Office*as a valid Click-to-Run product too. If ARP reports a genuine Office install under aMicrosoft Office ...name, Fleet will install it successfully and still report the maintained app absent/unpatched.Proposed fix
- "exists": "SELECT 1 FROM programs WHERE name LIKE 'Microsoft 365 %' AND publisher = 'Microsoft Corporation';", - "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE name LIKE 'Microsoft 365 %' AND publisher = 'Microsoft Corporation' AND version_compare(version, '16.0.19929.20090') < 0);" + "exists": "SELECT 1 FROM programs WHERE publisher = 'Microsoft Corporation' AND (name LIKE 'Microsoft 365 %' OR name LIKE 'Microsoft Office %');", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE publisher = 'Microsoft Corporation' AND (name LIKE 'Microsoft 365 %' OR name LIKE 'Microsoft Office %') AND version_compare(version, '16.0.19929.20090') < 0);"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ee/maintained-apps/outputs/microsoft-office/windows.json` around lines 6 - 7, The SQL predicates under the "exists" and "patched" keys currently only match names like 'Microsoft 365 %' but must also accept 'Microsoft Office %' to align with the registry matcher and validator behavior (see microsoft_office_install.ps1 and the Windows validator special-case). Update the "exists" SQL to include OR name LIKE 'Microsoft Office %' and update the "patched" SQL to apply the same inclusion so ARP-reported installs named "Microsoft Office ..." are counted and version-compared the same way as "Microsoft 365 ...".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ee/maintained-apps/inputs/winget/scripts/microsoft_office_install.ps1`:
- Around line 50-53: The script currently calls
[System.IO.File]::WriteAllText($configPath, $configXml, (New-Object
System.Text.UTF8Encoding $false)) before entering the existing try/catch, so
failures creating $configPath produce raw PowerShell errors; move the config
file creation into the same try block that handles installation so any exception
from WriteAllText is caught and logged the same way (use the existing catch to
call the script's logging and exit 1 path), ensuring $configPath and $configXml
are defined before the move and no other code paths assume the file exists
before the try.
---
Outside diff comments:
In `@ee/maintained-apps/outputs/microsoft-office/windows.json`:
- Around line 6-7: The SQL predicates under the "exists" and "patched" keys
currently only match names like 'Microsoft 365 %' but must also accept
'Microsoft Office %' to align with the registry matcher and validator behavior
(see microsoft_office_install.ps1 and the Windows validator special-case).
Update the "exists" SQL to include OR name LIKE 'Microsoft Office %' and update
the "patched" SQL to apply the same inclusion so ARP-reported installs named
"Microsoft Office ..." are counted and version-compared the same way as
"Microsoft 365 ...".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 22bbe377-b438-4655-8c3d-e21c6e43c87a
📒 Files selected for processing (2)
ee/maintained-apps/inputs/winget/scripts/microsoft_office_install.ps1ee/maintained-apps/outputs/microsoft-office/windows.json
Script Diff Resultsee/maintained-apps/outputs/microsoft-office/windows.json=== Install // 533c456c -> 7e3fc6bb ===
--- /tmp/old.nZq5NZ 2026-06-04 14:51:12.013628246 +0000
+++ /tmp/new.xA6nSp 2026-06-04 14:51:12.013628246 +0000
@@ -1,11 +1,56 @@
# Microsoft Office (Click-to-Run) bootstrap installer.
-# setup.exe is a small (~7 MB) Office Deployment Tool bootstrap; it downloads
-# the configuration XML from the URL passed with /configure, then downloads
-# and installs the full Office product set defined in that configuration.
+# setup.exe is a small (~7 MB) Office Deployment Tool bootstrap. Rather than
+# fetching the configuration XML from a Microsoft-hosted URL at install time,
+# we write a pinned configuration to disk and point setup.exe at it with
+# /configure. This makes the install behavior fully determined by this script
+# and immune to changes in the remote config (e.g. Display Level flipping to
+# Full, or the product set changing) and to that URL being unreachable.
# http://fleetdm.com/learn-more-about/exe-install-scripts
$exeFilePath = "${env:INSTALLER_PATH}"
-$configUrl = "https://aka.ms/fhlwingetconfig"
+
+# Office Deployment Tool configuration. Equivalent to the config Microsoft
+# serves at https://aka.ms/fhlwingetconfig, pinned here for deterministic,
+# offline-safe installs.
+# Display Level="None" -> fully silent, no setup UI is shown.
+# AcceptEULA="TRUE" -> license terms are accepted automatically, so the
+# user is not prompted on first launch of an Office
+# app (required for a hands-off fleet deployment).
+# RemoveMSI -> removes any pre-existing MSI (volume/perpetual)
+# Office before installing Click-to-Run.
+# Visio/Project install only when a matching MSI product is already present
+# (MSICondition), so a clean machine receives Microsoft 365 Apps only.
+$configXml = @'
+<Configuration>
+ <Add>
+ <Product ID="O365ProPlusRetail">
+ <Language ID="MatchOS"/>
+ <Language ID="MatchPreviousMSI"/>
+ <ExcludeApp ID="Groove"/>
+ <ExcludeApp ID="Lync"/>
+ </Product>
+ <Product ID="VisioProRetail" MSICondition="VisPro,VisProR">
+ <Language ID="MatchOS"/>
+ <Language ID="MatchPreviousMSI"/>
+ <ExcludeApp ID="Groove"/>
+ <ExcludeApp ID="Lync"/>
+ </Product>
+ <Product ID="ProjectProRetail" MSICondition="PrjPro,PrjProR">
+ <Language ID="MatchOS"/>
+ <Language ID="MatchPreviousMSI"/>
+ <ExcludeApp ID="Groove"/>
+ <ExcludeApp ID="Lync"/>
+ </Product>
+ </Add>
+ <RemoveMSI/>
+ <Display Level="None" AcceptEULA="TRUE"/>
+</Configuration>
+'@
+
+# Write the configuration next to the installer. Use .NET WriteAllText so the
+# file is UTF-8 without a BOM, which the Office Deployment Tool parses cleanly.
+$configPath = Join-Path $env:TEMP "fleet-office-config.xml"
+[System.IO.File]::WriteAllText($configPath, $configXml, (New-Object System.Text.UTF8Encoding $false))
$exitCode = 0
@@ -15,13 +60,13 @@
# 15-60+ minutes depending on network speed and selected products.
$processOptions = @{
FilePath = "$exeFilePath"
- ArgumentList = "/configure `"$configUrl`""
+ ArgumentList = "/configure `"$configPath`""
PassThru = $true
Wait = $true
NoNewWindow = $true
}
- Write-Host "Starting Microsoft Office setup: $exeFilePath /configure $configUrl"
+ Write-Host "Starting Microsoft Office setup: $exeFilePath /configure $configPath"
$process = Start-Process @processOptions
$exitCode = $process.ExitCode
Write-Host "setup.exe exit code: $exitCode"
=== Uninstall Script (no changes) === |
Tighten detection and uninstall behavior for Microsoft Office (Click-to-Run). Change unique_identifier to "Microsoft 365 Apps" and update exists/patched osquery queries to match either "Microsoft 365 Apps %" or "Microsoft Office %" (avoids matching unrelated Office-branded packages or Store apps like "Microsoft 365 Copilot"). Update inputs to add an explicit exists_query and ignore_hash, and update outputs: set unique_identifier, adjust patched/exists queries, set uninstall script ref and mark sha256 as no_check. Modify the PowerShell uninstall script to limit which processes are force-stopped (exclude standalone apps like Teams and OneDrive) and add clarifying comments. Also refine validation logic in windows.go so only genuine Office suite names are exempt from strict version checks.
Script Diff Resultsee/maintained-apps/outputs/microsoft-office/windows.json=== Install Script (no changes) ===
=== Uninstall // 86950a4e -> 6e7a8864 ===
--- /tmp/old.oUlxWp 2026-06-08 15:35:40.827814199 +0000
+++ /tmp/new.2ST3pw 2026-06-08 15:35:40.828814194 +0000
@@ -38,10 +38,14 @@
Write-Host "Found: $($uninstall.DisplayName) ($($uninstall.DisplayVersion))"
Write-Host "Original UninstallString: $($uninstall.UninstallString)"
-# Close Office apps that could block the uninstaller.
+# Close Office suite apps that hold file locks and can block the uninstaller.
+# Deliberately limited to Click-to-Run suite components: standalone apps that
+# are commonly managed separately (new Teams, OneDrive) are NOT killed here, as
+# they aren't part of Microsoft 365 Apps and don't block OfficeClickToRun.exe —
+# force-stopping them would needlessly interrupt sync/calls.
$officeProcesses = @(
'WINWORD', 'EXCEL', 'POWERPNT', 'OUTLOOK', 'ONENOTE', 'MSACCESS',
- 'MSPUB', 'VISIO', 'WINPROJ', 'LYNC', 'TEAMS', 'ONEDRIVE'
+ 'MSPUB', 'VISIO', 'WINPROJ', 'LYNC'
)
foreach ($proc in $officeProcesses) {
Stop-Process -Name $proc -Force -ErrorAction SilentlyContinue |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmd/maintained-apps/validate/windows.go`:
- Around line 149-151: The current exemption for appName == "Microsoft Office"
is too broad because it only checks result.Name prefixes; update the condition
in the validation function to also verify the publisher field (e.g.,
result.Publisher or result.PublisherName) matches Microsoft’s publisher (use the
same canonical string used elsewhere in manifests, e.g., "Microsoft Corporation"
or the exact publisher constant) before allowing the HasPrefix checks for
"Microsoft 365 Apps" or "Microsoft Office" to bypass validation; keep the
existing name checks but add the publisher guard so only Microsoft-published
entries are exempt.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 70c4f5ab-875e-4373-b75c-8488f3d4392a
📒 Files selected for processing (5)
cmd/maintained-apps/validate/windows.goee/maintained-apps/inputs/winget/microsoft-office.jsonee/maintained-apps/inputs/winget/scripts/microsoft_office_uninstall.ps1ee/maintained-apps/outputs/apps.jsonee/maintained-apps/outputs/microsoft-office/windows.json
✅ Files skipped from review due to trivial changes (1)
- ee/maintained-apps/outputs/apps.json
🚧 Files skipped from review as they are similar to previous changes (1)
- ee/maintained-apps/inputs/winget/microsoft-office.json
Script Diff Resultsee/maintained-apps/outputs/microsoft-office/windows.json=== Install Script (no changes) ===
=== Uninstall // 86950a4e -> 6e7a8864 ===
--- /tmp/old.gWNWWh 2026-06-08 17:26:34.779886615 +0000
+++ /tmp/new.jHMTSG 2026-06-08 17:26:34.780886597 +0000
@@ -38,10 +38,14 @@
Write-Host "Found: $($uninstall.DisplayName) ($($uninstall.DisplayVersion))"
Write-Host "Original UninstallString: $($uninstall.UninstallString)"
-# Close Office apps that could block the uninstaller.
+# Close Office suite apps that hold file locks and can block the uninstaller.
+# Deliberately limited to Click-to-Run suite components: standalone apps that
+# are commonly managed separately (new Teams, OneDrive) are NOT killed here, as
+# they aren't part of Microsoft 365 Apps and don't block OfficeClickToRun.exe —
+# force-stopping them would needlessly interrupt sync/calls.
$officeProcesses = @(
'WINWORD', 'EXCEL', 'POWERPNT', 'OUTLOOK', 'ONENOTE', 'MSACCESS',
- 'MSPUB', 'VISIO', 'WINPROJ', 'LYNC', 'TEAMS', 'ONEDRIVE'
+ 'MSPUB', 'VISIO', 'WINPROJ', 'LYNC'
)
foreach ($proc in $officeProcesses) {
Stop-Process -Name $proc -Force -ErrorAction SilentlyContinue |
|
@allenhouchins Sorry didn't mean to click merge. |
|
@lukeheath no worries! Thank you! |
This pull request adds full support for managing Microsoft Office (Click-to-Run) as a maintained app on Windows. It introduces new input and output manifests, robust install and uninstall scripts, and logic updates to correctly identify and handle Office installations, including edge cases with legacy version folders and Click-to-Run's auto-update behavior.
Support for Microsoft Office on Windows:
apps.jsonand created a detailed output manifest (windows.json) specifying install/uninstall scripts, version detection queries, and metadata. [1] [2]microsoft_office_install.ps1) and uninstall (microsoft_office_uninstall.ps1) scripts tailored for Click-to-Run, including logic to handle registry detection, process cleanup, and silent operation. [1] [2]Detection and versioning improvements:
Summary by CodeRabbit