Private/ConvertFrom-Win32ToolkitDisplayIcon.ps1
|
function ConvertFrom-Win32ToolkitDisplayIcon { <# .SYNOPSIS Parses an Add/Remove-Programs 'DisplayIcon' value into a resolved path + resource index. .DESCRIPTION The ARP DisplayIcon registry value points at the file that holds the app's icon. It comes in a few shapes: "C:\Program Files\App\app.exe",0 quoted path, explicit resource index C:\Program Files\App\app.exe,-3 unquoted path, negative index (a resource ID) C:\App\app.ico bare path, no index (defaults to 0) %SystemRoot%\system32\x.dll,12 environment variables to expand Returns [pscustomobject]@{ Path; Index } with environment variables expanded, or $null when the value is empty. A NEGATIVE index is preserved verbatim (PrivateExtractIcons / ExtractIconEx treat |index| as a resource ID in that case) — never clamp it to 0. NOTE: the guest capture script (New-TargetedDocumentation) inlines a byte-for-byte mirror of this logic as `ConvertFrom-DisplayIcon` so it can run under Windows PowerShell 5.1 with no module. Keep the two in sync; this host copy is the one covered by Tests\IconFromInstall.unit.ps1. #> [CmdletBinding()] [OutputType([pscustomobject])] param( [string]$Value ) if (-not $Value) { return $null } $v = $Value.Trim() if (-not $v) { return $null } $idx = 0 if ($v.StartsWith('"')) { # Quoted path: take everything up to the closing quote, then an optional ,<index> after it. $end = $v.IndexOf('"', 1) if ($end -lt 0) { return $null } $p = $v.Substring(1, $end - 1) $rest = $v.Substring($end + 1).Trim() if ($rest -match '^,\s*(-?\d+)') { $idx = [int]$matches[1] } } else { # Unquoted: a trailing ,<index> (last one wins) is the resource index; the rest is the path. if ($v -match '^(.*),\s*(-?\d+)\s*$') { $p = $matches[1].Trim(); $idx = [int]$matches[2] } else { $p = $v } } if (-not $p) { return $null } $p = [Environment]::ExpandEnvironmentVariables($p) [pscustomobject]@{ Path = $p; Index = $idx } } |