skip to content
Burak Berk Keskin
Table of Contents

Overview

An acquaintance recently handed me an older Core i5 laptop running a preview build of Windows 11 that had degraded into an unusable state. The machine suffered from perpetual micro-stuttering, cursor lag, unresponsive applications, and recurring multi-second system freezes at 100% disk and kernel CPU utilization.

I wanted to run an in-depth root cause analysis remotely from my macOS workstation over the local network rather than hunched over a lagging physical keyboard. More importantly, I wanted to drive the investigation through an autonomous AI agent harness running on my Mac—having the agent inspect system telemetry, formulate hypotheses, author diagnostic probes, and apply remediations iteratively.

However, bootstrapping an interactive OpenSSH server on a machine already choking under severe I/O exhaustion triggered a servicing deadlock. To give the AI agent remote execution access without installing heavy third-party management tools or wiping the drive, I set up a lightweight outbound HTTP polling loop between a local Python control plane and PowerShell.

Here are my notes on the agentic triage architecture, the telemetry findings, the root causes, and the automated fixes that restored the machine.

Environment

The hardware and operating system profile of the target machine:

  • Hardware Platform: Casper C650 Notebook
    • CPU: Intel Core i5-8250U (4 Cores / 8 Threads, 1.60 GHz base, 3.40 GHz boost, 15W TDP)
    • Memory: 1x 8 GB Crucial DDR4-2400 SODIMM (7.65 GB usable)
    • Storage: Dahua C800A 240 GB SATA SSD (DRAM-less)
    • Graphics: Intel UHD Graphics 620 + NVIDIA GeForce 940MX (2 GB dedicated VRAM)
  • Operating System: Windows 11 Pro 64-bit (Build 10.0.26200, 24H2 Preview)
  • Operator Workstation: macOS workstation on the LAN running an AI coding agent harness and a local HTTP control plane

The Inbound SSH Trap and the Slow-Machine Paradox

The standard sysadmin reflex for remote command execution on modern Windows is enabling the built-in OpenSSH server. I hosted a small setup script on my local HTTP server to fetch and install the Windows capability:

setup_ssh.ps1
# Elevation check
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Warning "Administrator privileges required."
Start-Process powershell.exe -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs
exit
}
# 1. Install OpenSSH Server capability
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
# 2. Configure and start sshd service
Set-Service -Name sshd -StartupType 'Automatic'
Start-Service -Name sshd
# 3. Configure Windows Firewall rule for TCP 22
if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue)) {
New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
}

This ran straight into what I call the slow-machine paradox.

Between the servicing lockup, firewall considerations, and the friction of having the user type lengthy one-liners on an unresponsive keyboard, inbound SSH proved to be the wrong tool for an emergency triage.

Pivoting to an Ephemeral Outbound HTTP Agent Loop

Instead of fighting inbound access, I flipped the connection architecture into an outbound pull-and-push model. The Windows target periodically polls an HTTP endpoint on my Mac, retrieves queued PowerShell tasks, executes them locally via Invoke-Expression, and posts the output back.

This gave the AI agent on my Mac direct, decoupled execution capability over the remote target:

+------------------------------------+ +------------------------------------+
| macOS Operator | | Windows Target |
| | | |
| +----------------------------+ | | +----------------------------+ |
| | AI Agent | | | | runner.ps1 | |
| | - Authors diag/fix scripts| | | | | |
| | - Enqueues tasks | | | | - Polls every 2 seconds | |
| | - Analyzes telemetry JSON | | | | - Invokes queued payloads | |
| +--------------┬-------------+ | | | - Streams stdout/stderr | |
| | | | +----------------------------+ |
| +--------------▼-------------+ | | | |
| | server.py | | | | |
| | - task_queue.json | | | | |
| | - agent_results.json | | | | |
| +--------------┬-------------+ | | | |
| | | | | |
| | <==== POST /agent/poll ======================| |
| | ===== { action: "run", script: "..." } =====>| |
| | | (Executes task) |
| | <==== POST /agent/result ====================| |
| | ===== { status: "ok" } =====================>| |
+------------------------------------+ +------------------------------------+

This model solved every operational obstacle:

  1. Zero External Packages: It relies strictly on built-in PowerShell Invoke-RestMethod and Invoke-Expression.
  2. NAT & Firewall Transparent: Outbound HTTP requests to the local network are permitted by default by Windows Firewall; no inbound ports or listening services were needed on the laptop.
  3. Autonomous Agent Feedback Loop: The AI agent running locally on macOS could iteratively enqueue tasks, observe execution output, digest structured JSON reports, formulate diagnostic conclusions, and push remediations without manual human intervention for each command.

