param( [Parameter(Mandatory = $true)] [string]$Archive, [Parameter(Mandatory = $true)] [string]$Slug, [string]$RootDirectory = "C:\codex\catalog-screenshots", [string]$InitialKeys = "", [ValidateRange(1, 60)] [int]$WaitSeconds = 8 ) $ErrorActionPreference = "Stop" [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new() $workDirectory = Join-Path $RootDirectory "work\$Slug" $outputDirectory = Join-Path $RootDirectory "results" $runner = Join-Path $PSScriptRoot "runScreenshotTask.ps1" $javaExecutable = "C:\codex\jre\bin\javaw.exe" function Get-NormalizedName { param([string]$Value) return ($Value.ToLowerInvariant() -replace '[^a-z0-9]', '') } function Get-CandidateScore { param( [System.IO.FileInfo]$File, [string]$ProgramSlug ) $stem = Get-NormalizedName $File.BaseName $slugName = Get-NormalizedName $ProgramSlug $score = [Math]::Log([Math]::Max($File.Length, 1), 2) if ($stem -eq $slugName) { $score += 100 } foreach ($token in ($ProgramSlug -split '[-_]')) { if ($token.Length -ge 3 -and $stem.Contains((Get-NormalizedName $token))) { $score += 15 } } $relativePath = $File.FullName.Substring($workDirectory.Length).TrimStart('\') $score -= ([regex]::Matches($relativePath, '\\').Count * 2) if ($File.BaseName -match '^(unins|uninstall|unwise|remove|register|regsvr)') { $score -= 200 } if ($File.BaseName -match '(setup|install|autorun|update|updater)') { $score -= 50 } return $score } function Stop-WorkDirectoryProcesses { $directoryPrefix = $workDirectory.TrimEnd('\') + '\' for ($attempt = 0; $attempt -lt 3; $attempt++) { foreach ($item in Get-CimInstance Win32_Process -ErrorAction SilentlyContinue) { if ($item.ExecutablePath -and $item.ExecutablePath.StartsWith($directoryPrefix, [System.StringComparison]::OrdinalIgnoreCase)) { taskkill.exe /PID $item.ProcessId /T /F 2>$null | Out-Null } } Start-Sleep -Milliseconds 300 } } New-Item -ItemType Directory -Force -Path $workDirectory, $outputDirectory | Out-Null try { Expand-Archive -LiteralPath $Archive -DestinationPath $workDirectory -Force $candidates = @( Get-ChildItem -LiteralPath $workDirectory -Recurse -File -Filter "*.exe" | ForEach-Object { [pscustomobject]@{ File = $_ Score = Get-CandidateScore -File $_ -ProgramSlug $Slug } } | Sort-Object @{ Expression = "Score"; Descending = $true }, @{ Expression = { $_.File.Length }; Descending = $true } ) $arguments = "" $executable = $null $workingDirectory = $null if ($candidates.Count -gt 0) { $selected = $candidates[0].File $executable = $selected.FullName $workingDirectory = $selected.DirectoryName } else { $candidates = @( Get-ChildItem -LiteralPath $workDirectory -Recurse -File -Filter "*.jar" | Where-Object { $_.DirectoryName -notmatch '\\lib($|\\)' } | ForEach-Object { [pscustomobject]@{ File = $_ Score = Get-CandidateScore -File $_ -ProgramSlug $Slug } } | Sort-Object @{ Expression = "Score"; Descending = $true }, @{ Expression = { $_.File.Length }; Descending = $true } ) if ($candidates.Count -eq 0 -or -not (Test-Path -LiteralPath $javaExecutable)) { [pscustomobject]@{ success = $false reason = "no-executable" candidates = @() } | ConvertTo-Json -Depth 5 -Compress exit 1 } $selected = $candidates[0].File $executable = $javaExecutable $workingDirectory = $selected.DirectoryName $arguments = "-jar `"$($selected.FullName)`"" } $installer = $selected.Extension -ieq ".exe" -and $selected.BaseName -match '(setup|install|autorun)' if ($installer) { [pscustomobject]@{ success = $false reason = "installer-only" selected = $selected.FullName.Substring($workDirectory.Length).TrimStart('\') installer = $true candidates = @($candidates | Select-Object -First 10 | ForEach-Object { [pscustomobject]@{ path = $_.File.FullName.Substring($workDirectory.Length).TrimStart('\') size = $_.File.Length score = [Math]::Round($_.Score, 2) } }) } | ConvertTo-Json -Depth 5 -Compress exit 1 } $winapp = "C:\codex\winapp\winapp.exe" $screenshotTool = if (Test-Path -LiteralPath $winapp) { $winapp } else { Join-Path $RootDirectory "nircmd.exe" } $runnerParameters = @{ Executable = $executable Name = $Slug OutputDirectory = $outputDirectory WaitSeconds = $WaitSeconds Arguments = $arguments WorkingDirectory = $workingDirectory InitialKeys = $InitialKeys ScreenshotTool = $screenshotTool } $rawResult = & $runner @runnerParameters $result = $rawResult | ConvertFrom-Json [pscustomobject]@{ success = [bool]$result.success reason = $result.reason title = $result.title error = $result.error selected = $selected.FullName.Substring($workDirectory.Length).TrimStart('\') installer = $installer width = $result.width height = $result.height windows = $result.windows candidates = @($candidates | Select-Object -First 10 | ForEach-Object { [pscustomobject]@{ path = $_.File.FullName.Substring($workDirectory.Length).TrimStart('\') size = $_.File.Length score = [Math]::Round($_.Score, 2) } }) } | ConvertTo-Json -Depth 7 -Compress } catch { [pscustomobject]@{ success = $false reason = "error" error = $_.Exception.Message candidates = @() } | ConvertTo-Json -Depth 5 -Compress exit 1 } finally { Stop-WorkDirectoryProcesses Remove-Item -LiteralPath $workDirectory -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -LiteralPath $Archive -Force -ErrorAction SilentlyContinue }