# internal flag to avoid infinite elevation loop
$currentUser = New-Object Security.Principal.WindowsPrincipal(
[Security.Principal.WindowsIdentity]::GetCurrent()
return $currentUser.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
# --- Locate the published EXE under bin\Release\{TFM}\{RID}\publish ---
$scriptDir = Split-Path $PSCommandPath -Parent
$releaseRoot = Join-Path $scriptDir "bin\Release"
if (-not (Test-Path $releaseRoot)) {
Write-Host "ERROR: Release build folder not found at:"
Write-Host " $releaseRoot"
Write-Host "Run: dotnet publish -c Release"
# Pick latest TFM directory (netX.X)
$tfmDirs = Get-ChildItem $releaseRoot -Directory | Sort-Object Name
if ($tfmDirs.Count -eq 0) {
Write-Host "ERROR: No TFM directories found under:"
Write-Host " $releaseRoot"
$latestTfmDir = $tfmDirs[-1]
Write-Host "Selected TFM: $($latestTfmDir.Name)"
# Inside that, pick latest RID directory (win-x64, win-arm64, etc.)
$ridDirs = Get-ChildItem $latestTfmDir.FullName -Directory | Sort-Object Name
if ($ridDirs.Count -eq 0) {
Write-Host "ERROR: No RID directories found under:"
Write-Host " $($latestTfmDir.FullName)"
$latestRidDir = $ridDirs[-1]
Write-Host "Selected RID: $($latestRidDir.Name)"
$publishDir = Join-Path $latestRidDir.FullName "publish"
if (-not (Test-Path $publishDir)) {
Write-Host "ERROR: Publish folder not found:"
Write-Host " $publishDir"
Write-Host "Run: dotnet publish -c Release -r $($latestRidDir.Name)"
$exeCandidate = Get-ChildItem $publishDir -Filter "*.exe" | Sort-Object LastWriteTime | Select-Object -Last 1
if (-not $exeCandidate) {
Write-Host "ERROR: No .exe found in:"
Write-Host " $publishDir"
$exePath = $exeCandidate.FullName
Write-Host "Using EXE: $exePath"
# --- Elevation dance ---
if (-not $NoElevate -and -not (Test-IsAdmin)) {
Write-Host "Not running as administrator. Requesting elevation..."
$scriptPath = $PSCommandPath
$args = "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`" -NoElevate"
Start-Process powershell -ArgumentList $args -Verb RunAs -Wait
Write-Host "Running with administrative privileges."
# --- 1) Copy EXE to Program Files\Uncharted Limbo Collective ---
$installDir = Join-Path $env:ProgramFiles "Uncharted Limbo Collective"
if (-not (Test-Path $installDir)) {
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
$exeName = "ThumbnailGenerator.exe"
$destExe = Join-Path $installDir $exeName
Copy-Item -Path $exePath -Destination $destExe -Force
Write-Host "Copied $exePath -> $destExe"
# --- 2) Registry: create nested context menu entries ---
$extensions = @(".jpg", ".jpeg", ".png", ".bmp", ".gif", ".webp")
foreach ($ext in $extensions) {
# Root: Uncharted Limbo Tools (cascading)
$rootKey = "Registry::HKEY_CLASSES_ROOT\SystemFileAssociations\$ext\shell\UnchartedLimboTools"
if (-not (Test-Path $rootKey)) {
New-Item -Path $rootKey -Force | Out-Null
Set-ItemProperty -Path $rootKey -Name 'MUIVerb' -Value 'Uncharted Limbo Tools'
Set-ItemProperty -Path $rootKey -Name 'SubCommands' -Value ''
# Child: Thumbnail Generator (cascading)
$thumbGenKey = Join-Path $rootKey "shell\ThumbnailGenerator"
if (-not (Test-Path $thumbGenKey)) {
New-Item -Path $thumbGenKey -Force | Out-Null
Set-ItemProperty -Path $thumbGenKey -Name 'MUIVerb' -Value 'Thumbnail Generator'
Set-ItemProperty -Path $thumbGenKey -Name 'SubCommands' -Value ''
# --- 512x512 Website Thumbnail ---
$make512Key = Join-Path $thumbGenKey "shell\Make512"
if (-not (Test-Path $make512Key)) {
New-Item -Path $make512Key -Force | Out-Null
Set-ItemProperty -Path $make512Key -Name 'MUIVerb' -Value 'Make 512x512 Website Thumbnail'
$cmd512Key = Join-Path $make512Key "command"
if (-not (Test-Path $cmd512Key)) {
New-Item -Path $cmd512Key -Force | Out-Null
$cmd512 = "`"$destExe`" 512 `"%1`""
Set-ItemProperty -Path $cmd512Key -Name '(default)' -Value $cmd512
# --- 256x256 Website Logo ---
$make256Key = Join-Path $thumbGenKey "shell\Make256"
if (-not (Test-Path $make256Key)) {
New-Item -Path $make256Key -Force | Out-Null
Set-ItemProperty -Path $make256Key -Name 'MUIVerb' -Value 'Make 256x256 Website Logo'
$cmd256Key = Join-Path $make256Key "command"
if (-not (Test-Path $cmd256Key)) {
New-Item -Path $cmd256Key -Force | Out-Null
$cmd256 = "`"$destExe`" 256 `"%1`""
Set-ItemProperty -Path $cmd256Key -Name '(default)' -Value $cmd256
Write-Host "Registered menu for $ext"
Write-Host "Deployment complete."
# Small pause so you can see the output in the elevated window
Write-Host "Done. Keeping this PowerShell window open for 5 seconds..."