The Operator Control Plane

On my Mac, I ran a compact Python server implementing the poll and result endpoints:

server.py
import http.server
import json
import os
import socketserver
import time
PORT = 8000
DIRECTORY = os.path.dirname(os.path.abspath(__file__))
QUEUE_FILE = os.path.join(DIRECTORY, "task_queue.json")
RESULTS_FILE = os.path.join(DIRECTORY, "agent_results.json")
def load_queue():
if os.path.exists(QUEUE_FILE):
try:
with open(QUEUE_FILE, "r") as f:
return json.load(f)
except Exception:
return []
return []
def save_queue(queue):
with open(QUEUE_FILE, "w") as f:
json.dump(queue, f, indent=2)
class AgentServer(http.server.SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=DIRECTORY, **kwargs)
def do_POST(self):
content_length = int(self.headers.get("Content-Length", 0))
post_data = self.rfile.read(content_length)
if self.path == "/agent/poll":
queue = load_queue()
if queue:
task = queue.pop(0)
save_queue(queue)
response = {
"action": "run",
"name": task.get("name", "task"),
"script_url": task.get("script_url", ""),
"command": task.get("command", "")
}
else:
response = {"action": "idle", "sleep": 2}
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(json.dumps(response).encode("utf-8"))
elif self.path == "/agent/result":
try:
data = json.loads(post_data.decode("utf-8", errors="ignore"))
except Exception:
data = {"raw": post_data.decode("utf-8", errors="ignore")}
print(f"\n[AGENT RESULT] Task: {data.get('name')}\n{data.get('output', '')}\n", flush=True)
with open(RESULTS_FILE, "a") as f:
f.write(json.dumps({"timestamp": time.time(), "result": data}) + "\n")
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(b'{"status":"ok"}')
elif self.path.startswith("/report"):
filename = "report_deep.json" if "deep" in self.path else "report.json"
report_path = os.path.join(DIRECTORY, filename)
with open(report_path, "wb") as f:
f.write(post_data)
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(b'{"status":"received"}')
else:
self.send_response(404)
self.end_headers()
class ReusableTCPServer(socketserver.TCPServer):
allow_reuse_address = True
if __name__ == "__main__":
with ReusableTCPServer(("0.0.0.0", PORT), AgentServer) as httpd:
print(f"Agent Server listening on 0.0.0.0:{PORT}", flush=True)
httpd.serve_forever()

The Target Client Runner

To bootstrap the agent loop on the laptop, only a single one-liner was executed in an elevated PowerShell window:

PowerShell
# Replace with the operator workstation IP on the LAN
irm http://192.168.1.50:8000/runner.ps1 | iex

The runner script loops indefinitely, polling the control plane and streaming back standard output and errors:

runner.ps1
$ProgressPreference = 'SilentlyContinue'
$ServerUrl = "http://192.168.1.50:8000"
Write-Host "[+] Agent runner active." -ForegroundColor Green
Write-Host "[+] Polling operator server at $ServerUrl" -ForegroundColor Cyan
while ($true) {
try {
$body = @{
ComputerName = $env:COMPUTERNAME
UserName = $env:USERNAME
Time = (Get-Date).ToString("s")
} | ConvertTo-Json
$resp = Invoke-RestMethod -Uri "$ServerUrl/agent/poll" -Method Post -Body $body -ContentType "application/json; charset=utf-8" -TimeoutSec 10
if ($resp.action -eq "run") {
Write-Host "`n[*] Task received: $($resp.name)" -ForegroundColor Cyan
$output = ""
try {
if ($resp.script_url) {
$scriptContent = Invoke-RestMethod -Uri "$ServerUrl/$($resp.script_url)"
$output = Invoke-Expression $scriptContent *>&1 | Out-String
} elseif ($resp.command) {
$output = Invoke-Expression $resp.command *>&1 | Out-String
}
} catch {
$output = "ERROR: $($_.Exception.Message)`n$($_.ScriptStackTrace)"
}
$resultPayload = @{
name = $resp.name
output = $output
} | ConvertTo-Json -Depth 3
Invoke-RestMethod -Uri "$ServerUrl/agent/result" -Method Post -Body $resultPayload -ContentType "application/json; charset=utf-8" -TimeoutSec 10 | Out-Null
} elseif ($resp.action -eq "done") {
Write-Host "[*] Execution complete. Exiting loop." -ForegroundColor Green
break
} else {
Start-Sleep -Seconds ($resp.sleep)
}
} catch {
Write-Host "." -NoNewline -ForegroundColor DarkGray
Start-Sleep -Seconds 3
}
}

The Autonomous Telemetry and Diagnostic Loop

With the target runner polling for work, the AI agent on macOS took over the diagnostic loop. The agent authored a reconnaissance payload (diag.ps1), placed it in the server directory, and enqueued the task in task_queue.json to dump hardware counters, processes, disk health, and Windows system events:

diag.ps1
$ProgressPreference = 'SilentlyContinue'
$report = [ordered]@{}
# 1. OS and Memory
$cs = Get-CimInstance Win32_ComputerSystem
$os = Get-CimInstance Win32_OperatingSystem
$report['System'] = [ordered]@{
Manufacturer = $cs.Manufacturer
Model = $cs.Model
TotalPhysicalRAM_GB = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2)
FreePhysicalRAM_GB = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
OSName = $os.Caption
OSVersion = $os.Version
}
# 2. CPU Frequency and Load
$cpus = Get-CimInstance Win32_Processor
$report['CPU'] = $cpus | ForEach-Object {
[ordered]@{
Name = $_.Name
Cores = $_.NumberOfCores
LogicalProcessors = $_.NumberOfLogicalProcessors
MaxClockSpeed_MHz = $_.MaxClockSpeed
CurrentClockSpeed_MHz = $_.CurrentClockSpeed
LoadPercentage = $_.LoadPercentage
}
}
# 3. Storage Hardware
$report['PhysicalDisks'] = Get-PhysicalDisk | ForEach-Object {
[ordered]@{
DeviceId = $_.DeviceId
FriendlyName = $_.FriendlyName
MediaType = $_.MediaType
BusType = $_.BusType
Size_GB = [math]::Round($_.Size / 1GB, 2)
HealthStatus = $_.HealthStatus
OperationalStatus = $_.OperationalStatus
}
}
# 4. Top Resource Consumers
$report['TopCPUProcesses'] = Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 | ForEach-Object {
[ordered]@{ Name = $_.ProcessName; Id = $_.Id; CPU = [math]::Round($_.CPU, 2); WorkingSet_MB = [math]::Round($_.WorkingSet64 / 1MB, 2) }
}
$report['TopMemoryProcesses'] = Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 10 | ForEach-Object {
[ordered]@{ Name = $_.ProcessName; Id = $_.Id; WorkingSet_MB = [math]::Round($_.WorkingSet64 / 1MB, 2) }
}
# 5. Event Log Analysis (WHEA and storage errors over the last 48 hours)
$since = (Get-Date).AddDays(-2)
$report['HardwareEvents'] = Get-WinEvent -FilterHashtable @{
LogName = 'System'; Level = 1, 2, 3; StartTime = $since
} -MaxEvents 50 -ErrorAction SilentlyContinue | Where-Object {
$_.ProviderName -match 'disk|WHEA|Kernel-Power|storahci'
} | Select-Object -First 10 | ForEach-Object {
[ordered]@{ TimeCreated = $_.TimeCreated.ToString('s'); ProviderName = $_.ProviderName; Id = $_.Id; Message = ($_.Message -split "`r?`n")[0] }
}
$json = $report | ConvertTo-Json -Depth 5
Invoke-RestMethod -Uri "http://192.168.1.50:8000/report" -Method Post -Body $json -ContentType "application/json; charset=utf-8"

Root Cause Analysis

When the target posted report.json back to the control plane, the AI agent digested the structured telemetry and pinpointed three distinct bottlenecks acting concurrently:

1. PCIe Correctable Error Storm (WHEA Event ID 17)

The Windows System event log was flooded with continuous entries from Microsoft-Windows-WHEA-Logger with Event ID 17 (“A corrected hardware error has occurred”).

The laptop houses dual graphics: an integrated Intel UHD 620 and a discrete NVIDIA GeForce 940MX. On Casper OEM motherboards, PCI Express Active State Power Management (ASPM / Link State Power Management) fails to synchronize packets cleanly when the discrete GPU toggles between low-power link states (L0s/L1) and active mode.

