ControlC ControlC.com

.Net finder

Views: 52Total Chars: 6,568
Created: 9/19/26 2:57:37AM ET
Self Destructs: Never
# Safely attempt compiling C# wrapper for native Windows resource string resolution
if (-not ([System.Management.Automation.PSTypeName]'ResourceResolver').Type) {
try {
$source = @"
using System;
using System.Text;
using System.Runtime.InteropServices;
public class ResourceResolver {
[DllImport("shlwapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode, ExactSpelling = true)]
public static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf, IntPtr ppvReserved);

public static string Resolve(string resourceUri) {
StringBuilder sb = new StringBuilder(1024);
int hr = SHLoadIndirectString(resourceUri, sb, (uint)sb.Capacity, IntPtr.Zero);
return (hr == 0 && sb.Length > 0) ? sb.ToString() : null;
}
}
"@
Add-Type -TypeDefinition $source -ErrorAction SilentlyContinue
} catch {}
}

# Safely extract friendly display name from AppxManifest.xml
function Get-AppxFriendlyName ($filePath) {
try {
$dir = Split-Path $filePath -Parent
$depth = 0
while ($dir -and (Test-Path $dir) -and $depth -lt 4) {
$manifestPath = Join-Path $dir "AppxManifest.xml"
if (Test-Path $manifestPath) {
[xml]$manifest = Get-Content $manifestPath -ErrorAction Stop
$dispName = $manifest.Package.Properties.DisplayName

# Resolve ms-resource: pointers
if ($dispName -like 'ms-resource:*') {
if (([System.Management.Automation.PSTypeName]'ResourceResolver').Type) {
$resUri = "@{$dir\resources.pri?$dispName}"
$resolved = [ResourceResolver]::Resolve($resUri)
if ($resolved) { return $resolved }
}
$dispName = $manifest.Package.Identity.Name
}

if ($dispName) {
return ($dispName -replace '^Microsoft\.', 'Microsoft ' -replace '\.', ' ')
}
break
}
$dir = Split-Path $dir -Parent
$depth++
}
} catch {}
return $null
}

# Configure .NET Enumeration Options
$enumOptions = [System.IO.EnumerationOptions]::new()
$enumOptions.RecurseSubdirectories = $true
$enumOptions.IgnoreInaccessible = $true
$enumOptions.AttributesToSkip = [System.IO.FileAttributes]0

$SearchPaths = @(
$env:ProgramFiles,
"${env:ProgramFiles(x86)}",
"$env:LOCALAPPDATA\Programs",
"$env:ProgramData"
) | Where-Object { $_ -and (Test-Path $_) }

$ExcludePatterns = @('\dotnet\shared\', '\dotnet\sdk\', '\dotnet\host\')

$files = foreach ($path in $SearchPaths) {
[System.IO.Directory]::EnumerateFiles($path, "*.runtimeconfig.json", $enumOptions)
}

$results = foreach ($file in $files) {
if ($ExcludePatterns | Where-Object { $file -like "*$_*" }) { continue }

try {
$fileInfo = Get-Item -Path $file -ErrorAction SilentlyContinue
if (-not $fileInfo) { continue }

$config = Get-Content -Path $file -Raw | ConvertFrom-Json
$options = $config.runtimeOptions
if (-not $options) { continue }

$dir = $fileInfo.DirectoryName
$baseName = $fileInfo.Name -replace '\.runtimeconfig\.json$', ''
$appName = $null

# 1. Resolve Store / UWP apps in WindowsApps
if ($file -like '*\WindowsApps\*') {
$appName = Get-AppxFriendlyName -filePath $file
}

# 2. Match base executable VersionInfo
if (-not $appName) {
$exePath = Join-Path $dir "$baseName.exe"
if (Test-Path $exePath) {
$vi = (Get-Item $exePath).VersionInfo
if ($vi.ProductName) { $appName = $vi.ProductName }
elseif ($vi.FileDescription) { $appName = $vi.FileDescription }
}
}

# 3. Check adjacent executables
if (-not $appName) {
$otherExes = Get-ChildItem -Path $dir -Filter "*.exe" -ErrorAction SilentlyContinue |
Where-Object { $_.Name -notmatch '^(createdump|apphost|dotnet)\.exe$' }

foreach ($exe in $otherExes) {
$vi = $exe.VersionInfo
if ($vi.ProductName) { $appName = $vi.ProductName; break }
if ($vi.FileDescription) { $appName = $vi.FileDescription; break }
}
}

# 4. Fallback to folder name
if (-not $appName) {
$appName = "$baseName [$($fileInfo.Directory.Name)]"
}

# Collect framework objects
$fwList = [System.Collections.Generic.List[PSCustomObject]]::new()
if ($options.framework) { $fwList.Add($options.framework) }
if ($options.frameworks) { foreach ($f in $options.frameworks) { $fwList.Add($f) } }
if ($options.includedFrameworks) { foreach ($f in $options.includedFrameworks) { $fwList.Add($f) } }

$runtimes = @()
foreach ($fw in $fwList) {
$runtimes += "$($fw.name) $($fw.version)"
}

if ($runtimes.Count -eq 0 -and $options.tfm) {
$runtimes += "Self-Contained ($($options.tfm))"
}

foreach ($runtime in $runtimes) {
[PSCustomObject]@{
AppName = $appName
Runtime = $runtime
Path = $file
}
}
} catch {}
}

# Group by Application, apply framework deduplication, and sort by RuntimeVersion
$results | Group-Object AppName | ForEach-Object {
$appName = $_.Name
$runtimes = $_.Group.Runtime | Select-Object -Unique

if ($runtimes | Where-Object { $_ -match 'WindowsDesktop|AspNetCore' }) {
$runtimes = $runtimes | Where-Object { $_ -notmatch 'Microsoft\.NETCore\.App' }
}

[PSCustomObject]@{
Application = $appName
RuntimeVersion = ($runtimes | Select-Object -Unique) -join ', '
}
} | Sort-Object @(
# 1. Framework Name (extract first word before space)
@{ Expression = { ($_.RuntimeVersion -split '\s+')[0] } },
# 2. Strict Version regex parsing (ignores trailing commas or text)
@{ Expression = {
if ($_.RuntimeVersion -match '(\d+\.\d+\.\d+)') {
try { [version]$matches[1] } catch { [version]'0.0' }
} else {
[version]'0.0'
}
}},
# 3. Application Name tiebreaker
@{ Expression = { $_.Application } }
) | Format-Table -Wrap
6,568 chars, 654 words, 173 lines·Create new version