Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions ee/maintained-apps/inputs/winget/aomei-backupper-standard.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "AOMEI Backupper Standard",
"slug": "aomei-backupper-standard/windows",
"package_identifier": "AOMEI.Backupper.Standard",
"unique_identifier": "AOMEI Backupper",
"program_publisher": "AOMEI International Network Limited.",
"install_script_path": "ee/maintained-apps/inputs/winget/scripts/aomei_backupper_standard_install.ps1",
"uninstall_script_path": "ee/maintained-apps/inputs/winget/scripts/aomei_backupper_standard_uninstall.ps1",
"installer_arch": "x86",
"installer_type": "exe",
"installer_scope": "machine",
"default_categories": ["Utilities"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Learn more about .exe install scripts:
# http://fleetdm.com/learn-more-about/exe-install-scripts

$exeFilePath = "${env:INSTALLER_PATH}"

try {

# AOMEI Backupper Standard uses Inno Setup
$processOptions = @{
FilePath = "$exeFilePath"
ArgumentList = "/VERYSILENT /SUPPRESSMSGBOXES /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
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# The ARP DisplayName is "AOMEI Backupper" (no "Standard" suffix since ~v7.4).
# Match name and publisher exactly so add-ons sharing the name prefix aren't hit.
$softwareName = "AOMEI Backupper"
$softwarePublisher = "AOMEI International Network Limited."
$uninstallArgs = "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART"

$machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
$machineKey32on64 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
$exitCode = 0

try {
[array]$uninstallKeys = Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |
ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue }
Comment on lines +12 to +13

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf 'Files:\n'
git ls-files | rg 'aomei_backupper_standard_uninstall\.ps1|winget/scripts' || true

printf '\nTarget file excerpt:\n'
sed -n '1,120p' ee/maintained-apps/inputs/winget/scripts/aomei_backupper_standard_uninstall.ps1

printf '\nSearch for similar uninstall registry handling:\n'
rg -n 'SilentlyContinue|Get-ItemProperty|Get-ChildItem|Exit 0|Exit -?\d+' ee/maintained-apps/inputs/winget/scripts || true

Repository: fleetdm/fleet

Length of output: 50370


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
# Read-only behavioral probe for the relevant PowerShell semantics as represented by the script:
# - Get-ChildItem / Get-ItemProperty with -ErrorAction SilentlyContinue suppress errors and continue returning
#   only the items/properties that did not error.
# - An empty result from a missing registry path is indistinguishable from a failed registry read.
import ast
from pathlib import Path

path = Path("ee/maintained-apps/inputs/winget/scripts/aomei_backupper_standard_uninstall.ps1")
text = path.read_text()

checks = {
    "uses_silently_continue_on_getchilditem": "-ErrorAction SilentlyContinue" in text.splitlines()[19],
    "uses_silently_continue_on_getitreprop": "-ErrorAction SilentlyContinue" in text.splitlines()[20],
    "exits_zero_if_not_found_inside_try": "if (-not $foundUninstaller) { Write-Host \"Uninstall entry not found for '$softwareName'.\"; Exit 0 }" in text,
    "exits_zero_after_try_when_not_found": "Exit $exitCode" in text,
    "catches_try_errors": "catch { Write-Host \"Error: $_\"; Exit 1 }" in text,
}
for k, v in checks.items():
    print(f"{k}={v}")

# Static shape check: the assignment to uninstallKeys contains no split handling for absent provider/permission errors.
assignment = next(line.strip() for line in text.splitlines() if line.strip().startswith("[array]$uninstallKeys"))
print("uninstallKeys_assignment=", assignment)
print("uses_error_action_stop_on_registry_read=", "-ErrorAction Stop" in assignment)
PY

Repository: fleetdm/fleet

Length of output: 526


Do not treat every registry read error as “not installed.”

SilentlyContinue suppresses registry enumeration/provider failures, so Exit 0 on “uninstall entry not found” can report success when AOMEI may still be installed. Handle absent registry views separately, and use ErrorAction Stop for expected registry access failures.

🤖 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/aomei_backupper_standard_uninstall.ps1`
around lines 20 - 21, Update the uninstall registry lookup that populates
$uninstallKeys so missing registry views are handled separately from registry
enumeration or provider failures. Replace suppressed registry access with
terminating error handling and explicitly distinguish an absent uninstall entry
from an access/read error; only return the existing “not installed” success path
when both registry views are confirmed absent.


$foundUninstaller = $false
foreach ($key in $uninstallKeys) {
if ($key.DisplayName -eq $softwareName -and $key.Publisher -eq $softwarePublisher) {
$foundUninstaller = $true
$uninstallCommand = if ($key.QuietUninstallString) { $key.QuietUninstallString } else { $key.UninstallString }
Comment on lines +16 to +19

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed. The lookup now matches the DisplayName exactly and also requires Publisher -eq 'AOMEI International Network Limited.', mirroring the exists query (name = 'AOMEI Backupper' AND publisher = ...).

The publisher value is verified, not assumed: the installer's PE version resource has CompanyName = 'AOMEI International Network Limited.', trailing period included. And requiring it here matters beyond picking the right key — the validator's appExists matches on name only, so a wrong exists-query publisher would otherwise ship undetected (that's what happened to Spyder in #50016).

Also added -ErrorAction SilentlyContinue on the key read and the bare-token UninstallString fallback while here. Output regenerated; run 30372509008 passes.

if ($uninstallCommand -match '^\s*"([^"]+)"\s*(.*)$') {
$uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = "$($Matches[2]) $uninstallArgs".Trim() }
} elseif ($uninstallCommand -match '(?i)^\s*(.+?\.exe)\s*(.*)$') {
$uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = "$($Matches[2]) $uninstallArgs".Trim() }
} elseif ($uninstallCommand -match '^\s*(\S+)\s*(.*)$') {
$uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = "$($Matches[2]) $uninstallArgs".Trim() }
}
Write-Host "Uninstall command: $uninstallCommand"; Write-Host "Uninstall args: $uninstallArgs"
$processOptions = @{ FilePath = $uninstallCommand; PassThru = $true; Wait = $true }
if ($uninstallArgs -ne '') { $processOptions.ArgumentList = $uninstallArgs }
$process = Start-Process @processOptions
$exitCode = $process.ExitCode; Write-Host "Uninstall exit code: $exitCode"; break
}
}
if (-not $foundUninstaller) { Write-Host "Uninstall entry not found for '$softwareName'."; Exit 0 }
} catch { Write-Host "Error: $_"; Exit 1 }

Exit $exitCode
22 changes: 22 additions & 0 deletions ee/maintained-apps/outputs/aomei-backupper-standard/windows.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"versions": [
{
"version": "8.4.0.0",
"queries": {
"exists": "SELECT 1 FROM programs WHERE name = 'AOMEI Backupper' AND publisher = 'AOMEI International Network Limited.';",
"patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE name = 'AOMEI Backupper' AND publisher = 'AOMEI International Network Limited.' AND version_compare(version, '8.4.0.0') < 0);"
},
"installer_url": "https://www2.aomeisoftware.com/download/adb/AOMEIBackupperStd.exe",
"install_script_ref": "03d967ed",
"uninstall_script_ref": "e92f2668",
"sha256": "a9b347b8e43a5ef626adad9eda2e5713df7ca86da11438ada7c0a90453a724d2",
"default_categories": [
"Utilities"
]
}
],
"refs": {
"03d967ed": "# Learn more about .exe install scripts:\n# http://fleetdm.com/learn-more-about/exe-install-scripts\n\n$exeFilePath = \"${env:INSTALLER_PATH}\"\n\ntry {\n\n# AOMEI Backupper Standard uses Inno Setup\n$processOptions = @{\n FilePath = \"$exeFilePath\"\n ArgumentList = \"/VERYSILENT /SUPPRESSMSGBOXES /NORESTART\"\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",
"e92f2668": "# The ARP DisplayName is \"AOMEI Backupper\" (no \"Standard\" suffix since ~v7.4).\n# Match name and publisher exactly so add-ons sharing the name prefix aren't hit.\n$softwareName = \"AOMEI Backupper\"\n$softwarePublisher = \"AOMEI International Network Limited.\"\n$uninstallArgs = \"/VERYSILENT /SUPPRESSMSGBOXES /NORESTART\"\n\n$machineKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$exitCode = 0\n\ntry {\n [array]$uninstallKeys = Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |\n ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue }\n\n $foundUninstaller = $false\n foreach ($key in $uninstallKeys) {\n if ($key.DisplayName -eq $softwareName -and $key.Publisher -eq $softwarePublisher) {\n $foundUninstaller = $true\n $uninstallCommand = if ($key.QuietUninstallString) { $key.QuietUninstallString } else { $key.UninstallString }\n if ($uninstallCommand -match '^\\s*\"([^\"]+)\"\\s*(.*)$') {\n $uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = \"$($Matches[2]) $uninstallArgs\".Trim() }\n } elseif ($uninstallCommand -match '(?i)^\\s*(.+?\\.exe)\\s*(.*)$') {\n $uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = \"$($Matches[2]) $uninstallArgs\".Trim() }\n } elseif ($uninstallCommand -match '^\\s*(\\S+)\\s*(.*)$') {\n $uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = \"$($Matches[2]) $uninstallArgs\".Trim() }\n }\n Write-Host \"Uninstall command: $uninstallCommand\"; Write-Host \"Uninstall args: $uninstallArgs\"\n $processOptions = @{ FilePath = $uninstallCommand; PassThru = $true; Wait = $true }\n if ($uninstallArgs -ne '') { $processOptions.ArgumentList = $uninstallArgs }\n $process = Start-Process @processOptions\n $exitCode = $process.ExitCode; Write-Host \"Uninstall exit code: $exitCode\"; break\n }\n }\n if (-not $foundUninstaller) { Write-Host \"Uninstall entry not found for '$softwareName'.\"; Exit 0 }\n} catch { Write-Host \"Error: $_\"; Exit 1 }\n\nExit $exitCode\n"
}
}
7 changes: 7 additions & 0 deletions ee/maintained-apps/outputs/apps.json
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,13 @@
"unique_identifier": "com.anytype.anytype",
"description": "Anytype is a local-first and end-to-end encrypted notes app."
},
{
"name": "AOMEI Backupper Standard",
"slug": "aomei-backupper-standard/windows",
"platform": "windows",
"unique_identifier": "AOMEI Backupper",
"description": "AOMEI Backupper Standard is a backup, sync, and disaster recovery tool for Windows."
},
{
"name": "Apidog",
"slug": "apidog/darwin",
Expand Down

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions frontend/pages/SoftwarePage/components/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import Anyburn from "./Anyburn";
import AnyDesk from "./AnyDesk";
import Anydo from "./Anydo";
import Anytype from "./Anytype";
import AomeiBackupperStandard from "./AomeiBackupperStandard";
import Apidog from "./Apidog";
import Apparency from "./Apparency";
import AppCleaner from "./AppCleaner";
Expand Down Expand Up @@ -1211,6 +1212,7 @@ export const SOFTWARE_NAME_TO_ICON_MAP = {
anyburn: Anyburn,
anydesk: AnyDesk,
anytype: Anytype,
"aomei backupper standard": AomeiBackupperStandard,
apidog: Apidog,
"app fair": AppFair,
apparency: Apparency,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading