# Status panel remote access for NA Ingest - run ONCE on each Windows PC # (OBS PC, Lighting PC, Bible TV PC), logged in as the normal user. # # 1. Save this file as C:\Users\\windows-setup.ps1 # 2. Start menu -> type PowerShell -> right-click -> Run as administrator # 3. Set-ExecutionPolicy RemoteSigned -Scope CurrentUser (answer Y; once per PC) # 4. Run it: & "$env:USERPROFILE\windows-setup.ps1" # 5. Send the "RESULT" block it prints back to Claude. If it says RESTART THIS PC, # restart, then repeat steps 2 and 4. # # It turns on Windows' built-in SSH server, lets NA Ingest log in with its key # (no password), and creates "start" tasks for the apps it finds (OBS, Resolume # Arena, rtpMIDI, the Bible app). The tasks start the app on this desktop, which # a plain SSH command cannot do on Windows. Safe to run more than once. $ErrorActionPreference = 'Stop' $Key = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHM2BPUpVpbMxKumLayVSutUsFWUXEfJ/4vxIJ0thbgY status-panel@NA-Ingest' $IngestIPs = @('10.1.1.1', '10.6.3.222') # NA Ingest on the 10.1 and 10.6 networks $notes = @() # 1. OpenSSH Server, started now and at every boot, allowed through the firewall $cap = Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Server*' | Select-Object -First 1 if (-not $cap) { throw 'This Windows has no OpenSSH Server feature to install - send this message to Claude.' } $restart = $false if ($cap.State -ne 'Installed') { Write-Host 'Installing the OpenSSH Server (Windows downloads it - this can take 10 minutes)...' $restart = [bool](Add-WindowsCapability -Online -Name $cap.Name).RestartNeeded } if (-not (Get-Service sshd -ErrorAction SilentlyContinue)) { $state = (Get-WindowsCapability -Online -Name $cap.Name).State Write-Host '' Write-Host '===== RESULT (send this to Claude) =====' Write-Host ('pc=' + $env:COMPUTERNAME + ' sshd=missing openssh=' + $state + ' restart_needed=' + $restart) Write-Host 'RESTART THIS PC, then run this script again.' Write-Host '========================================' return } Set-Service -Name sshd -StartupType Automatic Start-Service sshd if (-not (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 | Out-Null } # Windows' own rule covers "Private" networks only; open it on any network, but to NA Ingest alone. Set-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -Profile Any -RemoteAddress $IngestIPs Enable-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' # 2. NA Ingest's key. Administrators read C:\ProgramData\ssh\administrators_authorized_keys, # everyone else their own .ssh\authorized_keys - write both. $adminKeys = Join-Path $env:ProgramData 'ssh\administrators_authorized_keys' if (-not (Test-Path $adminKeys) -or -not (Select-String -Path $adminKeys -SimpleMatch 'status-panel@NA-Ingest' -Quiet)) { Add-Content -Path $adminKeys -Value $Key -Encoding ascii } icacls $adminKeys /inheritance:r /grant '*S-1-5-32-544:F' /grant '*S-1-5-18:F' | Out-Null $userSsh = Join-Path $env:USERPROFILE '.ssh' New-Item -ItemType Directory -Force -Path $userSsh | Out-Null $userKeys = Join-Path $userSsh 'authorized_keys' if (-not (Test-Path $userKeys) -or -not (Select-String -Path $userKeys -SimpleMatch 'status-panel@NA-Ingest' -Quiet)) { Add-Content -Path $userKeys -Value $Key -Encoding ascii } # 3. Start tasks for the apps found on this PC (they run on this user's desktop) function Find-First($candidates) { foreach ($c in $candidates) { if ($c -and (Test-Path $c)) { return (Resolve-Path $c).Path } } return $null } $roots = @($env:ProgramFiles, ${env:ProgramFiles(x86)}, (Join-Path $env:LOCALAPPDATA 'Programs')) | Where-Object { $_ } $bible = Get-ChildItem -Path $roots -Filter '*.exe' -Recurse -Depth 3 -ErrorAction SilentlyContinue | Where-Object { $_.FullName -match 'bible' -and $_.Name -notmatch 'uninst|update|crash|helper' } | Select-Object -First 1 -ExpandProperty FullName $apps = @( @{ Name = 'OBS'; Exe = (Find-First @("$env:ProgramFiles\obs-studio\bin\64bit\obs64.exe")); Args = '--disable-shutdown-check' }, @{ Name = 'Arena'; Exe = (Find-First (Get-ChildItem "$env:ProgramFiles\Resolume Arena*\Arena.exe" -ErrorAction SilentlyContinue | ForEach-Object FullName)); Args = '' }, @{ Name = 'rtpMIDI'; Exe = (Find-First @("${env:ProgramFiles(x86)}\Tobias Erichsen\rtpMIDI\rtpMIDI.exe", "$env:ProgramFiles\Tobias Erichsen\rtpMIDI\rtpMIDI.exe")); Args = '' }, @{ Name = 'BibleApp'; Exe = $bible; Args = '' } ) $principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" -LogonType Interactive -RunLevel Limited $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries ` -ExecutionTimeLimit ([TimeSpan]::Zero) -MultipleInstances IgnoreNew $tasks = @() foreach ($app in $apps) { if (-not $app.Exe) { continue } $actionArgs = @{ Execute = $app.Exe; WorkingDirectory = (Split-Path $app.Exe) } if ($app.Args) { $actionArgs.Argument = $app.Args } $action = New-ScheduledTaskAction @actionArgs Register-ScheduledTask -TaskPath '\StatusPanel\' -TaskName ('Start ' + $app.Name) -Action $action ` -Principal $principal -Settings $settings -Force | Out-Null $tasks += ('{0} = {1}' -f $app.Name, $app.Exe) } # 4. Wake-on-LAN: let the wired adapter wake the PC (the BIOS setting must be on too) $nics = Get-NetAdapter -Physical -ErrorAction SilentlyContinue | Where-Object Status -eq 'Up' foreach ($nic in $nics) { try { Set-NetAdapterPowerManagement -Name $nic.Name -WakeOnMagicPacket Enabled -ErrorAction Stop } catch { $notes += "Wake-on-LAN not settable on $($nic.Name)" } } Write-Host '' Write-Host '===== RESULT (send this to Claude) =====' Write-Host ('pc=' + $env:COMPUTERNAME + ' user=' + $env:USERNAME + ' domain=' + $env:USERDOMAIN) Write-Host ('sshd=' + (Get-Service sshd).Status) foreach ($nic in $nics) { Write-Host ('nic=' + $nic.Name + ' mac=' + $nic.MacAddress + ' ip=' + ((Get-NetIPAddress -InterfaceIndex $nic.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue).IPAddress -join ',') + ' network=' + (Get-NetConnectionProfile -InterfaceIndex $nic.ifIndex -ErrorAction SilentlyContinue).NetworkCategory) } if ($tasks) { $tasks | ForEach-Object { Write-Host ('task: ' + $_) } } else { Write-Host 'task: none (no known apps found)' } $notes | ForEach-Object { Write-Host ('note: ' + $_) } Write-Host '========================================'