From 7ba5d4cfcc0cc17be8996bc4706d9fc499f044fe Mon Sep 17 00:00:00 2001 From: Allen Houchins <32207388+allenhouchins@users.noreply.github.com> Date: Mon, 13 Jul 2026 15:07:06 -0500 Subject: [PATCH] Add Windows FMAs (letter F): 5 apps (#49218) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Related issue:** N/A — part of the Windows Fleet-maintained apps catalog expansion (letter F batch; follows #48872, #48881, #48950, #48969, #49086, #49186). Adds eight new Windows Fleet-maintained apps: | App | winget package | Installer | Notes | |-----|----------------|-----------|-------| | Foxit PDF Editor | `Foxit.PhantomPDF` | WiX bootstrapper EXE, machine, x64 | Covers both "Foxit PDF Editor" and "…Pro" from the inventory (one package). Runs an updater service → process-stopping uninstall. ARP key lives in the WOW6432Node hive. | | Foxit PDF Reader | `Foxit.FoxitReader` | WiX bootstrapper EXE, machine, x64 | Distinct DisplayName from the Editor (verified via msiinfo). Updater service → process-stopping uninstall. | | FreeCAD | `FreeCAD.FreeCAD` | NSIS (MultiUser), machine, x64 | `/AllUsers /S`; versioned ARP name ("FreeCAD 1.1.1") → `FreeCAD%` fuzzy. | | FastPictureViewer Professional | `AxelRietschin.FastPictureViewer.Professional` | MSI, machine, x64 | Versioned ARP name → fuzzy. Unversioned URL → `ignore_hash`. Declares VCRedist deps (near-ubiquitous; noted). | | FastStone Capture | `FastStone.Capture` | NSIS, machine, x86 | `/S`; versioned ARP name → fuzzy. Paid trialware, but silent install/detect/uninstall are clean. | | FastStone Image Viewer | `FastStone.Viewer` | NSIS, machine, x86 | `/S`; versioned ARP name → fuzzy. | | FlexWhere for Desktop | `Dutchview.Flexwhere` | MSI, machine, x64 | Auto-start tray app → process-stopping uninstall (stop process, then msiexec /x via UpgradeCode). | | Fortify | `PeculiarVentures.Fortify` | WiX MSI, machine, x64 (en-US) | Smart-card/cert bridge; auto-start tray → process-stopping uninstall. Per-arch+locale ProductCode, so `installer_locale: en-US`. | Considered but **not** added (recorded in the workstream tracker): - **FactSet Workstation** (`FactSet.FactSetWorkstation`): MSI defaults to per-user (ALLUSERS=2 + MSIINSTALLPERUSER=1) with no machine-scope override, AND a `SpawnFDSWorkstation` custom action launches the app at install (headless-hang risk in a SYSTEM session). Niche licensed terminal. - **Filius** (`StefanFreischlad.Filius`): winget manifest is de-DE only (no en-US locale); the ingester hard-codes the en-US locale fetch (same limitation that deferred Araxis Merge). - **FlashFXP** (`OpenSight.FlashFXP`): abandoned (frozen at 2017), the vendor site returns HTTP 500, only a 16×16 icon is available, and its InstallAware uninstall needs a fragile cached-setup `/s` injection. - **Front** (`FrontApp.Front`): per-user-only electron-builder installer (`Front-user-*.exe` → `%LocalAppData%`, HKCU); no machine/all-users artifact in winget. - **Autodesk Fusion** (`Autodesk.Fusion`): the winget "installer" is `Fusion Client Downloader.exe`, a per-user streaming/web bootstrapper that downloads at runtime, hangs headless, and needs interactive Autodesk sign-in. Identities verified per app (msiinfo Property tables; NSIS header decompilation; winget AppsAndFeaturesEntries; uninstall-database corroboration). Apps that run a service or auto-start tray (both Foxit products, FlexWhere, Fortify) get process-stopping uninstalls up front to avoid the MSI-rollback failure class. SHAs verified against manifests for pinned URLs; `ignore_hash` only for FastPictureViewer's actively-maintained latest-pointer URL. Icons via `tools/software/icons/generate-icons.sh` (all ≥256px except FastPictureViewer/Fortify at 256/180). # Checklist for submitter - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters. - [x] Timeouts are implemented and retries are limited to avoid infinite loops ## Testing - [ ] QA'd all new/changed functionality manually (relying on the FMA CI validator for Windows install/uninstall validation) --- .../inputs/winget/flexwhere.json | 11 +++ ee/maintained-apps/inputs/winget/fortify.json | 12 ++++ .../inputs/winget/foxit-pdf-editor.json | 12 ++++ .../inputs/winget/foxit-pdf-reader.json | 12 ++++ ee/maintained-apps/inputs/winget/freecad.json | 13 ++++ .../winget/scripts/flexwhere_uninstall.ps1 | 53 +++++++++++++++ .../winget/scripts/fortify_uninstall.ps1 | 53 +++++++++++++++ .../scripts/foxit-pdf-editor_install.ps1 | 34 ++++++++++ .../scripts/foxit-pdf-editor_uninstall.ps1 | 64 ++++++++++++++++++ .../scripts/foxit-pdf-reader_install.ps1 | 34 ++++++++++ .../scripts/foxit-pdf-reader_uninstall.ps1 | 64 ++++++++++++++++++ .../inputs/winget/scripts/freecad_install.ps1 | 27 ++++++++ .../winget/scripts/freecad_uninstall.ps1 | 57 ++++++++++++++++ ee/maintained-apps/outputs/apps.json | 35 ++++++++++ .../outputs/flexwhere/windows.json | 23 +++++++ .../outputs/fortify/windows.json | 23 +++++++ .../outputs/foxit-pdf-editor/windows.json | 22 ++++++ .../outputs/foxit-pdf-reader/windows.json | 22 ++++++ .../outputs/freecad/windows.json | 22 ++++++ .../components/icons/Flexwhere.tsx | 14 ++++ .../SoftwarePage/components/icons/Fortify.tsx | 14 ++++ .../components/icons/FoxitPdfEditor.tsx | 14 ++++ .../components/icons/FoxitPdfReader.tsx | 14 ++++ .../SoftwarePage/components/icons/Freecad.tsx | 14 ++++ .../SoftwarePage/components/icons/index.ts | 10 +++ .../images/app-icon-flexwhere-60x60@2x.png | Bin 0 -> 12448 bytes .../images/app-icon-fortify-60x60@2x.png | Bin 0 -> 12949 bytes .../app-icon-foxit-pdf-editor-60x60@2x.png | Bin 0 -> 7260 bytes .../app-icon-foxit-pdf-reader-60x60@2x.png | Bin 0 -> 8124 bytes .../images/app-icon-freecad-60x60@2x.png | Bin 0 -> 3510 bytes 30 files changed, 673 insertions(+) create mode 100644 ee/maintained-apps/inputs/winget/flexwhere.json create mode 100644 ee/maintained-apps/inputs/winget/fortify.json create mode 100644 ee/maintained-apps/inputs/winget/foxit-pdf-editor.json create mode 100644 ee/maintained-apps/inputs/winget/foxit-pdf-reader.json create mode 100644 ee/maintained-apps/inputs/winget/freecad.json create mode 100644 ee/maintained-apps/inputs/winget/scripts/flexwhere_uninstall.ps1 create mode 100644 ee/maintained-apps/inputs/winget/scripts/fortify_uninstall.ps1 create mode 100644 ee/maintained-apps/inputs/winget/scripts/foxit-pdf-editor_install.ps1 create mode 100644 ee/maintained-apps/inputs/winget/scripts/foxit-pdf-editor_uninstall.ps1 create mode 100644 ee/maintained-apps/inputs/winget/scripts/foxit-pdf-reader_install.ps1 create mode 100644 ee/maintained-apps/inputs/winget/scripts/foxit-pdf-reader_uninstall.ps1 create mode 100644 ee/maintained-apps/inputs/winget/scripts/freecad_install.ps1 create mode 100644 ee/maintained-apps/inputs/winget/scripts/freecad_uninstall.ps1 create mode 100644 ee/maintained-apps/outputs/flexwhere/windows.json create mode 100644 ee/maintained-apps/outputs/fortify/windows.json create mode 100644 ee/maintained-apps/outputs/foxit-pdf-editor/windows.json create mode 100644 ee/maintained-apps/outputs/foxit-pdf-reader/windows.json create mode 100644 ee/maintained-apps/outputs/freecad/windows.json create mode 100644 frontend/pages/SoftwarePage/components/icons/Flexwhere.tsx create mode 100644 frontend/pages/SoftwarePage/components/icons/Fortify.tsx create mode 100644 frontend/pages/SoftwarePage/components/icons/FoxitPdfEditor.tsx create mode 100644 frontend/pages/SoftwarePage/components/icons/FoxitPdfReader.tsx create mode 100644 frontend/pages/SoftwarePage/components/icons/Freecad.tsx create mode 100644 website/assets/images/app-icon-flexwhere-60x60@2x.png create mode 100644 website/assets/images/app-icon-fortify-60x60@2x.png create mode 100644 website/assets/images/app-icon-foxit-pdf-editor-60x60@2x.png create mode 100644 website/assets/images/app-icon-foxit-pdf-reader-60x60@2x.png create mode 100644 website/assets/images/app-icon-freecad-60x60@2x.png diff --git a/ee/maintained-apps/inputs/winget/flexwhere.json b/ee/maintained-apps/inputs/winget/flexwhere.json new file mode 100644 index 0000000000..77a272f0ae --- /dev/null +++ b/ee/maintained-apps/inputs/winget/flexwhere.json @@ -0,0 +1,11 @@ +{ + "name": "FlexWhere for Desktop", + "slug": "flexwhere/windows", + "package_identifier": "Dutchview.Flexwhere", + "unique_identifier": "Flexwhere for Desktop", + "installer_arch": "x64", + "installer_type": "msi", + "installer_scope": "machine", + "uninstall_script_path": "ee/maintained-apps/inputs/winget/scripts/flexwhere_uninstall.ps1", + "default_categories": ["Productivity"] +} diff --git a/ee/maintained-apps/inputs/winget/fortify.json b/ee/maintained-apps/inputs/winget/fortify.json new file mode 100644 index 0000000000..591b3f8267 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/fortify.json @@ -0,0 +1,12 @@ +{ + "name": "Fortify", + "slug": "fortify/windows", + "package_identifier": "PeculiarVentures.Fortify", + "unique_identifier": "Fortify", + "installer_arch": "x64", + "installer_type": "msi", + "installer_scope": "machine", + "installer_locale": "en-US", + "uninstall_script_path": "ee/maintained-apps/inputs/winget/scripts/fortify_uninstall.ps1", + "default_categories": ["Security"] +} diff --git a/ee/maintained-apps/inputs/winget/foxit-pdf-editor.json b/ee/maintained-apps/inputs/winget/foxit-pdf-editor.json new file mode 100644 index 0000000000..1cb349a35f --- /dev/null +++ b/ee/maintained-apps/inputs/winget/foxit-pdf-editor.json @@ -0,0 +1,12 @@ +{ + "name": "Foxit PDF Editor", + "slug": "foxit-pdf-editor/windows", + "package_identifier": "Foxit.PhantomPDF", + "unique_identifier": "Foxit PDF Editor", + "installer_arch": "x64", + "installer_type": "exe", + "installer_scope": "machine", + "install_script_path": "ee/maintained-apps/inputs/winget/scripts/foxit-pdf-editor_install.ps1", + "uninstall_script_path": "ee/maintained-apps/inputs/winget/scripts/foxit-pdf-editor_uninstall.ps1", + "default_categories": ["Productivity"] +} diff --git a/ee/maintained-apps/inputs/winget/foxit-pdf-reader.json b/ee/maintained-apps/inputs/winget/foxit-pdf-reader.json new file mode 100644 index 0000000000..73da4fe144 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/foxit-pdf-reader.json @@ -0,0 +1,12 @@ +{ + "name": "Foxit PDF Reader", + "slug": "foxit-pdf-reader/windows", + "package_identifier": "Foxit.FoxitReader", + "unique_identifier": "Foxit PDF Reader", + "installer_arch": "x64", + "installer_type": "exe", + "installer_scope": "machine", + "install_script_path": "ee/maintained-apps/inputs/winget/scripts/foxit-pdf-reader_install.ps1", + "uninstall_script_path": "ee/maintained-apps/inputs/winget/scripts/foxit-pdf-reader_uninstall.ps1", + "default_categories": ["Productivity"] +} diff --git a/ee/maintained-apps/inputs/winget/freecad.json b/ee/maintained-apps/inputs/winget/freecad.json new file mode 100644 index 0000000000..945aaeeb44 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/freecad.json @@ -0,0 +1,13 @@ +{ + "name": "FreeCAD", + "slug": "freecad/windows", + "package_identifier": "FreeCAD.FreeCAD", + "unique_identifier": "FreeCAD", + "fuzzy_match_name": "FreeCAD%", + "installer_arch": "x64", + "installer_type": "exe", + "installer_scope": "machine", + "install_script_path": "ee/maintained-apps/inputs/winget/scripts/freecad_install.ps1", + "uninstall_script_path": "ee/maintained-apps/inputs/winget/scripts/freecad_uninstall.ps1", + "default_categories": ["Productivity"] +} diff --git a/ee/maintained-apps/inputs/winget/scripts/flexwhere_uninstall.ps1 b/ee/maintained-apps/inputs/winget/scripts/flexwhere_uninstall.ps1 new file mode 100644 index 0000000000..5d16402e37 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/flexwhere_uninstall.ps1 @@ -0,0 +1,53 @@ +# Uninstalls Flexwhere for Desktop. +# +# Flexwhere for Desktop auto-starts a tray process (no Windows service), which can hold files +# and make msiexec roll back the uninstall. Stop anything running from the +# install dir (plus known process names) FIRST, then resolve the ProductCode(s) +# via the stable UpgradeCode and msiexec /x each. + +$upgradeCode = '{5916547D-CBFA-451B-AF68-D475E2DA9022}' +$softwareName = 'Flexwhere for Desktop' +$successCodes = @(0, 3010, 1641) + +$machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' +$machineKey32on64 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' + +try { + +# Stop the app's processes so the MSI uninstall isn't rolled back by locked files. +$entry = Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue | + ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } | + Where-Object { $_.DisplayName -eq $softwareName } | Select-Object -First 1 +if ($entry -and $entry.InstallLocation -and (Test-Path -LiteralPath $entry.InstallLocation)) { + $loc = $entry.InstallLocation.TrimEnd('\') + Get-Process | Where-Object { $_.Path -and $_.Path -like "$loc\*" } | + ForEach-Object { Stop-Process -Id $_.Id -Force -ErrorAction SilentlyContinue } +} +foreach ($p in @("Flexwhere for Desktop")) { + Stop-Process -Name $p -Force -ErrorAction SilentlyContinue +} +Start-Sleep -Seconds 3 + +# Resolve ProductCode(s) from the stable UpgradeCode and uninstall each. +$inst = New-Object -ComObject "WindowsInstaller.Installer" +$productCodes = @($inst.RelatedProducts($upgradeCode)) +if ($productCodes.Count -eq 0) { + Write-Host "No products found for upgrade code $upgradeCode" + Exit 1 +} + +foreach ($productCode in $productCodes) { + Write-Host "Uninstalling product code: $productCode" + $process = Start-Process msiexec.exe ` + -ArgumentList "/x $productCode /quiet /norestart" ` + -NoNewWindow -PassThru -Wait + Write-Host "Uninstall exit code: $($process.ExitCode)" + if ($successCodes -notcontains $process.ExitCode) { Exit $process.ExitCode } +} + +Exit 0 + +} catch { + Write-Host "Error: $_" + Exit 1 +} diff --git a/ee/maintained-apps/inputs/winget/scripts/fortify_uninstall.ps1 b/ee/maintained-apps/inputs/winget/scripts/fortify_uninstall.ps1 new file mode 100644 index 0000000000..a89d08f929 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/fortify_uninstall.ps1 @@ -0,0 +1,53 @@ +# Uninstalls Fortify. +# +# Fortify auto-starts a tray process (no Windows service), which can hold files +# and make msiexec roll back the uninstall. Stop anything running from the +# install dir (plus known process names) FIRST, then resolve the ProductCode(s) +# via the stable UpgradeCode and msiexec /x each. + +$upgradeCode = '{AB87B5E7-17F6-5394-8A15-9EE6AA6B06B8}' +$softwareName = 'Fortify' +$successCodes = @(0, 3010, 1641) + +$machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' +$machineKey32on64 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' + +try { + +# Stop the app's processes so the MSI uninstall isn't rolled back by locked files. +$entry = Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue | + ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } | + Where-Object { $_.DisplayName -eq $softwareName } | Select-Object -First 1 +if ($entry -and $entry.InstallLocation -and (Test-Path -LiteralPath $entry.InstallLocation)) { + $loc = $entry.InstallLocation.TrimEnd('\') + Get-Process | Where-Object { $_.Path -and $_.Path -like "$loc\*" } | + ForEach-Object { Stop-Process -Id $_.Id -Force -ErrorAction SilentlyContinue } +} +foreach ($p in @("Fortify")) { + Stop-Process -Name $p -Force -ErrorAction SilentlyContinue +} +Start-Sleep -Seconds 3 + +# Resolve ProductCode(s) from the stable UpgradeCode and uninstall each. +$inst = New-Object -ComObject "WindowsInstaller.Installer" +$productCodes = @($inst.RelatedProducts($upgradeCode)) +if ($productCodes.Count -eq 0) { + Write-Host "No products found for upgrade code $upgradeCode" + Exit 1 +} + +foreach ($productCode in $productCodes) { + Write-Host "Uninstalling product code: $productCode" + $process = Start-Process msiexec.exe ` + -ArgumentList "/x $productCode /quiet /norestart" ` + -NoNewWindow -PassThru -Wait + Write-Host "Uninstall exit code: $($process.ExitCode)" + if ($successCodes -notcontains $process.ExitCode) { Exit $process.ExitCode } +} + +Exit 0 + +} catch { + Write-Host "Error: $_" + Exit 1 +} diff --git a/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-editor_install.ps1 b/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-editor_install.ps1 new file mode 100644 index 0000000000..6e3bd052aa --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-editor_install.ps1 @@ -0,0 +1,34 @@ +# Learn more about .exe install scripts: +# http://fleetdm.com/learn-more-about/exe-install-scripts +# +# Foxit PDF Editor ships as a Foxit WiX MultiLangBootstrapper EXE. /quiet /norestart +# performs a silent per-machine install. + +$exeFilePath = "${env:INSTALLER_PATH}" + +try { + if (-not (Test-Path $exeFilePath)) { + Write-Host "Error: Installer file not found at: $exeFilePath" + Exit 1 + } + + $processOptions = @{ + FilePath = "$exeFilePath" + ArgumentList = "/quiet" + PassThru = $true + Wait = $true + NoNewWindow = $true + } + + $process = Start-Process @processOptions + $exitCode = $process.ExitCode + Write-Host "Install exit code: $exitCode" + + # 0 = success, 3010 = success but reboot required, 1641 = reboot initiated + if ($exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 } + Exit $exitCode + +} catch { + Write-Host "Error: $_" + Exit 1 +} diff --git a/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-editor_uninstall.ps1 b/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-editor_uninstall.ps1 new file mode 100644 index 0000000000..82253470c6 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-editor_uninstall.ps1 @@ -0,0 +1,64 @@ +# Uninstalls Foxit PDF Editor. +# +# Foxit PDF Editor is a Foxit WiX MultiLangBootstrapper install that runs an auto-updater +# service; its visible ARP entry is the inner MSI (its UninstallString uses +# "MsiExec.exe /I{ProductCode}", the maintenance/repair form). We stop the +# Foxit services/processes first so files aren't locked, then resolve the +# ProductCode GUID and run a clean "msiexec /x {ProductCode} /qn /norestart" +# (never reuse the /I from the registry string). The ARP entry lives in the +# WOW6432Node (32-bit) hive even on x64. + +$softwareName = "Foxit PDF Editor" + +$machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' +$machineKey32on64 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' +$successCodes = @(0, 3010, 1641) +$exitCode = $null + +try { + +foreach ($svc in @("FoxitPhantomPDFUpdateService")) { + Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue +} +foreach ($p in @("FoxitPDFEditor", "FoxitPhantomPDF", "FoxitUpdater")) { + Stop-Process -Name $p -Force -ErrorAction SilentlyContinue +} +Start-Sleep -Seconds 3 + +[array]$uninstallKeys = Get-ChildItem ` + -Path @($machineKey, $machineKey32on64) ` + -ErrorAction SilentlyContinue | + ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } + +$selected = $uninstallKeys | Where-Object { $_.DisplayName -eq $softwareName } | Select-Object -First 1 +if (-not $selected) { + Write-Host "Uninstall entry not found for '$softwareName'." + Exit 1 +} + +# ProductCode: prefer the ARP key name (it is the MSI ProductCode), else pull +# the first GUID out of the UninstallString. Never carry over its /I switch. +$productCode = $selected.PSChildName +if ($productCode -notmatch '^\{[0-9A-Fa-f-]+\}$') { + $raw = $selected.UninstallString + if ($raw -match '(\{[0-9A-Fa-f-]+\})') { $productCode = $matches[1] } +} +if ($productCode -notmatch '^\{[0-9A-Fa-f-]+\}$') { + Write-Host "Could not determine ProductCode for '$softwareName'." + Exit 1 +} + +Write-Host "Uninstalling product code: $productCode" +$process = Start-Process msiexec.exe ` + -ArgumentList "/x $productCode /qn /norestart" ` + -NoNewWindow -PassThru -Wait +$exitCode = $process.ExitCode +Write-Host "Uninstall exit code: $exitCode" + +} catch { + Write-Host "Error: $_" + Exit 1 +} + +if ($successCodes -contains $exitCode) { Exit 0 } +Exit $exitCode diff --git a/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-reader_install.ps1 b/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-reader_install.ps1 new file mode 100644 index 0000000000..5f682f9ba1 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-reader_install.ps1 @@ -0,0 +1,34 @@ +# Learn more about .exe install scripts: +# http://fleetdm.com/learn-more-about/exe-install-scripts +# +# Foxit PDF Reader ships as a Foxit WiX MultiLangBootstrapper EXE. /quiet /norestart +# performs a silent per-machine install. + +$exeFilePath = "${env:INSTALLER_PATH}" + +try { + if (-not (Test-Path $exeFilePath)) { + Write-Host "Error: Installer file not found at: $exeFilePath" + Exit 1 + } + + $processOptions = @{ + FilePath = "$exeFilePath" + ArgumentList = "/quiet" + PassThru = $true + Wait = $true + NoNewWindow = $true + } + + $process = Start-Process @processOptions + $exitCode = $process.ExitCode + Write-Host "Install exit code: $exitCode" + + # 0 = success, 3010 = success but reboot required, 1641 = reboot initiated + if ($exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 } + Exit $exitCode + +} catch { + Write-Host "Error: $_" + Exit 1 +} diff --git a/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-reader_uninstall.ps1 b/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-reader_uninstall.ps1 new file mode 100644 index 0000000000..a5582af442 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/foxit-pdf-reader_uninstall.ps1 @@ -0,0 +1,64 @@ +# Uninstalls Foxit PDF Reader. +# +# Foxit PDF Reader is a Foxit WiX MultiLangBootstrapper install that runs an auto-updater +# service; its visible ARP entry is the inner MSI (its UninstallString uses +# "MsiExec.exe /I{ProductCode}", the maintenance/repair form). We stop the +# Foxit services/processes first so files aren't locked, then resolve the +# ProductCode GUID and run a clean "msiexec /x {ProductCode} /qn /norestart" +# (never reuse the /I from the registry string). The ARP entry lives in the +# WOW6432Node (32-bit) hive even on x64. + +$softwareName = "Foxit PDF Reader" + +$machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' +$machineKey32on64 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' +$successCodes = @(0, 3010, 1641) +$exitCode = $null + +try { + +foreach ($svc in @("FoxitPDFReaderUpdateService")) { + Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue +} +foreach ($p in @("FoxitPDFReader", "FoxitReader", "FoxitUpdater")) { + Stop-Process -Name $p -Force -ErrorAction SilentlyContinue +} +Start-Sleep -Seconds 3 + +[array]$uninstallKeys = Get-ChildItem ` + -Path @($machineKey, $machineKey32on64) ` + -ErrorAction SilentlyContinue | + ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } + +$selected = $uninstallKeys | Where-Object { $_.DisplayName -eq $softwareName } | Select-Object -First 1 +if (-not $selected) { + Write-Host "Uninstall entry not found for '$softwareName'." + Exit 1 +} + +# ProductCode: prefer the ARP key name (it is the MSI ProductCode), else pull +# the first GUID out of the UninstallString. Never carry over its /I switch. +$productCode = $selected.PSChildName +if ($productCode -notmatch '^\{[0-9A-Fa-f-]+\}$') { + $raw = $selected.UninstallString + if ($raw -match '(\{[0-9A-Fa-f-]+\})') { $productCode = $matches[1] } +} +if ($productCode -notmatch '^\{[0-9A-Fa-f-]+\}$') { + Write-Host "Could not determine ProductCode for '$softwareName'." + Exit 1 +} + +Write-Host "Uninstalling product code: $productCode" +$process = Start-Process msiexec.exe ` + -ArgumentList "/x $productCode /qn /norestart" ` + -NoNewWindow -PassThru -Wait +$exitCode = $process.ExitCode +Write-Host "Uninstall exit code: $exitCode" + +} catch { + Write-Host "Error: $_" + Exit 1 +} + +if ($successCodes -contains $exitCode) { Exit 0 } +Exit $exitCode diff --git a/ee/maintained-apps/inputs/winget/scripts/freecad_install.ps1 b/ee/maintained-apps/inputs/winget/scripts/freecad_install.ps1 new file mode 100644 index 0000000000..a461c18b0d --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/freecad_install.ps1 @@ -0,0 +1,27 @@ +# Learn more about .exe install scripts: +# http://fleetdm.com/learn-more-about/exe-install-scripts +# +# FreeCAD ships as a MultiUser NSIS installer. /S runs it silently and +# /AllUsers forces the machine-wide install (HKLM + C:\Program Files). + +$exeFilePath = "${env:INSTALLER_PATH}" + +try { + +$processOptions = @{ + FilePath = "$exeFilePath" + ArgumentList = "/AllUsers /S" + 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 +} diff --git a/ee/maintained-apps/inputs/winget/scripts/freecad_uninstall.ps1 b/ee/maintained-apps/inputs/winget/scripts/freecad_uninstall.ps1 new file mode 100644 index 0000000000..bea7e1fdd5 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/freecad_uninstall.ps1 @@ -0,0 +1,57 @@ +# Uninstalls FreeCAD. +# +# FreeCAD (MultiUser NSIS) registers a versioned DisplayName ("FreeCAD 1.1.1") +# under HKLM when installed with /AllUsers, so match on the "FreeCAD" prefix. +# Its QuietUninstallString runs "Uninstall-FreeCAD.exe" /S (real silent, no +# service to block removal). + +$softwareNameLike = "FreeCAD*" +$publisherLike = "FreeCAD*" + +$machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' +$machineKey32on64 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' + +$exitCode = $null + +try { + +[array]$uninstallKeys = Get-ChildItem ` + -Path @($machineKey, $machineKey32on64) ` + -ErrorAction SilentlyContinue | + ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } + +$selected = $uninstallKeys | + Where-Object { $_.DisplayName -like $softwareNameLike -and $_.Publisher -like $publisherLike } | + Select-Object -First 1 +if (-not $selected -or -not $selected.UninstallString) { + Write-Host "Uninstall entry not found for $softwareNameLike" + Exit 1 +} + +$raw = if ($selected.QuietUninstallString) { $selected.QuietUninstallString } else { $selected.UninstallString } + +# Parse exe + args (quoted / unquoted / bare). +if ($raw -match '^\s*"([^"]+)"\s*(.*)$') { + $exe = $matches[1]; $exeArgs = $matches[2].Trim() +} elseif ($raw -match '(?i)^\s*(.+?\.exe)\s*(.*)$') { + $exe = $matches[1]; $exeArgs = $matches[2].Trim() +} else { + $exe = $raw; $exeArgs = "" +} + +# NSIS uninstallers require /S for a silent uninstall. +if ($exeArgs -notmatch '(?i)(^|\s)/S(\s|$)') { $exeArgs = "$exeArgs /S".Trim() } + +Write-Host "Uninstall command: $exe" +Write-Host "Uninstall args: $exeArgs" +$process = Start-Process -FilePath $exe -ArgumentList $exeArgs -PassThru -Wait +$exitCode = $process.ExitCode +Write-Host "Uninstall exit code: $exitCode" + +} catch { + Write-Host "Error: $_" + Exit 1 +} + +if ($exitCode -eq 0 -or $exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 } +Exit $exitCode diff --git a/ee/maintained-apps/outputs/apps.json b/ee/maintained-apps/outputs/apps.json index f56dbfd42c..7b0cb82098 100644 --- a/ee/maintained-apps/outputs/apps.json +++ b/ee/maintained-apps/outputs/apps.json @@ -3312,6 +3312,13 @@ "unique_identifier": "net.flexoptix.flexoptix.app", "description": "FLEXOPTIX App is a connect to your FLEXBOX without cables and configure transceivers." }, + { + "name": "FlexWhere for Desktop", + "slug": "flexwhere/windows", + "platform": "windows", + "unique_identifier": "Flexwhere for Desktop", + "description": "FlexWhere for Desktop shows real-time workplace and colleague availability from FlexWhere." + }, { "name": "Fluid", "slug": "fluid/darwin", @@ -3382,6 +3389,27 @@ "unique_identifier": "com.binarynights.ForkLift-4", "description": "ForkLift is a finder replacement and FTP, SFTP, WebDAV and Amazon s3 client." }, + { + "name": "Fortify", + "slug": "fortify/windows", + "platform": "windows", + "unique_identifier": "Fortify", + "description": "Fortify enables cross-browser use of local certificates and smart cards." + }, + { + "name": "Foxit PDF Editor", + "slug": "foxit-pdf-editor/windows", + "platform": "windows", + "unique_identifier": "Foxit PDF Editor", + "description": "Foxit PDF Editor is a desktop application for creating and editing PDF documents." + }, + { + "name": "Foxit PDF Reader", + "slug": "foxit-pdf-reader/windows", + "platform": "windows", + "unique_identifier": "Foxit PDF Reader", + "description": "Foxit PDF Reader is a desktop application for viewing and annotating PDF documents." + }, { "name": "Framer", "slug": "framer/darwin", @@ -3410,6 +3438,13 @@ "unique_identifier": "org.freedownloadmanager.fdm6", "description": "Free Download Manager is a download accelerator and organizer." }, + { + "name": "FreeCAD", + "slug": "freecad/windows", + "platform": "windows", + "unique_identifier": "FreeCAD", + "description": "FreeCAD is a general-purpose, open-source parametric 3D CAD modeler." + }, { "name": "FreeFileSync", "slug": "freefilesync/darwin", diff --git a/ee/maintained-apps/outputs/flexwhere/windows.json b/ee/maintained-apps/outputs/flexwhere/windows.json new file mode 100644 index 0000000000..c000db8562 --- /dev/null +++ b/ee/maintained-apps/outputs/flexwhere/windows.json @@ -0,0 +1,23 @@ +{ + "versions": [ + { + "version": "3.5", + "queries": { + "exists": "SELECT 1 FROM programs WHERE name = 'Flexwhere for Desktop' AND publisher = 'Dutchview';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE name = 'Flexwhere for Desktop' AND publisher = 'Dutchview' AND version_compare(version, '3.5') < 0);" + }, + "installer_url": "https://s3.eu-central-1.amazonaws.com/releases.flexwhere.net/Flexwhere+for+Desktop+3.5.msi", + "install_script_ref": "8959087b", + "uninstall_script_ref": "a679a246", + "sha256": "50786b5d742a5f90ede3790e8a47153eaf3137cf1c6b3dc9e786ba3363d0ef70", + "default_categories": [ + "Productivity" + ], + "upgrade_code": "{5916547D-CBFA-451B-AF68-D475E2DA9022}" + } + ], + "refs": { + "8959087b": "$logFile = \"${env:TEMP}/fleet-install-software.log\"\n\ntry {\n\n$installProcess = Start-Process msiexec.exe `\n -ArgumentList \"/quiet /norestart /lv ${logFile} /i `\"${env:INSTALLER_PATH}`\"\" `\n -PassThru -Verb RunAs -Wait\n\nGet-Content $logFile -Tail 500\n\nExit $installProcess.ExitCode\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n", + "a679a246": "# Uninstalls Flexwhere for Desktop.\n#\n# Flexwhere for Desktop auto-starts a tray process (no Windows service), which can hold files\n# and make msiexec roll back the uninstall. Stop anything running from the\n# install dir (plus known process names) FIRST, then resolve the ProductCode(s)\n# via the stable UpgradeCode and msiexec /x each.\n\n$upgradeCode = '{5916547D-CBFA-451B-AF68-D475E2DA9022}'\n$softwareName = 'Flexwhere for Desktop'\n$successCodes = @(0, 3010, 1641)\n\n$machineKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n\ntry {\n\n# Stop the app's processes so the MSI uninstall isn't rolled back by locked files.\n$entry = Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |\n ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } |\n Where-Object { $_.DisplayName -eq $softwareName } | Select-Object -First 1\nif ($entry -and $entry.InstallLocation -and (Test-Path -LiteralPath $entry.InstallLocation)) {\n $loc = $entry.InstallLocation.TrimEnd('\\')\n Get-Process | Where-Object { $_.Path -and $_.Path -like \"$loc\\*\" } |\n ForEach-Object { Stop-Process -Id $_.Id -Force -ErrorAction SilentlyContinue }\n}\nforeach ($p in @(\"Flexwhere for Desktop\")) {\n Stop-Process -Name $p -Force -ErrorAction SilentlyContinue\n}\nStart-Sleep -Seconds 3\n\n# Resolve ProductCode(s) from the stable UpgradeCode and uninstall each.\n$inst = New-Object -ComObject \"WindowsInstaller.Installer\"\n$productCodes = @($inst.RelatedProducts($upgradeCode))\nif ($productCodes.Count -eq 0) {\n Write-Host \"No products found for upgrade code $upgradeCode\"\n Exit 1\n}\n\nforeach ($productCode in $productCodes) {\n Write-Host \"Uninstalling product code: $productCode\"\n $process = Start-Process msiexec.exe `\n -ArgumentList \"/x $productCode /quiet /norestart\" `\n -NoNewWindow -PassThru -Wait\n Write-Host \"Uninstall exit code: $($process.ExitCode)\"\n if ($successCodes -notcontains $process.ExitCode) { Exit $process.ExitCode }\n}\n\nExit 0\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n" + } +} diff --git a/ee/maintained-apps/outputs/fortify/windows.json b/ee/maintained-apps/outputs/fortify/windows.json new file mode 100644 index 0000000000..43e61725c1 --- /dev/null +++ b/ee/maintained-apps/outputs/fortify/windows.json @@ -0,0 +1,23 @@ +{ + "versions": [ + { + "version": "2.1.0", + "queries": { + "exists": "SELECT 1 FROM programs WHERE name = 'Fortify' AND publisher = 'Peculiar Ventures';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE name = 'Fortify' AND publisher = 'Peculiar Ventures' AND version_compare(version, '2.1.0') < 0);" + }, + "installer_url": "https://github.com/PeculiarVentures/fortify-releases/releases/download/v2.1.0/Fortify_2.1.0_x64_en-US.msi", + "install_script_ref": "8959087b", + "uninstall_script_ref": "132b8cb2", + "sha256": "57daec289ba8298d591427014e8ef3339d019907a207282ba61393fd271df04d", + "default_categories": [ + "Security" + ], + "upgrade_code": "{AB87B5E7-17F6-5394-8A15-9EE6AA6B06B8}" + } + ], + "refs": { + "132b8cb2": "# Uninstalls Fortify.\n#\n# Fortify auto-starts a tray process (no Windows service), which can hold files\n# and make msiexec roll back the uninstall. Stop anything running from the\n# install dir (plus known process names) FIRST, then resolve the ProductCode(s)\n# via the stable UpgradeCode and msiexec /x each.\n\n$upgradeCode = '{AB87B5E7-17F6-5394-8A15-9EE6AA6B06B8}'\n$softwareName = 'Fortify'\n$successCodes = @(0, 3010, 1641)\n\n$machineKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n\ntry {\n\n# Stop the app's processes so the MSI uninstall isn't rolled back by locked files.\n$entry = Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |\n ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } |\n Where-Object { $_.DisplayName -eq $softwareName } | Select-Object -First 1\nif ($entry -and $entry.InstallLocation -and (Test-Path -LiteralPath $entry.InstallLocation)) {\n $loc = $entry.InstallLocation.TrimEnd('\\')\n Get-Process | Where-Object { $_.Path -and $_.Path -like \"$loc\\*\" } |\n ForEach-Object { Stop-Process -Id $_.Id -Force -ErrorAction SilentlyContinue }\n}\nforeach ($p in @(\"Fortify\")) {\n Stop-Process -Name $p -Force -ErrorAction SilentlyContinue\n}\nStart-Sleep -Seconds 3\n\n# Resolve ProductCode(s) from the stable UpgradeCode and uninstall each.\n$inst = New-Object -ComObject \"WindowsInstaller.Installer\"\n$productCodes = @($inst.RelatedProducts($upgradeCode))\nif ($productCodes.Count -eq 0) {\n Write-Host \"No products found for upgrade code $upgradeCode\"\n Exit 1\n}\n\nforeach ($productCode in $productCodes) {\n Write-Host \"Uninstalling product code: $productCode\"\n $process = Start-Process msiexec.exe `\n -ArgumentList \"/x $productCode /quiet /norestart\" `\n -NoNewWindow -PassThru -Wait\n Write-Host \"Uninstall exit code: $($process.ExitCode)\"\n if ($successCodes -notcontains $process.ExitCode) { Exit $process.ExitCode }\n}\n\nExit 0\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n", + "8959087b": "$logFile = \"${env:TEMP}/fleet-install-software.log\"\n\ntry {\n\n$installProcess = Start-Process msiexec.exe `\n -ArgumentList \"/quiet /norestart /lv ${logFile} /i `\"${env:INSTALLER_PATH}`\"\" `\n -PassThru -Verb RunAs -Wait\n\nGet-Content $logFile -Tail 500\n\nExit $installProcess.ExitCode\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n" + } +} diff --git a/ee/maintained-apps/outputs/foxit-pdf-editor/windows.json b/ee/maintained-apps/outputs/foxit-pdf-editor/windows.json new file mode 100644 index 0000000000..dd4692d511 --- /dev/null +++ b/ee/maintained-apps/outputs/foxit-pdf-editor/windows.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "14.0.5.33580", + "queries": { + "exists": "SELECT 1 FROM programs WHERE name = 'Foxit PDF Editor' AND publisher = 'Foxit Software Inc.';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE name = 'Foxit PDF Editor' AND publisher = 'Foxit Software Inc.' AND version_compare(version, '14.0.5.33580') < 0);" + }, + "installer_url": "https://cdn01.foxitsoftware.com/product/phantomPDF/desktop/win/14.0.5/FoxitPDFEditor1405_L10N_Setup_x64.exe", + "install_script_ref": "a6208245", + "uninstall_script_ref": "5d55608a", + "sha256": "764aa7ca2679c568539ada4dfa4b1f7de91f9c006fdb8fb98489dea0bce354f7", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "5d55608a": "# Uninstalls Foxit PDF Editor.\n#\n# Foxit PDF Editor is a Foxit WiX MultiLangBootstrapper install that runs an auto-updater\n# service; its visible ARP entry is the inner MSI (its UninstallString uses\n# \"MsiExec.exe /I{ProductCode}\", the maintenance/repair form). We stop the\n# Foxit services/processes first so files aren't locked, then resolve the\n# ProductCode GUID and run a clean \"msiexec /x {ProductCode} /qn /norestart\"\n# (never reuse the /I from the registry string). The ARP entry lives in the\n# WOW6432Node (32-bit) hive even on x64.\n\n$softwareName = \"Foxit PDF Editor\"\n\n$machineKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$successCodes = @(0, 3010, 1641)\n$exitCode = $null\n\ntry {\n\nforeach ($svc in @(\"FoxitPhantomPDFUpdateService\")) {\n Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue\n}\nforeach ($p in @(\"FoxitPDFEditor\", \"FoxitPhantomPDF\", \"FoxitUpdater\")) {\n Stop-Process -Name $p -Force -ErrorAction SilentlyContinue\n}\nStart-Sleep -Seconds 3\n\n[array]$uninstallKeys = Get-ChildItem `\n -Path @($machineKey, $machineKey32on64) `\n -ErrorAction SilentlyContinue |\n ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue }\n\n$selected = $uninstallKeys | Where-Object { $_.DisplayName -eq $softwareName } | Select-Object -First 1\nif (-not $selected) {\n Write-Host \"Uninstall entry not found for '$softwareName'.\"\n Exit 1\n}\n\n# ProductCode: prefer the ARP key name (it is the MSI ProductCode), else pull\n# the first GUID out of the UninstallString. Never carry over its /I switch.\n$productCode = $selected.PSChildName\nif ($productCode -notmatch '^\\{[0-9A-Fa-f-]+\\}$') {\n $raw = $selected.UninstallString\n if ($raw -match '(\\{[0-9A-Fa-f-]+\\})') { $productCode = $matches[1] }\n}\nif ($productCode -notmatch '^\\{[0-9A-Fa-f-]+\\}$') {\n Write-Host \"Could not determine ProductCode for '$softwareName'.\"\n Exit 1\n}\n\nWrite-Host \"Uninstalling product code: $productCode\"\n$process = Start-Process msiexec.exe `\n -ArgumentList \"/x $productCode /qn /norestart\" `\n -NoNewWindow -PassThru -Wait\n$exitCode = $process.ExitCode\nWrite-Host \"Uninstall exit code: $exitCode\"\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n\nif ($successCodes -contains $exitCode) { Exit 0 }\nExit $exitCode\n", + "a6208245": "# Learn more about .exe install scripts:\n# http://fleetdm.com/learn-more-about/exe-install-scripts\n#\n# Foxit PDF Editor ships as a Foxit WiX MultiLangBootstrapper EXE. /quiet /norestart\n# performs a silent per-machine install.\n\n$exeFilePath = \"${env:INSTALLER_PATH}\"\n\ntry {\n if (-not (Test-Path $exeFilePath)) {\n Write-Host \"Error: Installer file not found at: $exeFilePath\"\n Exit 1\n }\n\n $processOptions = @{\n FilePath = \"$exeFilePath\"\n ArgumentList = \"/quiet\"\n PassThru = $true\n Wait = $true\n NoNewWindow = $true\n }\n\n $process = Start-Process @processOptions\n $exitCode = $process.ExitCode\n Write-Host \"Install exit code: $exitCode\"\n\n # 0 = success, 3010 = success but reboot required, 1641 = reboot initiated\n if ($exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 }\n Exit $exitCode\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n" + } +} diff --git a/ee/maintained-apps/outputs/foxit-pdf-reader/windows.json b/ee/maintained-apps/outputs/foxit-pdf-reader/windows.json new file mode 100644 index 0000000000..0ff068a69b --- /dev/null +++ b/ee/maintained-apps/outputs/foxit-pdf-reader/windows.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "2026.1.2.36540", + "queries": { + "exists": "SELECT 1 FROM programs WHERE name = 'Foxit PDF Reader' AND publisher = 'Foxit Software Inc.';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE name = 'Foxit PDF Reader' AND publisher = 'Foxit Software Inc.' AND version_compare(version, '2026.1.2.36540') < 0);" + }, + "installer_url": "https://cdn01.foxitsoftware.com/product/reader/desktop/win/2026.1.2/FoxitPDFReader202612_L10N_Setup_x64.exe", + "install_script_ref": "4ce619b8", + "uninstall_script_ref": "8dbc0197", + "sha256": "74bb18acd4970f2596d63a05a83421e256d272c37c12216de69984e3244c6485", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "4ce619b8": "# Learn more about .exe install scripts:\n# http://fleetdm.com/learn-more-about/exe-install-scripts\n#\n# Foxit PDF Reader ships as a Foxit WiX MultiLangBootstrapper EXE. /quiet /norestart\n# performs a silent per-machine install.\n\n$exeFilePath = \"${env:INSTALLER_PATH}\"\n\ntry {\n if (-not (Test-Path $exeFilePath)) {\n Write-Host \"Error: Installer file not found at: $exeFilePath\"\n Exit 1\n }\n\n $processOptions = @{\n FilePath = \"$exeFilePath\"\n ArgumentList = \"/quiet\"\n PassThru = $true\n Wait = $true\n NoNewWindow = $true\n }\n\n $process = Start-Process @processOptions\n $exitCode = $process.ExitCode\n Write-Host \"Install exit code: $exitCode\"\n\n # 0 = success, 3010 = success but reboot required, 1641 = reboot initiated\n if ($exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 }\n Exit $exitCode\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n", + "8dbc0197": "# Uninstalls Foxit PDF Reader.\n#\n# Foxit PDF Reader is a Foxit WiX MultiLangBootstrapper install that runs an auto-updater\n# service; its visible ARP entry is the inner MSI (its UninstallString uses\n# \"MsiExec.exe /I{ProductCode}\", the maintenance/repair form). We stop the\n# Foxit services/processes first so files aren't locked, then resolve the\n# ProductCode GUID and run a clean \"msiexec /x {ProductCode} /qn /norestart\"\n# (never reuse the /I from the registry string). The ARP entry lives in the\n# WOW6432Node (32-bit) hive even on x64.\n\n$softwareName = \"Foxit PDF Reader\"\n\n$machineKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$successCodes = @(0, 3010, 1641)\n$exitCode = $null\n\ntry {\n\nforeach ($svc in @(\"FoxitPDFReaderUpdateService\")) {\n Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue\n}\nforeach ($p in @(\"FoxitPDFReader\", \"FoxitReader\", \"FoxitUpdater\")) {\n Stop-Process -Name $p -Force -ErrorAction SilentlyContinue\n}\nStart-Sleep -Seconds 3\n\n[array]$uninstallKeys = Get-ChildItem `\n -Path @($machineKey, $machineKey32on64) `\n -ErrorAction SilentlyContinue |\n ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue }\n\n$selected = $uninstallKeys | Where-Object { $_.DisplayName -eq $softwareName } | Select-Object -First 1\nif (-not $selected) {\n Write-Host \"Uninstall entry not found for '$softwareName'.\"\n Exit 1\n}\n\n# ProductCode: prefer the ARP key name (it is the MSI ProductCode), else pull\n# the first GUID out of the UninstallString. Never carry over its /I switch.\n$productCode = $selected.PSChildName\nif ($productCode -notmatch '^\\{[0-9A-Fa-f-]+\\}$') {\n $raw = $selected.UninstallString\n if ($raw -match '(\\{[0-9A-Fa-f-]+\\})') { $productCode = $matches[1] }\n}\nif ($productCode -notmatch '^\\{[0-9A-Fa-f-]+\\}$') {\n Write-Host \"Could not determine ProductCode for '$softwareName'.\"\n Exit 1\n}\n\nWrite-Host \"Uninstalling product code: $productCode\"\n$process = Start-Process msiexec.exe `\n -ArgumentList \"/x $productCode /qn /norestart\" `\n -NoNewWindow -PassThru -Wait\n$exitCode = $process.ExitCode\nWrite-Host \"Uninstall exit code: $exitCode\"\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n\nif ($successCodes -contains $exitCode) { Exit 0 }\nExit $exitCode\n" + } +} diff --git a/ee/maintained-apps/outputs/freecad/windows.json b/ee/maintained-apps/outputs/freecad/windows.json new file mode 100644 index 0000000000..a3335540ce --- /dev/null +++ b/ee/maintained-apps/outputs/freecad/windows.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.1.1", + "queries": { + "exists": "SELECT 1 FROM programs WHERE name LIKE 'FreeCAD%' AND publisher = 'FreeCAD Team';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE name LIKE 'FreeCAD%' AND publisher = 'FreeCAD Team' AND version_compare(version, '1.1.1') < 0);" + }, + "installer_url": "https://github.com/FreeCAD/FreeCAD/releases/download/1.1.1/FreeCAD_1.1.1-Windows-x86_64-py311-installer.exe", + "install_script_ref": "1cf2c1f5", + "uninstall_script_ref": "6baebf4c", + "sha256": "3e4caf58cc1d82e4e8d726572f741ae664b6e91a77c4d3cb59102d9b8bd51feb", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "1cf2c1f5": "# Learn more about .exe install scripts:\n# http://fleetdm.com/learn-more-about/exe-install-scripts\n#\n# FreeCAD ships as a MultiUser NSIS installer. /S runs it silently and\n# /AllUsers forces the machine-wide install (HKLM + C:\\Program Files).\n\n$exeFilePath = \"${env:INSTALLER_PATH}\"\n\ntry {\n\n$processOptions = @{\n FilePath = \"$exeFilePath\"\n ArgumentList = \"/AllUsers /S\"\n PassThru = $true\n Wait = $true\n}\n\n$process = Start-Process @processOptions\n$exitCode = $process.ExitCode\n\nWrite-Host \"Install exit code: $exitCode\"\nExit $exitCode\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n", + "6baebf4c": "# Uninstalls FreeCAD.\n#\n# FreeCAD (MultiUser NSIS) registers a versioned DisplayName (\"FreeCAD 1.1.1\")\n# under HKLM when installed with /AllUsers, so match on the \"FreeCAD\" prefix.\n# Its QuietUninstallString runs \"Uninstall-FreeCAD.exe\" /S (real silent, no\n# service to block removal).\n\n$softwareNameLike = \"FreeCAD*\"\n$publisherLike = \"FreeCAD*\"\n\n$machineKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n\n$exitCode = $null\n\ntry {\n\n[array]$uninstallKeys = Get-ChildItem `\n -Path @($machineKey, $machineKey32on64) `\n -ErrorAction SilentlyContinue |\n ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue }\n\n$selected = $uninstallKeys |\n Where-Object { $_.DisplayName -like $softwareNameLike -and $_.Publisher -like $publisherLike } |\n Select-Object -First 1\nif (-not $selected -or -not $selected.UninstallString) {\n Write-Host \"Uninstall entry not found for $softwareNameLike\"\n Exit 1\n}\n\n$raw = if ($selected.QuietUninstallString) { $selected.QuietUninstallString } else { $selected.UninstallString }\n\n# Parse exe + args (quoted / unquoted / bare).\nif ($raw -match '^\\s*\"([^\"]+)\"\\s*(.*)$') {\n $exe = $matches[1]; $exeArgs = $matches[2].Trim()\n} elseif ($raw -match '(?i)^\\s*(.+?\\.exe)\\s*(.*)$') {\n $exe = $matches[1]; $exeArgs = $matches[2].Trim()\n} else {\n $exe = $raw; $exeArgs = \"\"\n}\n\n# NSIS uninstallers require /S for a silent uninstall.\nif ($exeArgs -notmatch '(?i)(^|\\s)/S(\\s|$)') { $exeArgs = \"$exeArgs /S\".Trim() }\n\nWrite-Host \"Uninstall command: $exe\"\nWrite-Host \"Uninstall args: $exeArgs\"\n$process = Start-Process -FilePath $exe -ArgumentList $exeArgs -PassThru -Wait\n$exitCode = $process.ExitCode\nWrite-Host \"Uninstall exit code: $exitCode\"\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n\nif ($exitCode -eq 0 -or $exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 }\nExit $exitCode\n" + } +} diff --git a/frontend/pages/SoftwarePage/components/icons/Flexwhere.tsx b/frontend/pages/SoftwarePage/components/icons/Flexwhere.tsx new file mode 100644 index 0000000000..62bd0235eb --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Flexwhere.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Flexwhere = (props: SVGProps) => ( + + + +); +export default Flexwhere; diff --git a/frontend/pages/SoftwarePage/components/icons/Fortify.tsx b/frontend/pages/SoftwarePage/components/icons/Fortify.tsx new file mode 100644 index 0000000000..4d8c6f761a --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Fortify.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Fortify = (props: SVGProps) => ( + + + +); +export default Fortify; diff --git a/frontend/pages/SoftwarePage/components/icons/FoxitPdfEditor.tsx b/frontend/pages/SoftwarePage/components/icons/FoxitPdfEditor.tsx new file mode 100644 index 0000000000..febb7fc4c3 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/FoxitPdfEditor.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const FoxitPdfEditor = (props: SVGProps) => ( + + + +); +export default FoxitPdfEditor; diff --git a/frontend/pages/SoftwarePage/components/icons/FoxitPdfReader.tsx b/frontend/pages/SoftwarePage/components/icons/FoxitPdfReader.tsx new file mode 100644 index 0000000000..1ccc51aabd --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/FoxitPdfReader.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const FoxitPdfReader = (props: SVGProps) => ( + + + +); +export default FoxitPdfReader; diff --git a/frontend/pages/SoftwarePage/components/icons/Freecad.tsx b/frontend/pages/SoftwarePage/components/icons/Freecad.tsx new file mode 100644 index 0000000000..88b230783b --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Freecad.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Freecad = (props: SVGProps) => ( + + + +); +export default Freecad; diff --git a/frontend/pages/SoftwarePage/components/icons/index.ts b/frontend/pages/SoftwarePage/components/icons/index.ts index 138b1ff59d..a122c9c37d 100644 --- a/frontend/pages/SoftwarePage/components/icons/index.ts +++ b/frontend/pages/SoftwarePage/components/icons/index.ts @@ -385,6 +385,7 @@ import Firefox from "./Firefox"; import Fission from "./Fission"; import FleetDesktop from "./FleetDesktop"; import Flexoptix from "./Flexoptix"; +import Flexwhere from "./Flexwhere"; import Fluid from "./Fluid"; import FluxApp from "./FluxApp"; import FocusriteControl2 from "./FocusriteControl2"; @@ -394,14 +395,18 @@ import Fontlab from "./Fontlab"; import Forecast from "./Forecast"; import Fork from "./Fork"; import Forklift from "./Forklift"; +import Fortify from "./Fortify"; import FourKSlideshowMaker from "./FourKSlideshowMaker"; import FourKStogram from "./FourKStogram"; import FourKVideoDownloader from "./FourKVideoDownloader"; import FourKVideoDownloaderPlus from "./FourKVideoDownloaderPlus"; import FourKVideoToMp3 from "./FourKVideoToMp3"; import FourKYoutubeToMp3 from "./FourKYoutubeToMp3"; +import FoxitPdfEditor from "./FoxitPdfEditor"; +import FoxitPdfReader from "./FoxitPdfReader"; import Framer from "./Framer"; import Franz from "./Franz"; +import Freecad from "./Freecad"; import FreeDownloadManager from "./FreeDownloadManager"; import Freefilesync from "./Freefilesync"; import Front from "./Front"; @@ -1492,6 +1497,7 @@ export const SOFTWARE_NAME_TO_ICON_MAP = { fission: Fission, "fleet desktop": FleetDesktop, "flexoptix app": Flexoptix, + flexwhere: Flexwhere, fluid: Fluid, "focusrite control 2": FocusriteControl2, folx: Folx, @@ -1500,9 +1506,13 @@ export const SOFTWARE_NAME_TO_ICON_MAP = { forecast: Forecast, fork: Fork, forklift: Forklift, + fortify: Fortify, + "foxit pdf editor": FoxitPdfEditor, + "foxit pdf reader": FoxitPdfReader, framer: Framer, franz: Franz, "free download manager": FreeDownloadManager, + freecad: Freecad, freefilesync: Freefilesync, front: Front, fsmonitor: Fsmonitor, diff --git a/website/assets/images/app-icon-flexwhere-60x60@2x.png b/website/assets/images/app-icon-flexwhere-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bf205fea5a3691eed186b88ad8e288f647e7cf57 GIT binary patch literal 12448 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

o>>Iao|s9N-p0Sa$7Oabc^ec z22BqO*J2C4;FYE`hSQjrWqteG1ciqyV|swy93DU?)6az<`F_+k@SXMyGNj3GTPn+F z%MwLW^<7cJ+RqS&5h7VHXN*MJf49q>T0j-YSZ=#Fq>4ero93IwJ|YIaLOtwa1ckU} zZNWIY);wW|W9|&riF^A8bg0M`o|%|;$*7N{pn^iS+>WO&(X_>q@)021SUrElh{+cF zi`8ViJsG_qKVOjxfKRam5~LrKA`WW_WH92$%0c46M+$_rJdwqs=5uq=m-E~6O`mIE zD)>U^f?A#Kipc^gmaMpSEF8y8N-wNQo5E4X(pq9!BYU0)`)eG`Eh_(hpzFDGIxGAn z9A;5pb;08dFiNa3vK%HL1EPWh8|Sk`2mPkljAx&vt}1wg`15E8S<0s+SSSG6U!Aj*_rYA1|`m?6~7{BLAi=QP5tSTM-r zG+t%k76H$8Z2Ist{Mi={dq31QZmkgz*O#&Ir`(|Hv{d!F*2`eh&-F;CPDf&-e4!Gj z@L&zkwQ$^`2Frs@!-=vQe=9Nr3O%c^!?ty!Naim9C^3r;51$*$hvd! zer2U|mRSGQY{(-*(QXcT8K#&qH_a!HYGa01M_ftWka6+4zEY+hfshUdbRS!_)9brN z!|QW8)b%lxfbFDtWcc&*#+ol18940=Zbe77RqH$Q;g4eMHRB8v8_CO-2?5liunl@> zYBF-UT*(!r?fRQ)@2a?)>FEbKpK%k8nZ2lCsqft$G^g2@oROxk52vZxhKxSS#6g~~ ze~f*fr-bxx6PwsAoZg?8jKJt~QYgFUqtI{P=TELplMS+@#s(CSYNX&{9*B>Ve17@I z3(I**9Zxz6tgO^*dafM__VRtVY%-QC!}puXA5mN~dV{+VywdNL&Az2d%BP9-=$`Xt zHPrUmeK*5tN%kBYFjYi6;DX2vk$iPzT@DoLaO{4b@Ur~a=iVXdI6DfTO8-Xi%9~6* zw6O2r>SglV>EqzdO89mpSNM5%hu)akr+Bqyc#uW(Qtm?&cM+$-A9XFJ%;WIpxd3Xb zsbnS+;cN|>mnh|ji2D+{HoIse^LY*d(g5X)4dzc|4|amytF(bGqu#)WDk|!_ZQn^L htX$$@f-r%Pk6$p(`8jHBWdB^|mz7kKs1-8_{XdAw$w>eJ literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-fortify-60x60@2x.png b/website/assets/images/app-icon-fortify-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..17ae33442fcc7ead715d164ed0a14c3ab4a84630 GIT binary patch literal 12949 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 HBEtR;Dt=9q literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-foxit-pdf-reader-60x60@2x.png b/website/assets/images/app-icon-foxit-pdf-reader-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4a35467b9efb57887a52efcb3d4136c3390c289f GIT binary patch literal 8124 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 literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-freecad-60x60@2x.png b/website/assets/images/app-icon-freecad-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cc332d87ad561663b9d4c59ca4e5d381fcdd598d GIT binary patch literal 3510 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 JrLJ?te*jiOkIMi6 literal 0 HcmV?d00001