Skip to content

Instantly share code, notes, and snippets.

@waggertron
Created March 17, 2026 09:47
Show Gist options
  • Select an option

  • Save waggertron/4c63b46c16a74d4a6e021b3361851c52 to your computer and use it in GitHub Desktop.

Select an option

Save waggertron/4c63b46c16a74d4a6e021b3361851c52 to your computer and use it in GitHub Desktop.
Weyflix Server Full Diagnostic - Run on Windows server as Administrator
@echo off
REM
REM Weyflix Server Full Diagnostic
REM Right-click → Run as Administrator
REM
PowerShell.exe -ExecutionPolicy Bypass -File "%~dp0server-full-diagnostic.ps1"
if %ERRORLEVEL% NEQ 0 (
echo.
echo [ERROR] Could not run diagnostic script.
echo Make sure server-full-diagnostic.ps1 is in the same folder.
pause
)
#
# Weyflix Server Full Diagnostic
# Run on the Windows media server as Administrator
#
# Right-click → Run with PowerShell (as Administrator)
# Results saved to Desktop
#
$outputFile = "$env:USERPROFILE\Desktop\weyflix-server-diagnostic-$(Get-Date -Format 'yyyyMMdd-HHmmss').txt"
function Log {
param([string]$msg, [string]$color = "White")
Write-Host $msg -ForegroundColor $color
$msg | Out-File -FilePath $outputFile -Append -Encoding utf8
}
function LogSection {
param([string]$title)
Log ""
Log "============================================"
Log " $title"
Log "============================================"
}
# Config
$portMap = [ordered]@{
32400 = "Plex"
8989 = "Sonarr"
7878 = "Radarr"
6789 = "NZBGet"
9696 = "Prowlarr"
9876 = "Weyflix Agent"
}
> $outputFile
Clear-Host
Log "================================================================" "Cyan"
Log " WEYFLIX SERVER FULL DIAGNOSTIC" "Cyan"
Log " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" "Gray"
Log "================================================================" "Cyan"
# ── 1. SYSTEM INFO ──
LogSection "1. SYSTEM INFO"
$os = Get-CimInstance Win32_OperatingSystem
$cpu = Get-CimInstance Win32_Processor | Select-Object -First 1
$uptime = (Get-Date) - $os.LastBootUpTime
$totalRAM = [math]::Round($os.TotalVisibleMemorySize / 1MB, 1)
$freeRAM = [math]::Round($os.FreePhysicalMemory / 1MB, 1)
$usedRAM = [math]::Round($totalRAM - $freeRAM, 1)
Log " Hostname : $env:COMPUTERNAME"
Log " OS : $($os.Caption) $($os.Version)"
Log " CPU : $($cpu.Name)"
Log " RAM : ${usedRAM}GB used / ${totalRAM}GB total (${freeRAM}GB free)"
Log " Uptime : $($uptime.Days)d $($uptime.Hours)h $($uptime.Minutes)m"
# CPU load
$cpuLoad = (Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average
$cpuColor = if ($cpuLoad -gt 80) { "Red" } elseif ($cpuLoad -gt 50) { "Yellow" } else { "Green" }
Log " CPU Load : ${cpuLoad}%" $cpuColor
# ── 2. NETWORK INFO ──
LogSection "2. NETWORK"
# Local IPs
$adapters = Get-NetAdapter | Where-Object { $_.Status -eq "Up" }
foreach ($adapter in $adapters) {
$ip = (Get-NetIPAddress -InterfaceIndex $adapter.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue | Select-Object -First 1).IPAddress
$mtu = (Get-NetIPInterface -InterfaceIndex $adapter.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue).NlMtu
$mtuWarn = if ($mtu -gt 1500) { " *** JUMBO FRAMES - may break Plex ***" } else { "" }
Log " $($adapter.Name): $ip (MTU: $mtu$mtuWarn, Speed: $($adapter.LinkSpeed))"
}
# Gateway
$gateway = (Get-NetRoute -DestinationPrefix "0.0.0.0/0" -ErrorAction SilentlyContinue | Select-Object -First 1).NextHop
Log " Gateway : $gateway"
# DNS
$dns = (Get-DnsClientServerAddress -AddressFamily IPv4 | Where-Object { $_.ServerAddresses.Count -gt 0 } | Select-Object -First 1).ServerAddresses -join ", "
Log " DNS Servers : $dns"
# Public IP
Log ""
try {
$publicIP = (Invoke-WebRequest -Uri "https://api.ipify.org" -UseBasicParsing -TimeoutSec 10).Content
Log " Public IP : $publicIP" "Green"
} catch {
Log " Public IP : CANNOT DETERMINE" "Red"
$publicIP = $null
}
# Server IP for comparisons
$serverIP = ($adapters | ForEach-Object {
Get-NetIPAddress -InterfaceIndex $_.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue
} | Where-Object { $_.IPAddress -notlike "127.*" } | Select-Object -First 1).IPAddress
Log " Server LAN : $serverIP"
# ── 3. SERVICE PORTS ──
LogSection "3. SERVICE PORTS"
$allUp = $true
foreach ($port in $portMap.Keys) {
$name = $portMap[$port]
$conn = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
if ($conn) {
$proc = Get-Process -Id $conn[0].OwningProcess -ErrorAction SilentlyContinue
$bind = $conn[0].LocalAddress
$bindNote = if ($bind -eq "0.0.0.0" -or $bind -eq "::") { "(all interfaces)" } else { "(bound to $bind only!)" }
Log " [OK] $name`:$port → $($proc.ProcessName) PID:$($conn[0].OwningProcess) $bindNote" "Green"
} else {
Log " [DOWN] $name`:$port → NOT LISTENING" "Red"
$allUp = $false
}
}
if (-not $allUp) {
Log ""
Log " >>> Some services are down! Check if they are running. <<<" "Red"
}
# ── 4. SERVICE API HEALTH ──
LogSection "4. SERVICE API HEALTH"
$apiChecks = @(
@{ Name="Plex"; URL="http://localhost:32400/identity" },
@{ Name="Sonarr"; URL="http://localhost:8989/ping" },
@{ Name="Radarr"; URL="http://localhost:7878/ping" },
@{ Name="NZBGet"; URL="http://localhost:6789/" },
@{ Name="Prowlarr"; URL="http://localhost:9696/ping" },
@{ Name="Agent"; URL="http://localhost:9876/health" }
)
foreach ($check in $apiChecks) {
try {
$sw = [System.Diagnostics.Stopwatch]::StartNew()
$r = Invoke-WebRequest -Uri $check.URL -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop
$sw.Stop()
Log " [OK] $($check.Name) → HTTP $($r.StatusCode) ($($sw.ElapsedMilliseconds)ms)" "Green"
} catch {
$code = if ($_.Exception.Response) { [int]$_.Exception.Response.StatusCode } else { "TIMEOUT" }
Log " [FAIL] $($check.Name) → $code" "Red"
}
}
# ── 5. FIREWALL ──
LogSection "5. FIREWALL"
# Profile status
Get-NetFirewallProfile | ForEach-Object {
$status = if ($_.Enabled) { "[ON] " } else { "[OFF]" }
$color = if ($_.Enabled) { "Green" } else { "Yellow" }
Log " $status $($_.Name) profile (Default inbound: $($_.DefaultInboundAction))" $color
}
Log ""
# Per-port rules
$missingRules = @()
foreach ($port in $portMap.Keys) {
$name = $portMap[$port]
$rules = Get-NetFirewallPortFilter -ErrorAction SilentlyContinue |
Where-Object { $_.LocalPort -eq "$port" -and $_.Protocol -eq "TCP" } |
Get-NetFirewallRule -ErrorAction SilentlyContinue |
Where-Object { $_.Direction -eq "Inbound" -and $_.Action -eq "Allow" -and $_.Enabled -eq "True" }
# Also check program-based rules
$progRules = Get-NetFirewallRule -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -match $name -and $_.Direction -eq "Inbound" -and $_.Action -eq "Allow" -and $_.Enabled -eq "True" }
if ($rules -or $progRules) {
$ruleNames = @()
if ($rules) { $ruleNames += $rules | ForEach-Object { $_.DisplayName } }
if ($progRules) { $ruleNames += $progRules | ForEach-Object { $_.DisplayName } }
Log " [OK] $name`:$port → $($ruleNames -join ', ')" "Green"
} else {
Log " [WARN] $name`:$port → No inbound allow rule found" "Yellow"
$missingRules += @{ Name=$name; Port=$port }
}
}
if ($missingRules.Count -gt 0) {
Log ""
Log " Missing rules can be created with:" "Yellow"
foreach ($mr in $missingRules) {
Log " New-NetFirewallRule -DisplayName '$($mr.Name) (TCP $($mr.Port))' -Direction Inbound -Protocol TCP -LocalPort $($mr.Port) -Action Allow" "Yellow"
}
}
# ── 6. CGNAT / DOUBLE NAT ──
LogSection "6. CGNAT / DOUBLE NAT DETECTION"
if ($publicIP) {
Log " Public IP: $publicIP"
Log " Gateway: $gateway"
Log ""
# Simple double NAT heuristic
if ($gateway -match "^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)") {
Log " Gateway is a private IP (expected for single-NAT setup)" "Green"
}
Log " Running tracert to $publicIP (max 5 hops)..."
$tracert = tracert -d -h 5 $publicIP 2>&1
foreach ($line in $tracert) { Log " $line" }
$cgnat = $tracert | Select-String "100\.(6[4-9]|[7-9]\d|1[01]\d|12[0-7])\."
if ($cgnat) {
Log ""
Log " [FAIL] CGNAT DETECTED!" "Red"
Log " Your ISP is using Carrier-Grade NAT." "Red"
Log " Port forwarding will NOT work." "Red"
Log " Solutions:" "Yellow"
Log " 1. Contact ISP and request a public/static IP" "Yellow"
Log " 2. Set up Tailscale for remote access" "Yellow"
Log " 3. Set up a VPS reverse proxy" "Yellow"
} else {
Log ""
Log " [OK] No CGNAT detected" "Green"
}
Log ""
Log " To check for Double NAT:" "Gray"
Log " 1. Open router admin: http://$gateway" "Gray"
Log " 2. Find the WAN/Internet IP" "Gray"
Log " 3. If WAN IP ≠ $publicIP → you have Double NAT" "Gray"
Log " 4. Fix: put ISP modem into Bridge Mode" "Gray"
} else {
Log " Skipped (no public IP determined)" "Yellow"
}
# ── 7. PORT FORWARD SELF-TEST ──
LogSection "7. PORT FORWARD SELF-TEST"
if ($publicIP) {
Log " Testing if port 32400 is reachable via your public IP..."
Log " (Tests NAT hairpin + port forwarding from inside the network)"
Log ""
$test = Test-NetConnection -ComputerName $publicIP -Port 32400 -WarningAction SilentlyContinue
if ($test.TcpTestSucceeded) {
Log " [OK] Port 32400 is reachable via $publicIP" "Green"
# Also test the API
try {
$api = Invoke-WebRequest -Uri "http://${publicIP}:32400/identity" -UseBasicParsing -TimeoutSec 10
Log " [OK] Plex API responds via public IP (HTTP $($api.StatusCode))" "Green"
} catch {
Log " [WARN] Port open but Plex API didn't respond via public IP" "Yellow"
}
} else {
Log " [FAIL] Port 32400 NOT reachable via $publicIP" "Red"
Log ""
Log " Possible causes:" "Yellow"
Log " 1. No port forward configured on router" "Yellow"
Log " 2. Router doesn't support NAT hairpin (test from external network instead)" "Yellow"
Log " 3. ISP blocking port 32400" "Yellow"
Log " 4. CGNAT (see section 6)" "Yellow"
Log ""
Log " Verify from outside: https://canyouseeme.org (test port 32400)" "Gray"
}
} else {
Log " Skipped (no public IP)" "Yellow"
}
# ── 8. DISK SPACE ──
LogSection "8. DISK SPACE"
Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Used -gt 0 } | ForEach-Object {
$total = $_.Used + $_.Free
$pct = [math]::Round(($_.Used / $total) * 100, 1)
$freeGB = [math]::Round($_.Free / 1GB, 1)
$totalGB = [math]::Round($total / 1GB, 1)
$usedGB = [math]::Round($_.Used / 1GB, 1)
$color = if ($pct -gt 90) { "Red" } elseif ($pct -gt 75) { "Yellow" } else { "Green" }
$warn = if ($pct -gt 90) { " *** CRITICAL ***" } elseif ($pct -gt 75) { " * WARNING *" } else { "" }
Log " $($_.Name): ${usedGB}GB / ${totalGB}GB (${pct}% used, ${freeGB}GB free)$warn" $color
}
# ── 9. DISK HEALTH ──
LogSection "9. DISK HEALTH"
try {
Get-PhysicalDisk | ForEach-Object {
$color = if ($_.HealthStatus -eq "Healthy") { "Green" } else { "Red" }
$warn = if ($_.HealthStatus -ne "Healthy") { " *** ATTENTION NEEDED ***" } else { "" }
Log " $($_.FriendlyName) ($($_.MediaType), $([math]::Round($_.Size/1GB))GB) → $($_.HealthStatus)$warn" $color
}
} catch {
Log " Cannot read disk health (need Administrator)" "Yellow"
}
# ── 10. PROCESS STATUS ──
LogSection "10. SERVICE PROCESSES"
$processNames = @(
@{ Search="Plex Media Server"; Display="Plex Media Server" },
@{ Search="Plex Transcoder"; Display="Plex Transcoder" },
@{ Search="NzbDrone"; Display="Sonarr" },
@{ Search="Radarr"; Display="Radarr" },
@{ Search="nzbget"; Display="NZBGet" },
@{ Search="Prowlarr"; Display="Prowlarr" }
)
foreach ($p in $processNames) {
$proc = Get-Process -Name $p.Search -ErrorAction SilentlyContinue
if ($proc) {
$mem = [math]::Round(($proc | Measure-Object WorkingSet64 -Sum).Sum / 1MB, 1)
$startTime = ($proc | Select-Object -First 1).StartTime
$running = if ($startTime) { (Get-Date) - $startTime } else { $null }
$runStr = if ($running) { "$($running.Days)d $($running.Hours)h $($running.Minutes)m" } else { "unknown" }
Log " [OK] $($p.Display) → ${mem}MB RAM, running $runStr" "Green"
} else {
Log " [DOWN] $($p.Display) → NOT RUNNING" "Red"
}
}
# ── 11. ACTIVE CONNECTIONS ──
LogSection "11. ACTIVE CONNECTIONS TO SERVICES"
foreach ($port in $portMap.Keys) {
$name = $portMap[$port]
$conns = Get-NetTCPConnection -LocalPort $port -State Established -ErrorAction SilentlyContinue
$count = ($conns | Measure-Object).Count
if ($count -gt 0) {
$ips = ($conns | ForEach-Object {
$ip = $_.RemoteAddress
$type = if ($ip -match "^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.|127\.)") { "LAN" } else { "WAN" }
"$ip($type)"
} | Select-Object -Unique) -join ", "
Log " $name`:$port → $count connection(s): $ips" "Green"
} else {
Log " $name`:$port → no active connections" "Gray"
}
}
# ── 12. PLEX LOG HIGHLIGHTS ──
LogSection "12. RECENT PLEX LOG ENTRIES (remote access related)"
$plexLog = "$env:LOCALAPPDATA\Plex Media Server\Logs\Plex Media Server.log"
if (Test-Path $plexLog) {
$entries = Select-String -Path $plexLog -Pattern "remote|nat|upnp|relay|mapping|external|port.forward" -AllMatches |
Select-Object -Last 20
if ($entries) {
foreach ($entry in $entries) {
Log " $($entry.Line)" "Gray"
}
} else {
Log " No remote access entries found in recent logs" "Gray"
}
} else {
Log " Plex log not found at expected location" "Yellow"
Log " Expected: $plexLog" "Gray"
}
# ── 13. SUMMARY ──
LogSection "SUMMARY"
$issues = @()
# Check for down services
foreach ($port in $portMap.Keys) {
$name = $portMap[$port]
$conn = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
if (-not $conn) { $issues += "$name is not running (port $port)" }
}
# Check for missing firewall rules
if ($missingRules.Count -gt 0) {
foreach ($mr in $missingRules) {
$issues += "No firewall rule for $($mr.Name) (port $($mr.Port))"
}
}
# Check CGNAT
if ($cgnat) { $issues += "CGNAT detected - port forwarding won't work" }
# Check port forward
if ($publicIP -and $test -and -not $test.TcpTestSucceeded) {
$issues += "Port 32400 not reachable via public IP"
}
# Check jumbo frames
$jumbo = Get-NetIPInterface -AddressFamily IPv4 -ErrorAction SilentlyContinue |
Where-Object { $_.NlMtu -gt 1500 -and $_.ConnectionState -eq "Connected" }
if ($jumbo) { $issues += "Jumbo frames detected (MTU > 1500) - can break Plex streaming" }
# Check disk space
Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Used -gt 0 } | ForEach-Object {
$total = $_.Used + $_.Free
$pct = [math]::Round(($_.Used / $total) * 100, 1)
if ($pct -gt 90) { $issues += "Drive $($_.Name): is critically full ($pct%)" }
}
# Check disk health
try {
Get-PhysicalDisk | Where-Object { $_.HealthStatus -ne "Healthy" } | ForEach-Object {
$issues += "Disk '$($_.FriendlyName)' health: $($_.HealthStatus)"
}
} catch {}
if ($issues.Count -eq 0) {
Log ""
Log " [OK] Server looks healthy! No issues detected." "Green"
Log ""
Log " If users still can't connect:" "White"
Log " 1. Have them run the user diagnostic script" "White"
Log " 2. Test from an external network (canyouseeme.org port 32400)" "White"
Log " 3. Check router port forwarding config" "White"
Log " 4. Check Plex Settings > Remote Access" "White"
} else {
Log ""
Log " Issues found ($($issues.Count)):" "Red"
foreach ($issue in $issues) {
Log " ✗ $issue" "Yellow"
}
}
Log ""
Log "================================================================"
Log " Results saved to: $outputFile"
Log "================================================================"
Start-Process notepad.exe $outputFile
Write-Host ""
Read-Host "Press Enter to exit"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment