# ChipRepair.ps1 # Chip Computer Helper - Repair Tool v1.0 # Double-click to run. Fixes most common Chip issues automatically. # Logs everything to C:\ComputerHelper\chip-repair.log $ErrorActionPreference = 'SilentlyContinue' $DIR = 'C:\ComputerHelper' $LOG = "$DIR\chip-repair.log" $AGENT = "$DIR\chip-agent.js" $BACKUP = "$DIR\chip-agent.bak.js" $LICENSE = "$DIR\license.key" $SERVER = 'https://helper.tekdr.net' $PORT = 9001 # -- Logging -------------------------------------------------- function Log([string]$msg, [string]$level = 'INFO') { $ts = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' $line = "[$ts] [$level] $msg" Add-Content -Path $LOG -Value $line -Encoding ASCII $color = switch ($level) { 'OK' { 'Green' } 'WARN' { 'Yellow' } 'FAIL' { 'Red' } 'FIX' { 'Cyan' } default{ 'White' } } Write-Host $line -ForegroundColor $color } function Section([string]$title) { $line = "`n--- $title ---" Write-Host $line -ForegroundColor Magenta Add-Content -Path $LOG -Value $line -Encoding ASCII } # -- Banner --------------------------------------------------- Clear-Host Write-Host '' Write-Host ' +=======================================+' -ForegroundColor Cyan Write-Host ' | Chip Computer Helper - Repair |' -ForegroundColor Cyan Write-Host ' | TekDr v1.0 |' -ForegroundColor Cyan Write-Host ' +=======================================+' -ForegroundColor Cyan Write-Host '' Write-Host ' Diagnosing and repairing Chip...' -ForegroundColor White Write-Host ' Log: C:\ComputerHelper\chip-repair.log' -ForegroundColor DarkGray Write-Host '' Add-Content -Path $LOG -Value "`n========== Chip Repair $(Get-Date) ==========" -Encoding ASCII $fixes = 0 $issues = 0 # -- 1. Install directory ------------------------------------- Section '1. Installation Directory' if (Test-Path $DIR) { Log "Directory exists: $DIR" 'OK' } else { Log "Directory missing - creating $DIR" 'FIX' New-Item -ItemType Directory -Path $DIR -Force | Out-Null $fixes++ } # -- 2. Node.js ----------------------------------------------- Section '2. Node.js' $node = Get-Command node -ErrorAction SilentlyContinue if ($node) { $ver = & node --version 2>$null Log "Node.js found: $ver at $($node.Source)" 'OK' } else { $paths = @( "$env:ProgramFiles\nodejs\node.exe", "${env:ProgramFiles(x86)}\nodejs\node.exe" ) $nodePath = $paths | Where-Object { Test-Path $_ } | Select-Object -First 1 if ($nodePath) { Log "Node.js found at $nodePath (not in PATH)" 'WARN' $issues++ } else { Log 'Node.js NOT FOUND - Chip cannot run without Node.js' 'FAIL' Log 'Download Node.js LTS from https://nodejs.org and run this repair again' 'FAIL' $issues++ } } # -- 3. Agent file -------------------------------------------- Section '3. Agent File' if (Test-Path $AGENT) { $size = (Get-Item $AGENT).Length if ($size -gt 5000) { Log "chip-agent.js OK: $([math]::Round($size/1KB))KB" 'OK' # Quick syntax check $syntaxOk = $false try { $result = & node --check $AGENT 2>&1 $syntaxOk = ($LASTEXITCODE -eq 0) } catch {} if ($syntaxOk) { Log 'Agent syntax check passed' 'OK' } else { Log 'Agent file has syntax errors!' 'FAIL' if (Test-Path $BACKUP) { Log 'Restoring from backup...' 'FIX' Copy-Item $BACKUP $AGENT -Force Log 'Restored chip-agent.js from chip-agent.bak.js' 'OK' $fixes++ } else { Log 'No backup available - downloading fresh copy...' 'FIX' try { Invoke-WebRequest "$SERVER/api/agent-update" -OutFile $AGENT -UseBasicParsing -TimeoutSec 30 Log 'Downloaded fresh agent from server' 'OK' $fixes++ } catch { Log "Download failed: $_" 'FAIL' $issues++ } } } } else { Log "chip-agent.js is too small ($size bytes) - likely corrupted" 'FAIL' $issues++ if (Test-Path $BACKUP) { Copy-Item $BACKUP $AGENT -Force Log 'Restored from backup' 'FIX' $fixes++ } else { try { Invoke-WebRequest "$SERVER/api/agent-update" -OutFile $AGENT -UseBasicParsing -TimeoutSec 30 Log 'Downloaded fresh agent from server' 'FIX' $fixes++ } catch { Log "Could not download: $_" 'FAIL'; $issues++ } } } } else { Log 'chip-agent.js NOT FOUND' 'FAIL' $issues++ try { Log 'Downloading chip-agent.js from server...' 'FIX' Invoke-WebRequest "$SERVER/api/agent-update" -OutFile $AGENT -UseBasicParsing -TimeoutSec 30 Log 'Downloaded chip-agent.js OK' 'OK' $fixes++ } catch { Log "Download failed: $_" 'FAIL' $issues++ } } # -- 4. Supporting files -------------------------------------- Section '4. Supporting Files' $supportFiles = @{ 'ChipTray.ps1' = '/api/tray-update' 'ChipWatchdog.ps1'= '/api/watchdog-update' 'chip-start.ps1' = '/api/chipstart-update' 'chip-sentinel.js'= '/api/sentinel-update' } foreach ($file in $supportFiles.GetEnumerator()) { $filePath = "$DIR\$($file.Key)" if (Test-Path $filePath) { $sz = (Get-Item $filePath).Length if ($sz -gt 500) { Log "$($file.Key): OK ($sz bytes)" 'OK' } else { Log "$($file.Key): too small, re-downloading" 'WARN' try { Invoke-WebRequest "$SERVER$($file.Value)" -OutFile $filePath -UseBasicParsing -TimeoutSec 15 Log "$($file.Key): re-downloaded OK" 'FIX' $fixes++ } catch { Log "Could not re-download $($file.Key): $_" 'FAIL'; $issues++ } } } else { Log "$($file.Key): MISSING - downloading..." 'WARN' try { Invoke-WebRequest "$SERVER$($file.Value)" -OutFile $filePath -UseBasicParsing -TimeoutSec 15 Log "$($file.Key): downloaded OK" 'FIX' $fixes++ } catch { Log "Could not download $($file.Key): $_" 'FAIL'; $issues++ } } } # -- 5. License key ------------------------------------------- Section '5. License Key' if (Test-Path $LICENSE) { $key = Get-Content $LICENSE -Raw -ErrorAction SilentlyContinue if ($key -and $key.Trim().StartsWith('chip_')) { Log "License key present: $($key.Trim().Substring(0, 12))..." 'OK' } else { Log 'License key file exists but appears invalid' 'WARN' $issues++ } } else { Log 'License key file missing - you may need to re-enter your license' 'WARN' $issues++ } # -- 6. Port 9001 --------------------------------------------- Section '6. Port 9001' $portInUse = netstat -ano 2>$null | Select-String ":$PORT\s" if ($portInUse) { # Check if it's our own agent $nodeProcs = Get-Process -Name node -ErrorAction SilentlyContinue if ($nodeProcs) { Log "Port $PORT in use by Node.js (PID: $($nodeProcs.Id -join ',')) - agent running" 'OK' } else { Log "Port $PORT is in use by a non-Node process - possible conflict" 'WARN' $issues++ $pids = $portInUse | ForEach-Object { ($_ -split '\s+')[-1] } | Select-Object -Unique foreach ($pid in $pids) { $proc = Get-Process -Id $pid -ErrorAction SilentlyContinue if ($proc) { Log " Port held by: $($proc.Name) (PID $pid)" 'WARN' } } } } else { Log "Port $PORT is free - agent is not running" 'WARN' $issues++ } # -- 7. Firewall ---------------------------------------------- Section '7. Firewall' $loopbackRules = Get-NetFirewallRule -DisplayName "*Chip*" -ErrorAction SilentlyContinue if ($loopbackRules) { Log "Chip firewall rules found: $($loopbackRules.Count)" 'OK' } else { Log 'No Chip firewall rule found - creating loopback rule...' 'FIX' try { New-NetFirewallRule -DisplayName 'Chip Local Agent' ` -Direction Inbound ` -Action Allow ` -Protocol TCP ` -LocalPort 9001 ` -Profile Private,Domain ` -Program "$env:ProgramFiles\nodejs\node.exe" ` -ErrorAction Stop | Out-Null Log 'Firewall rule created for port 9001' 'OK' $fixes++ } catch { Log "Could not create firewall rule (non-critical): $_" 'WARN' } } # -- 8. Scheduled Tasks --------------------------------------- Section '8. Scheduled Tasks' $tasks = @('ChipAgent', 'ChipWatchdog') $ps = "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" $node = (Get-Command node -ErrorAction SilentlyContinue).Source foreach ($taskName in $tasks) { $task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue if ($task) { $state = $task.State Log " $taskName`: $state" 'OK' if ($state -eq 'Disabled') { Enable-ScheduledTask -TaskName $taskName | Out-Null Log " $taskName`: re-enabled" 'FIX' $fixes++ } } else { Log " $taskName`: MISSING - re-creating..." 'WARN' $issues++ try { switch ($taskName) { 'ChipAgent' { if ($node) { $action = New-ScheduledTaskAction -Execute $node -Argument $AGENT -WorkingDirectory $DIR $trigger = New-ScheduledTaskTrigger -AtLogOn $settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hours 0) -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) -MultipleInstances IgnoreNew $principal = New-ScheduledTaskPrincipal -GroupId 'BUILTIN\Users' -RunLevel Highest Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Force | Out-Null Log " $taskName`: re-created" 'FIX' $fixes++ } } 'ChipWatchdog' { $action = New-ScheduledTaskAction -Execute $ps -Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$DIR\ChipWatchdog.ps1`"" -WorkingDirectory $DIR $trigger = New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 5) -Once -At (Get-Date) $settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hours 0) -MultipleInstances IgnoreNew $principal = New-ScheduledTaskPrincipal -GroupId 'BUILTIN\Users' -RunLevel Highest Register-ScheduledTask -TaskName $taskName -TaskPath '\Chip\' -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Force | Out-Null Log " \Chip\$taskName`: re-created" 'FIX' $fixes++ } } } catch { Log " Could not re-create $taskName`: $_" 'FAIL'; $issues++ } } } try { Get-ScheduledTask -TaskName 'ChipTray' -ErrorAction SilentlyContinue | ForEach-Object { Unregister-ScheduledTask -TaskName $_.TaskName -TaskPath $_.TaskPath -Confirm:$false -ErrorAction SilentlyContinue } Log ' Legacy ChipTray scheduled task: removed if present' 'FIX' } catch {} try { $trayScript = "$DIR\ChipTray.ps1" $trayPsArgs = "-NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$trayScript`"" $conhost = "$env:SystemRoot\System32\conhost.exe" $headlessConhostAvailable = $false if (Test-Path $conhost) { try { $probe = Start-Process -FilePath $conhost -ArgumentList @('--headless', $ps, '-NoLogo', '-NoProfile', '-NonInteractive', '-Command', 'exit 0') -Wait -PassThru -WindowStyle Hidden $headlessConhostAvailable = ($probe.ExitCode -eq 0) } catch { $headlessConhostAvailable = $false } } if ($headlessConhostAvailable) { $action = New-ScheduledTaskAction -Execute $conhost -Argument "--headless `"$ps`" $trayPsArgs" -WorkingDirectory $DIR $trayLaunchMode = 'conhost-headless' } else { $action = New-ScheduledTaskAction -Execute $ps -Argument $trayPsArgs -WorkingDirectory $DIR $trayLaunchMode = 'powershell-direct-fallback' } $trigger = New-ScheduledTaskTrigger -AtLogOn $trigger.Delay = 'PT8S' $settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hours 0) -MultipleInstances IgnoreNew -StartWhenAvailable $principal = New-ScheduledTaskPrincipal -GroupId 'BUILTIN\Users' -RunLevel Limited Register-ScheduledTask -TaskName 'ChipTrayUserLogon' -TaskPath '\Chip\' -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Description 'Chip tray icon user-session launcher' -Force | Out-Null Log " ChipTrayUserLogon: ensured user-session tray launch task ($trayLaunchMode)" 'FIX' } catch { Log " Could not ensure ChipTrayUserLogon: $_" 'WARN' } try { $sentinelScript = "$DIR\chip-sentinel.js" $runtimeNode = "$DIR\runtime\node.exe" $sentinelNode = $null if (Test-Path -LiteralPath $runtimeNode) { $sentinelNode = $runtimeNode } if (-not $sentinelNode -and (Test-Path -LiteralPath "$env:ProgramFiles\nodejs\node.exe")) { $sentinelNode = "$env:ProgramFiles\nodejs\node.exe" } if (-not $sentinelNode) { $cmd = Get-Command node.exe -ErrorAction SilentlyContinue if ($cmd -and $cmd.Source -and (Test-Path -LiteralPath $cmd.Source)) { $sentinelNode = $cmd.Source } } if (-not (Test-Path -LiteralPath $sentinelScript)) { throw "Missing $sentinelScript" } if (-not $sentinelNode) { throw 'node.exe not found' } $action = New-ScheduledTaskAction -Execute $sentinelNode -Argument "`"$sentinelScript`"" -WorkingDirectory $DIR $trigger = New-ScheduledTaskTrigger -AtStartup $settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hours 0) -RestartCount 5 -RestartInterval (New-TimeSpan -Minutes 2) -MultipleInstances IgnoreNew -StartWhenAvailable $principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest Register-ScheduledTask -TaskName 'ChipSentinel' -TaskPath '\Chip\' -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Description 'Chip always-on system monitor: runs as SYSTEM from boot, no user session required' -Force | Out-Null Log " ChipSentinel: ensured using $sentinelNode $sentinelScript" 'FIX' } catch { Log " Could not ensure ChipSentinel: $_" 'WARN' } # -- 9. Leftover staging files -------------------------------- Section '9. Cleanup' $stagingFile = "$DIR\chip-agent.staging.js" if (Test-Path $stagingFile) { Remove-Item $stagingFile -Force Log 'Removed leftover staging file' 'FIX' $fixes++ } else { Log 'No staging files to clean up' 'OK' } $restartFlag = "$DIR\chip-restart.flag" if (Test-Path $restartFlag) { Remove-Item $restartFlag -Force Log 'Removed restart flag' 'FIX' } # -- 10. Restart agent ---------------------------------------- Section '10. Restarting Chip' Log 'Stopping any running agent processes...' 'INFO' Get-Process -Name node -ErrorAction SilentlyContinue | Where-Object { $_.MainModule.FileName -like '*node*' } | Stop-Process -Force -ErrorAction SilentlyContinue Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like '*ChipTray*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue } Start-Sleep -Seconds 2 Log 'Starting ChipAgent...' 'FIX' Start-ScheduledTask -TaskName 'ChipAgent' -ErrorAction SilentlyContinue Start-Sleep -Seconds 5 # Verify it started $nodeRunning = Get-Process -Name node -ErrorAction SilentlyContinue if ($nodeRunning) { Log "Agent started successfully (PID: $($nodeRunning.Id))" 'OK' $fixes++ # Test health endpoint Start-Sleep -Seconds 3 try { $h = Invoke-WebRequest 'http://localhost:9001/health' -UseBasicParsing -TimeoutSec 5 $data = $h.Content | ConvertFrom-Json -ErrorAction SilentlyContinue if ($data.ok) { Log "Health check PASSED - Agent v$($data.version) responding" 'OK' } } catch { Log "Health check failed (may still be starting): $_" 'WARN' } } else { Log 'Agent did not start - check chip-maintenance.log for details' 'FAIL' $issues++ } Log 'Starting ChipTray...' 'FIX' # Clear cached icon so tray picks up fresh version Remove-Item "$DIR\chip-icon-48.png" -Force -ErrorAction SilentlyContinue $trayScript = "$DIR\ChipTray.ps1" if (Test-Path $trayScript) { Start-ScheduledTask -TaskName 'ChipTrayUserLogon' -TaskPath '\Chip\' -ErrorAction SilentlyContinue } # -- Summary -------------------------------------------------- Section 'Summary' Log "Issues found: $issues" 'INFO' Log "Fixes applied: $fixes" 'INFO' Write-Host '' if ($issues -eq 0) { Write-Host ' OK Everything looks good!' -ForegroundColor Green } elseif ($fixes -ge $issues) { Write-Host " OK Fixed $fixes issue(s) automatically." -ForegroundColor Green Write-Host ' Chip should be working now.' -ForegroundColor Green } else { Write-Host " ! Fixed $fixes issue(s), but $($issues - $fixes) could not be fixed automatically." -ForegroundColor Yellow Write-Host ' Review chip-repair.log for details.' -ForegroundColor Yellow Write-Host ' Contact support@tekdr.net if the issue continues.' -ForegroundColor White } Write-Host '' Write-Host ' Log saved to: C:\ComputerHelper\chip-repair.log' -ForegroundColor DarkGray Write-Host '' # Open Chip $openChip = Read-Host ' Open Chip now? (Y/N)' if ($openChip -eq 'Y' -or $openChip -eq 'y') { Start-Process 'https://helper.tekdr.net' }