# UI enumeration — dumps every window + every clickable control visible at OOBE $ErrorActionPreference = 'SilentlyContinue' Add-Type -AssemblyName UIAutomationClient Add-Type -AssemblyName UIAutomationTypes $report = [ordered]@{} $report.ts = (Get-Date -Format o) $report.sn = (Get-CimInstance Win32_BIOS).SerialNumber $report.phase = 'ui-enum' $root = [System.Windows.Automation.AutomationElement]::RootElement $report.screen = @{ width = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Width height = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Height } 2>$null # Enumerate top-level windows $windowCond = New-Object System.Windows.Automation.PropertyCondition([System.Windows.Automation.AutomationElement]::ControlTypeProperty, [System.Windows.Automation.ControlType]::Window) $windows = $root.FindAll([System.Windows.Automation.TreeScope]::Children, $windowCond) $report.windows = @() foreach ($w in $windows) { $wInfo = [ordered]@{ name = $w.Current.Name className = $w.Current.ClassName processId = $w.Current.ProcessId automationId = $w.Current.AutomationId isVisible = -not $w.Current.IsOffscreen bounds = "$($w.Current.BoundingRectangle)" children = @() } # Try to get process name try { $wInfo.processName = (Get-Process -Id $w.Current.ProcessId -ErrorAction Stop).ProcessName } catch { $wInfo.processName = '?' } # Enumerate descendants — buttons, hyperlinks, text, edit fields $types = @( [System.Windows.Automation.ControlType]::Button, [System.Windows.Automation.ControlType]::Hyperlink, [System.Windows.Automation.ControlType]::Edit, [System.Windows.Automation.ControlType]::Text, [System.Windows.Automation.ControlType]::ListItem, [System.Windows.Automation.ControlType]::CheckBox ) foreach ($t in $types) { $c = New-Object System.Windows.Automation.PropertyCondition([System.Windows.Automation.AutomationElement]::ControlTypeProperty, $t) $elems = $w.FindAll([System.Windows.Automation.TreeScope]::Descendants, $c) foreach ($e in $elems) { if ($e.Current.IsOffscreen) { continue } $name = $e.Current.Name if ([string]::IsNullOrWhiteSpace($name) -and [string]::IsNullOrWhiteSpace($e.Current.AutomationId)) { continue } $wInfo.children += [ordered]@{ type = "$t".Split('.')[-1] name = if ($name) { $name.Substring(0,[Math]::Min(150,$name.Length)) } else { '' } automationId = $e.Current.AutomationId className = $e.Current.ClassName enabled = $e.Current.IsEnabled bounds = "$($e.Current.BoundingRectangle)" } } } $report.windows += $wInfo } # Also dump foreground window specifically $foregroundSig = '[DllImport("user32.dll")]public static extern System.IntPtr GetForegroundWindow();' $fg = Add-Type -MemberDefinition $foregroundSig -Name FG -Namespace W -PassThru $hwnd = $fg::GetForegroundWindow() try { $fgElem = [System.Windows.Automation.AutomationElement]::FromHandle($hwnd) $report.foreground = [ordered]@{ name = $fgElem.Current.Name className = $fgElem.Current.ClassName processId = $fgElem.Current.ProcessId } } catch { $report.foreground = "lookup failed: $_" } # Check if PPD registry trigger exists $ppdKeys = @( 'HKLM:\SOFTWARE\Microsoft\Provisioning\AutopilotSettings', 'HKLM:\SOFTWARE\Microsoft\Provisioning\CommercialOOBE', 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\OobeBackground' ) $report.ppdRegistry = @{} foreach ($k in $ppdKeys) { $v = Get-ItemProperty -Path $k -ErrorAction SilentlyContinue if ($v) { $props = @{} $v.PSObject.Properties | Where-Object { $_.Name -notlike 'PS*' } | ForEach-Object { $val = $_.Value if ($val -is [byte[]]) { $val = "" } $props[$_.Name] = $val } $report.ppdRegistry[$k] = $props } } # Check running processes related to OOBE $report.oobeProcs = @(Get-Process | Where-Object { $_.ProcessName -match 'CloudExperienceHost|WWAHost|LogonUI|UserOOBEBroker|msoobe|setupshell' } | ForEach-Object { [ordered]@{ name = $_.ProcessName; id = $_.Id; title = $_.MainWindowTitle } }) # Test PPD URI handlers (don't actually launch — just check if registered) $report.uriHandlers = @{} foreach ($uri in @('ms-cxh','ms-contact-support','ms-settings')) { try { $report.uriHandlers[$uri] = [bool](Get-Item "HKCR:\$uri" -ErrorAction Stop) } catch { $report.uriHandlers[$uri] = $false } } Write-Host "" Write-Host "=== UI Enumeration ===" -ForegroundColor Cyan Write-Host ("Windows found: {0}" -f $report.windows.Count) -ForegroundColor White Write-Host ("Foreground: {0}" -f $report.foreground.className) -ForegroundColor White foreach ($w in $report.windows) { Write-Host (" [{0}] {1} ({2}) - {3} children" -f $w.processName, $w.name, $w.className, $w.children.Count) -ForegroundColor Gray foreach ($c in $w.children | Select-Object -First 8) { Write-Host (" {0}: '{1}' (id={2})" -f $c.type, $c.name, $c.automationId) -ForegroundColor DarkGray } } # POST try { $body = @{hostname=$env:COMPUTERNAME; ip=((Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.IPAddress -notlike '169.*' -and $_.IPAddress -ne '127.0.0.1'} | Select-Object -First 1).IPAddress); data=($report | ConvertTo-Json -Depth 8 -Compress)} | ConvertTo-Json -Compress Invoke-RestMethod -Uri 'https://mkl.techtoschool.com/p/report' -Method POST -ContentType 'application/json' -Body $body -TimeoutSec 15 | Out-Null Write-Host "" Write-Host "UI enum POSTed to MKL." -ForegroundColor Green } catch { Write-Host ("POST failed: {0}" -f $_.Exception.Message) -ForegroundColor Red }