While the error is marked “corrected”, each occurrence fires a hardware interrupt. The Windows kernel traps the interrupt, retransmits the dropped packet, and logs the event. This constant loop created an interrupt storm:

  • The kernel process System (PID 4) had accumulated 4,471 CPU seconds of execution time.
  • The machine suffered from continuous cursor micro-stuttering and lag even when no user applications were open.

2. Physical Memory Exhaustion and Paging Pressure

Out of 7.65 GB usable RAM, the machine had only 1.52 GB free at idle (an 80.1% baseline memory commit).

The culprits were a mix of background bloat and memory leaks:

  • svchost.exe (PID 3012): 512 MB
  • PhoneExperienceHost.exe (Windows Phone Link): 427 MB
  • MsMpEng.exe (Windows Defender): 298 MB
  • explorer.exe: 281 MB
  • Background Autostart Items: Microsoft Teams, OneDrive, Adobe Acrobat Synchronizer (AdobeCollabSync.exe), Microsoft Edge AutoLaunch, and four separate Realtek audio helper binaries (RAVBg64.exe).

With only 1.5 GB of headroom, opening even two or three browser tabs forced Windows into hard page faults, swapping memory back and forth to disk.

3. DRAM-Less SATA SSD Queue Saturation

The drive installed was a Dahua C800A 240 GB SATA SSD.

The C800A is a budget DRAM-less solid-state drive. Without dedicated DRAM cache to hold its Flash Translation Layer (FTL) mapping table in fast memory, random 4K write operations introduce significant controller latency. When MsMpEng.exe (file scanning), SearchIndexer.exe, TiWorker.exe, and SysMain (Superfetch attempting to prefetch binaries into an already constrained RAM) fired concurrent random write requests alongside virtual memory pagefile swapping, the controller’s I/O queue backed up completely. Disk active time spiked to 100%, freezing the entire UI for seconds at a time.

Remediation

Having isolated all three mechanisms, the AI agent synthesized a unified remediation payload (fix.ps1) targeting each root cause in a single queue execution:

fix.ps1
Write-Host "[1/5] Disabling PCIe Link State Power Management (WHEA Event 17)..." -ForegroundColor Cyan
try {
# GUID 0ee12f90-76e7-4b4d-9e91-b3a2b56e0893 = Link State Power Management
# Setting index 0 = Off
powercfg /setacvalueindex SCHEME_CURRENT SUB_PCIEXPRESS 0ee12f90-76e7-4b4d-9e91-b3a2b56e0893 0
powercfg /setdcvalueindex SCHEME_CURRENT SUB_PCIEXPRESS 0ee12f90-76e7-4b4d-9e91-b3a2b56e0893 0
powercfg /setactive SCHEME_CURRENT
Write-Host "[OK] PCIe ASPM disabled." -ForegroundColor Green
} catch {
Write-Warning "Failed to set PCIe power profile: $_"
}
Write-Host "`n[2/5] Disabling disk-thrashing background services..." -ForegroundColor Cyan
$servicesToDisable = @('SysMain', 'DiagTrack')
foreach ($svc in $servicesToDisable) {
if (Get-Service -Name $svc -ErrorAction SilentlyContinue) {
Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue
Set-Service -Name $svc -StartupType Disabled
Write-Host "[OK] Service disabled: $svc" -ForegroundColor Green
}
}
Write-Host "`n[3/5] Terminating memory leaks and cleaning startup items..." -ForegroundColor Cyan
Get-Process -Name "PhoneExperienceHost", "CrossDeviceService" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
Set-Service -Name "CrossDeviceService" -StartupType Manual -ErrorAction SilentlyContinue
$runKeyPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run"
$bloatEntries = @(
'Teams',
'OneDrive',
'Adobe Acrobat Synchronizer',
'MicrosoftEdgeAutoLaunch_9EDF312A5B50E1CCDC30082229C6FF51'
)
foreach ($entry in $bloatEntries) {
if (Get-ItemProperty -Path $runKeyPath -Name $entry -ErrorAction SilentlyContinue) {
Remove-ItemProperty -Path $runKeyPath -Name $entry -ErrorAction SilentlyContinue
Write-Host "[OK] Removed autostart entry: $entry" -ForegroundColor Green
}
}
Write-Host "`n[4/5] Executing SSD TRIM optimization..." -ForegroundColor Cyan
try {
Optimize-Volume -DriveLetter C -ReTrim -Verbose -ErrorAction SilentlyContinue
Write-Host "[OK] TRIM issued to C: drive." -ForegroundColor Green
} catch {
Write-Warning "TRIM error: $_"
}

