Add Windows instructions for FMAs (#34671)
Related: #34069 --------- Co-authored-by: George Karr <georgekarrv@users.noreply.github.com> Co-authored-by: Jonathan Katz <44128041+jkatz01@users.noreply.github.com>
This commit is contained in:
co-authored by
George Karr
Jonathan Katz
parent
d84e75d7ff
commit
ba4964d87c
@@ -5,7 +5,7 @@
|
||||
1. Create a new issue using the [New Fleet-maintained app](https://github.com/fleetdm/fleet/issues/new?template=fma-request.md) issue template
|
||||
2. Find the app's metadata in its [Homebrew formulae](https://formulae.brew.sh/)
|
||||
3. Create a new mainfiest file called `$YOUR_APP_NAME.json` in the `inputs/homebrew/` directory. For
|
||||
example, if you wanted to add Box Drive, create the file `inputs/homebrew/box-drive.json`.
|
||||
example, if you wanted to add Box Drive, create the file `inputs/homebrew/box-drive.json`.
|
||||
4. Fill out the file according to the [input schema below](#input-file-schema). For our example Box Drive app, it would look like this:
|
||||
|
||||
```json
|
||||
@@ -102,6 +102,138 @@ This is a filepath to an uninstall script. If provided, this script will be used
|
||||
|
||||
The script should be added to the `inputs/homebrew/scripts` directory.
|
||||
|
||||
## Adding a new app (Windows)
|
||||
|
||||
Use the Winget ingester. You will author:
|
||||
- An input JSON in `ee/maintained-apps/inputs/winget/`
|
||||
- Optional PowerShell scripts in `ee/maintained-apps/inputs/winget/scripts/`
|
||||
|
||||
### Can I do this on macOS?
|
||||
|
||||
The instructions below are meant to be run on a Windows host. But, you can run most of this on a macOS host, as well:
|
||||
- You can author Windows inputs and run the generator on macOS. The ingester is Go code that fetches data from winget/GitHub and works cross‑platform.
|
||||
- To find a Winget PackageIdentifier without a Windows host, browse the winget-pkgs repo: https://github.com/microsoft/winget-pkgs (search for your app’s manifests).
|
||||
- To find the PackageName and Publisher, you can look in the locale and installer yaml files in the winget-pkgs repo.
|
||||
- Validation and testing still require a Windows host (to verify programs.name and to run install/uninstall).
|
||||
|
||||
### Step 1: Find the Winget PackageIdentifier
|
||||
- On a Windows host, run: `winget search <app name>`
|
||||
- Note the `PackageIdentifier`. For example, Box Drive is typically `Box.Box`.
|
||||
|
||||
### Step 2: Find the unique identifier used by osquery
|
||||
The Windows ingester expects `unique_identifier` to match the value in `programs.name` on the host after install (this is what Fleet uses to confirm the app exists).
|
||||
- On a test Windows host, install the app manually, then check either:
|
||||
- Fleet live query: `SELECT name, version, publisher FROM programs WHERE name LIKE '%<App Name>%';`
|
||||
- PowerShell: `Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' | Where-Object {$_.DisplayName -like '*<App Name>*'} | Select-Object DisplayName, DisplayVersion, Publisher`
|
||||
- Use the exact `DisplayName`/`programs.name` string as `unique_identifier`.
|
||||
|
||||
### Step 3: Choose installer metadata
|
||||
If the winget manifest supports multiple installers, these fields select the right one:
|
||||
- `installer_arch`: `x64` or `x86` (most apps use `x64`)
|
||||
- `installer_type`: `exe`, `msi`, or `msix` (file type, not vendor tech like "wix")
|
||||
- `installer_scope`: `machine` or `user` (prefer `machine` for managed installs)
|
||||
- Optional: `installer_locale` if a specific locale is required
|
||||
- Optional: `program_publisher`, `uninstall_type`, `fuzzy_match_name` (rare)
|
||||
- `default_categories`: one or more of: `Browsers`, `Communication`, `Developer Tools`, `Productivity`
|
||||
|
||||
Tip: Setting these accurately avoids ambiguity when multiple installers exist.
|
||||
|
||||
### Step 4: Provide install/uninstall scripts
|
||||
|
||||
How scripts work:
|
||||
- MSI installers: The ingester automatically generates install and uninstall scripts. Do not add scripts unless you need to override the generated behavior.
|
||||
- EXE installers: You must provide PowerShell scripts that run the installer file directly. Fleet stores the installer and sends it to the host at install time; your script must execute it using the INSTALLER_PATH environment variable.
|
||||
|
||||
Place scripts in `ee/maintained-apps/inputs/winget/scripts/`.
|
||||
|
||||
Example install script `ee/maintained-apps/inputs/winget/scripts/box_drive_install.ps1`:
|
||||
```powershell
|
||||
# Install system-wide, silent
|
||||
# Learn more about .exe install scripts:
|
||||
# http://fleetdm.com/learn-more-about/exe-install-scripts
|
||||
|
||||
$exeFilePath = "${env:INSTALLER_PATH}"
|
||||
|
||||
try {
|
||||
# Silent arguments vary by installer (e.g., /S, /silent, /VERYSILENT)
|
||||
$processOptions = @{
|
||||
FilePath = "$exeFilePath"
|
||||
ArgumentList = "/VERYSILENT /NORESTART"
|
||||
PassThru = $true
|
||||
Wait = $true
|
||||
}
|
||||
|
||||
$process = Start-Process @processOptions
|
||||
$exitCode = $process.ExitCode
|
||||
|
||||
Write-Host "Install exit code: $exitCode"
|
||||
Exit $exitCode
|
||||
}
|
||||
catch {
|
||||
Write-Host "Error: $_"
|
||||
Exit 1
|
||||
}
|
||||
```
|
||||
|
||||
Uninstall scripts for EXE installers are vendor-specific. Use the vendor’s documented silent uninstall switch or the registered UninstallString (if available), ensuring the script runs silently and returns the installer’s exit code.
|
||||
|
||||
For MSI installers, you can omit scripts; for EXE installers, scripts are required.
|
||||
|
||||
### Step 5: Create the Winget input JSON
|
||||
Create `ee/maintained-apps/inputs/winget/box-drive.json`:
|
||||
```json
|
||||
{
|
||||
"name": "Box Drive",
|
||||
"slug": "box-drive/windows",
|
||||
"package_identifier": "Box.Box",
|
||||
"unique_identifier": "Box",
|
||||
"installer_arch": "x64",
|
||||
"installer_type": "msi",
|
||||
"installer_scope": "machine",
|
||||
"default_categories": ["Productivity"]
|
||||
}
|
||||
```
|
||||
Notes:
|
||||
- `slug` uses `<app-name>/windows` (lowercase, dash-separated name)
|
||||
- `unique_identifier` must match `programs.name` exactly
|
||||
|
||||
### Step 6: Generate outputs
|
||||
From the repo root:
|
||||
```bash
|
||||
go run cmd/maintained-apps/main.go --slug="box-drive/windows" --debug
|
||||
```
|
||||
This updates/creates:
|
||||
- `ee/maintained-apps/outputs/apps.json` (catalog entry)
|
||||
- `ee/maintained-apps/outputs/box-drive/windows.json` (manifest + script refs)
|
||||
|
||||
### Step 7: Add description
|
||||
Edit `ee/maintained-apps/outputs/apps.json` to add a human-friendly `description` for your app’s entry. For Windows entries, use the vendor description (from the winget manifest or vendor site).
|
||||
|
||||
### Step 8: Test in a Fleet instance
|
||||
- Set an override to point your Fleet instance at your branch’s catalog:
|
||||
```bash
|
||||
export FLEET_DEV_MAINTAINED_APPS_BASE_URL="https://raw.githubusercontent.com/<repository-name>/fleet/refs/heads/<PR-branch-name>/ee/maintained-apps/outputs"
|
||||
```
|
||||
- Trigger a refresh:
|
||||
```bash
|
||||
fleetctl trigger --name maintained_apps
|
||||
```
|
||||
- Add the app to a team, deploy to a Windows host, and verify:
|
||||
- Install completes
|
||||
- App launches
|
||||
- App uninstalls cleanly
|
||||
|
||||
### Step 9: Open the PR
|
||||
- Include “Fixes #<issue-number>” and any validation notes/screenshots
|
||||
- The software group will review, validate, and merge when ready
|
||||
|
||||
### Troubleshooting (Windows)
|
||||
- App not found in Fleet UI: ensure `apps.json` was updated by the generator and your override URL is correct
|
||||
- Install fails silently: confirm your `installer_type`, `installer_arch`, and `installer_scope` match the selected winget installer; run your PowerShell script manually on a test host
|
||||
- Uninstall doesn’t remove the app: prefer explicit uninstall scripts; otherwise, ensure the winget manifest exposes `ProductCode` or `UpgradeCode`
|
||||
- Hash mismatch errors: if the upstream manifest is in flux, you can set `ignore_hash: true` in the input JSON (use sparingly)
|
||||
|
||||
|
||||
### Validating Fleet-maintained apps additions
|
||||
|
||||
1. When a pull request (PR) is opened containing changes to `ee/maintained-apps/inputs/`, the [#g-software Product Designer (PD) and Engineering Manager (EM)](https://fleetdm.com/handbook/company/product-groups#software-group) are automatically added as reviewers.
|
||||
|
||||
Reference in New Issue
Block a user