# Console-window watcher for the ELEVATED job path (app/igneum-app/src/jobrun.rs run_script with elevated=true: the # app's headless powershell runs `Start-Process powershell.exe -Verb RunAs -Wait -WindowStyle Hidden`, the AppInfo # service creates this process after the UAC prompt). The engine's power cap, the sweep helper and the clock sync take # the same road with cmd.exe (platform.rs run_elevated, sync_clock; app/windows/host.cpp runElevated). This script # runs INSIDE the elevated process and reports whether its own console has a window, which host serves it, and # whether a Windows Terminal window appeared for it. One UAC prompt on the PC; a few seconds. # packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --elevated --timeout-minutes 3 \ # --script tools/windows/console-watch-elevated.ps1 --title "PC 1: elevated console watcher" --deploy $ErrorActionPreference = 'Continue' $src = @' using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; public static class IgWin3 { public delegate bool EnumProc(IntPtr h, IntPtr l); [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc p, IntPtr l); [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h); [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid); [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetWindowText(IntPtr h, StringBuilder s, int n); [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetClassName(IntPtr h, StringBuilder s, int n); [DllImport("kernel32.dll")] public static extern IntPtr GetConsoleWindow(); public static List Visible() { var list = new List(); EnumWindows((h, l) => { if (!IsWindowVisible(h)) return true; uint pid; GetWindowThreadProcessId(h, out pid); var t = new StringBuilder(512); GetWindowText(h, t, 512); var c = new StringBuilder(256); GetClassName(h, c, 256); list.Add(((long)h).ToString() + "|" + pid + "|" + c + "|" + t); return true; }, IntPtr.Zero); return list; } } '@ Add-Type -TypeDefinition $src function Say([string] $m) { Write-Output $m } function ProcName([int] $procId) { try { (Get-Process -Id $procId -ErrorAction Stop).ProcessName } catch { 'gone' } } function Chain([int] $procId) { $out = @(); $seen = @{}; $p = $procId for ($i = 0; $i -lt 6 -and $p -gt 0 -and -not $seen.ContainsKey($p); $i++) { $seen[$p] = 1 $ci = Get-CimInstance Win32_Process -Filter "ProcessId=$p" -ErrorAction SilentlyContinue if (-not $ci) { $out += ("pid " + $p + " gone"); break } $cl = [string]$ci.CommandLine; if ($cl.Length -gt 140) { $cl = $cl.Substring(0, 140) + '...' } $out += ($ci.Name + " pid " + $p + " [" + $cl + "]") $p = $ci.ParentProcessId } return ($out -join ' <- ') } $me = [System.Diagnostics.Process]::GetCurrentProcess() $id = [Security.Principal.WindowsIdentity]::GetCurrent() $admin = (New-Object Security.Principal.WindowsPrincipal($id)).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) Say ("RESULT elevated: " + $admin + " user " + $id.Name + " session " + $me.SessionId + " chain " + (Chain $me.Id)) $hwnd = [IgWin3]::GetConsoleWindow() $cls = '' if ($hwnd -ne [IntPtr]::Zero) { $sb = New-Object System.Text.StringBuilder 256; [void][IgWin3]::GetClassName($hwnd, $sb, 256); $cls = $sb.ToString() } $vis = if ($hwnd -ne [IntPtr]::Zero) { [IgWin3]::IsWindowVisible($hwnd) } else { 'no window' } Say ("RESULT self-console: hwnd " + $hwnd + " class [" + $cls + "] visible " + $vis) # the hosts that serve this process: a conhost with this pid as parent (classic), or an OpenConsole + WindowsTerminal # pair started by svchost in the last seconds (the default-terminal handoff) $since = (Get-Date).AddSeconds(-20) foreach ($h in @(Get-CimInstance Win32_Process -Filter "Name='conhost.exe' OR Name='OpenConsole.exe' OR Name='WindowsTerminal.exe'" -ErrorAction SilentlyContinue)) { $created = try { [Management.ManagementDateTimeConverter]::ToDateTime($h.CreationDate) } catch { $null } if ($h.ParentProcessId -eq $me.Id -or ($created -and $created -gt $since)) { Say ("RESULT host: " + $h.Name + " pid " + $h.ProcessId + " parent " + (ProcName $h.ParentProcessId) + " started " + $(if ($created) { $created.ToUniversalTime().ToString('HH:mm:ss') } else { '?' }) + " cmd " + $h.CommandLine) } } $wins = @([IgWin3]::Visible() | Where-Object { $f = $_.Split('|', 4); $f[2] -eq 'CASCADIA_HOSTING_WINDOW_CLASS' -or $f[2] -eq 'ConsoleWindowClass' -or $f[2] -eq 'PseudoConsoleWindow' }) Say ("RESULT console-windows-now: " + $wins.Count) foreach ($w in $wins) { $f = $w.Split('|', 4); Say ("RESULT window: " + (ProcName ([int]$f[1])) + " pid " + $f[1] + " [" + $f[2] + "] " + $f[3]) } # a child the elevated script starts the way the sweep helper and the power cap do (cmd, inherited console), watched $before = @{}; foreach ($w in [IgWin3]::Visible()) { $before[$w.Split('|', 4)[0]] = 1 } $p = Start-Process -FilePath cmd.exe -ArgumentList '/c ping -n 3 127.0.0.1 >nul' -NoNewWindow -PassThru $seen = @{} for ($i = 0; $i -lt 30; $i++) { foreach ($w in [IgWin3]::Visible()) { $f = $w.Split('|', 4); if (-not $before.ContainsKey($f[0]) -and -not $seen.ContainsKey($f[0])) { $seen[$f[0]] = (ProcName ([int]$f[1])) + " pid " + $f[1] + " [" + $f[2] + "] " + $f[3] } } Start-Sleep -Milliseconds 100 } try { $p.WaitForExit(10000) | Out-Null } catch {} Say ("RESULT probe cmd-inherit-elevated: " + $seen.Count + " new window(s)") foreach ($s in $seen.Values) { Say ("RESULT window: " + $s + " (probe cmd-inherit-elevated)") } exit 0