categories/OemSuites.ps1

# OEM Suites category: hardcoded ASUS/Dell/HP/Lenovo/Acer service patterns, plus a generic
# heuristic detector for other non-Microsoft-signed "vendor utility"-style services
# (research.md -> "OEM vendor-suite heuristic detection"). Heuristic hits are flagged
# separately (HeuristicMatch = $true) and need their own confirmation (FR-017).
#
# ponytail: only Windows services are covered (both hardcoded and heuristic paths), not
# Win32_StartupCommand registry Run-key entries - parsing every HKU/HKLM Run-key location
# format robustly is a separate, larger piece of work. Upgrade if a vendor suite turns out to
# rely on a Run-key autostart instead of a service.

$script:OctaOemHardcodedPatterns = @(
    # ponytail: \bAURA\b, not a bare AURA - real -match is case-insensitive and an unanchored
    # substring, so bare "AURA" matched inside the Spanish word "restauracion" (as in
    # "reconstitution/restore"). Verified on a real Spanish-language Windows install: Microsoft's
    # own "Cloud backup and restore" service - "Servicio de copia de seguridad y restauracion en
    # la nube" - got hardcoded-pattern-matched as ASUS bloat, through the branch with NO separate
    # confirmation gate (unlike a HeuristicMatch hit), purely from that substring collision. Word
    # boundaries still match the real target correctly (confirmed: "ASUS AURA SYNC lighting
    # service"), just not as a substring of an unrelated word in another language.
    @{ Vendor = 'ASUS'; Pattern = 'Armoury Crate|ASUS.*Service|\bAURA\b|ROG Live Service|Ambient.*HAL' },
    @{ Vendor = 'Dell'; Pattern = 'Dell.*Update|SupportAssist|Dell Digital Delivery' },
    @{ Vendor = 'HP'; Pattern = 'HP Support Assistant|HP.*Update|HPWMISvc|HP Sure' },
    @{ Vendor = 'Lenovo'; Pattern = 'Lenovo Vantage|ImController|Lenovo.*Service' },
    @{ Vendor = 'Acer'; Pattern = 'Acer.*Care|Acer.*Update|Quick Access' }
)
$script:OctaOemHeuristicKeywords = 'Update|Service|Assistant|Center|Tray|Helper|Agent|Monitor'

function Get-OctaOemSuitesCategory {
    [CmdletBinding()]
    param()
    return [pscustomobject]@{
        Id                  = 'oem-suites'
        DisplayName         = 'OEM Suites'
        Description         = 'ASUS/Dell/HP/Lenovo/Acer + heuristic detector'
        RequiresElevation   = $true
        ContainsIrreversibleActions = $false
        GetActionsFunction  = 'Get-OctaOemSuitesActions'
        ApplyActionFunction = 'Set-OctaOemSuitesAction'
    }
}

function Get-OctaOemSuitesActions {
    [CmdletBinding()]
    param()
    $actions = @()
    $allServices = @(Get-CimInstance -ClassName Win32_Service -ErrorAction SilentlyContinue)
    $hardcodedNames = @()

    foreach ($pat in $script:OctaOemHardcodedPatterns) {
        $matched = $allServices | Where-Object { $_.DisplayName -match $pat.Pattern -or $_.Name -match $pat.Pattern }
        foreach ($svc in $matched) {
            if ($svc.StartMode -ne 'Disabled') {
                $actions += New-OctaAction -TargetType Service -TargetIdentifier $svc.Name `
                    -CurrentValue $svc.StartMode -PlannedValue 'Disabled' -Reversible $true
            }
            $hardcodedNames += $svc.Name
        }
    }

    $candidates = $allServices | Where-Object {
        $_.StartMode -ne 'Disabled' -and $_.Name -notin $hardcodedNames -and $_.PathName
    }
    foreach ($svc in $candidates) {
        if ($svc.PathName -match '^"([^"]+)"') {
            $exePath = $Matches[1]
        }
        elseif ($svc.PathName -match '^([^\s]+\.exe)') {
            $exePath = $Matches[1]
        }
        else {
            continue
        }

        $exists = $false
        try { $exists = Test-Path -LiteralPath $exePath -ErrorAction Stop } catch { continue }
        if (-not $exists) { continue }

        $sig = Get-AuthenticodeSignature -LiteralPath $exePath -ErrorAction SilentlyContinue
        $isMicrosoft = $sig -and $sig.SignerCertificate -and ($sig.SignerCertificate.Subject -match 'O=Microsoft Corporation')
        if ($isMicrosoft) { continue }

        if ($svc.Name -match $script:OctaOemHeuristicKeywords -or $svc.DisplayName -match $script:OctaOemHeuristicKeywords) {
            $actions += New-OctaAction -TargetType Service -TargetIdentifier $svc.Name `
                -CurrentValue $svc.StartMode -PlannedValue 'Disabled' -Reversible $true -HeuristicMatch $true
        }
    }

    return $actions
}

function Set-OctaOemSuitesAction {
    [CmdletBinding()]
    param([Parameter(Mandatory)]$Action)
    Set-Service -Name $Action.TargetIdentifier -StartupType Disabled
}