Verification and Telemetry Comparison

After the payload executed, the AI agent enqueued follow-up verification scripts (check_whea.ps1, check_cpu.ps1) to capture the delta against the baseline:

Metric Baseline (Pre-Fix) Post-Remediation Impact
Free Physical RAM 1.52 GB 2.67 GB +1.15 GB recovered (+75% free memory)
Idle CPU Load 73% 5% -68% CPU load reduction
WHEA Event 17 Errors Flooding continuously 0 errors Hardware interrupt storm eliminated
System (PID 4) Thrashing 4,471 CPU seconds Normalized to near 0% Kernel interrupt overhead resolved
SSD I/O Congestion SysMain, TiWorker, DiagTrack active Services disabled + TRIM issued Random 4K queue saturation cleared
PhoneExperienceHost 427 MB memory footprint Process killed, service manual Memory leak cleared

Disabling PCIe Link State Power Management immediately silenced the WHEA Event 17 interrupt storm. The cursor lag and UI stutters stopped instantly.

Hardware Audit and Thermal Benchmark

To verify whether the laptop had underlying hardware degradation or dried thermal paste, the AI agent enqueued an audit payload (audit.ps1) querying memory layout, SMART attributes, and thermal headroom under load.

Memory and Storage Topology

  • Memory Topology:
    • ChannelA-DIMM0: 1x 8 GB Crucial DDR4-2400 SODIMM (PartNumber: CT8G4SFS824A.C8FHD1).
    • ChannelB-DIMM0: Empty.
    • Bus Mode: Single-Channel (64-bit).
  • SSD Health:
    • Dahua C800A 240 GB SSD.
    • Wear indicator: 0% wear (100% health remaining).
    • Power-On Hours: 1,027 hours (~42 operational days).
    • Temperature: 48°C (healthy operating range).

Thermal Saturation Test

The agent subjected the CPU to a 60-second multi-threaded mathematical calculation using background PowerShell jobs (Start-Job) while sampling clock speeds and temperatures every 10 seconds:

Thermal Soak Benchmark
[Baseline] Temp: 71°C | Clock: 1600 MHz
[T + 10s] Temp: 71°C | Clock: 1600 MHz | Load: 79%
[T + 20s] Temp: 71°C | Clock: 1600 MHz | Load: 100%
[T + 30s] Temp: 71°C | Clock: 1600 MHz | Load: 100%
[T + 40s] Temp: 71°C | Clock: 1600 MHz | Load: 100%
[T + 50s] Temp: 71°C | Clock: 1600 MHz | Load: 100%
[T + 60s] Temp: 71°C | Clock: 1600 MHz | Load: 84%
Peak Temperature: 71°C

Takeaways

  1. Decoupled HTTP Loops Enable Autonomous Agentic Remediation: Pairing an AI coding agent with a decoupled HTTP pull-and-push mechanism turns the agent into a remote incident responder. The agent can inspect raw diagnostics, write tailored remediation scripts, and verify metrics across heterogeneous platforms without requiring complex SSH or remote management agents.
  2. Avoid Inbound Administrative Ports for Ad-Hoc Triage: Setting up OpenSSH, opening firewalls, and managing authentication on a crippled machine invites servicing deadlocks. A lightweight outbound HTTP polling loop over PowerShell Invoke-RestMethod bypasses inbound network blocks and requires zero target-side installation.
  3. Beware of DISM on Resource-Starved Hosts: Commands like Add-WindowsCapability spin up Windows Update servicing workers (TiWorker.exe) that exacerbate disk and RAM thrashing on already compromised systems.
  4. Hardware Interrupt Storms Mimic OS Corruption: Frequent PCIe ASPM packet errors (WHEA Event 17) silently pin the Windows kernel (System PID 4) in an interrupt-handling loop. Setting PCIe Link State Power Management to “Off” in the active power profile cuts off the storm at the source.
  5. Protect DRAM-Less SATA SSDs from Random 4K Floods: Turning off Superfetch (SysMain) and diagnostic telemetry (DiagTrack) prevents FTL queue saturation and eliminates multi-second UI freezing on budget SATA drives.
  6. Single-Channel Memory Is a Severe Constraint: Populating the second SODIMM slot to enable Dual-Channel 128-bit memory doubles available memory bandwidth and feeds both the CPU and shared integrated graphics.