Skip to content

Detect applications by ProductCode instead of substring matching - #6

Merged
TecharyJames merged 1 commit into
BETAfrom
fix/precise-app-detection
Sep 19, 2026
Merged

TecharyJames merged 1 commit into
BETAfrom
fix/precise-app-detection

Conversation

@TecharyJames

Copy link
Copy Markdown
Member

Stacked on #3 (uses the manifest index). Diff is against its branch; base retargets as the stack merges.

The problem

Test-TecharyApp matched only on DisplayName -like "*$Name*", which fails in both directions.

False negative. It could not detect anything by winget package ID — the identifier Install-TecharyApp takes. No ARP DisplayName contains the string 7zip.7zip, so on a machine with 7-Zip installed:

Test-TecharyApp -Name 7zip.7zip   ->  False

False positive. Teams matches Microsoft Teams Meeting Add-in for Microsoft Office, reporting Teams as installed on a machine with no Teams desktop app.

Detection order

winget records the ARP subkey name in ProductCode — an MSI product GUID, or a plain name such as 7-Zip or Notepad++. With the index from #3 available, that makes detection a direct key lookup.

Tier Basis Precision
1 ProductCode → ARP subkey Definitive
2 Exact DisplayName (from -Name or the custom catalogue) Exact
3 Substring DisplayName Imprecise
4 MSIX package name Name-based

The substring tier is kept deliberately. Removing it would flip detections from True to False across the estate and trigger reinstalls. It is now reported through MatchedBy, so an imprecise match is visible rather than indistinguishable from an exact one.

Other changes

  • No network calls. Get-ManifestIndex and Get-CustomApp take -NoRefresh, and detection uses it, because this runs on a schedule on every endpoint.
  • Names are escaped before wildcard comparison. A name containing [ or ] was previously treated as a wildcard pattern and silently matched nothing.
  • MSIX enumeration uses -AllUsers when elevated, for the same reason as Make MSIX removal work under SYSTEM and stop deprovisioned apps returning #4: SYSTEM sees almost none of its own packages.
  • Adds -Detailed, returning what matched and the installed version. The default return stays a boolean, so existing callers are unaffected.

Verification

Against the BETA implementation, same machine:

  7zip.7zip            old=False  new=True   via=ProductCode   <-- CHANGED
  7-Zip                old=True   new=True   via=Substring
  Teams                old=True   new=True   via=Substring
  WindowsCalculator    old=True   new=True   via=Msix

7-Zip is in fact installed (7-Zip 26.03 (x64)), so the single change is a false negative corrected. No case flips to False.

-Detailed output:

  7zip.7zip              installed=True  via=ProductCode  7-Zip 26.03 (x64)
  Notepad++.Notepad++    installed=False via=None
  Teams                  installed=True  via=Substring    Microsoft Teams Meeting Add-in for Microsoft Office
  WindowsCalculator      installed=True  via=Msix         Microsoft.WindowsCalculator
  NoSuchAppZZZ           installed=False via=None

Boolean contract confirmed: 7zip.7zip → True (Boolean), NoSuchAppZZZ → False (Boolean).

Tier 1 requires the package to be in the index from #3. Without it, detection falls back to tiers 2–4, which is the current behaviour plus the escaping fix.

Test-TecharyApp matched only on DisplayName -like "*$Name*", which fails in
both directions.

False negative: it could not detect anything by winget package ID, which is
the identifier Install-TecharyApp takes. No ARP DisplayName contains the
string "7zip.7zip", so Test-TecharyApp -Name 7zip.7zip returned False on a
machine with 7-Zip installed.

False positive: "Teams" matches "Microsoft Teams Meeting Add-in for
Microsoft Office", so it reports Teams as installed on a machine with no
Teams desktop app.

Detection now works most-precise-first. winget records the ARP subkey name
in ProductCode, an MSI product GUID or a plain name such as "7-Zip", so with
the manifest index available this becomes a direct key lookup and is
definitive. Failing that it tries an exact DisplayName, then the previous
substring behaviour, then MSIX.

The substring tier is kept deliberately. Removing it would flip detections
from True to False across the estate and trigger reinstalls. It is now
reported through MatchedBy so an imprecise match is visible rather than
indistinguishable from an exact one.

Makes no network calls. Get-ManifestIndex and Get-CustomApp take -NoRefresh,
and detection uses it, because this runs on a schedule on every endpoint.

Names are escaped before wildcard comparison. A name containing [ or ] was
previously treated as a wildcard pattern and silently matched nothing.

MSIX enumeration uses -AllUsers when elevated, for the same reason as the
uninstall path: SYSTEM sees almost none of its own packages.

Adds -Detailed, returning what matched and the installed version. The
default return stays a boolean, so existing callers are unaffected.

Verified against the BETA implementation on the same machine: 7zip.7zip goes
False to True via ProductCode, and 7-Zip, Teams and WindowsCalculator are
unchanged. No case flips to False.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant