@echo off rem net.frody.cl - diagnostico automatico para Valorant rem Solo LEE la configuracion y mide la red: no cambia nada, no instala nada, no pide administrador. rem Es texto plano: puedes abrirlo con el Bloc de notas para ver todo lo que hace. setlocal title net.frody.cl - diagnostico automatico set "NF_SELF=%~f0" powershell -NoProfile -ExecutionPolicy Bypass -Command "$s=[IO.File]::ReadAllText($env:NF_SELF,[Text.Encoding]::UTF8); Invoke-Expression ($s.Substring($s.IndexOf('#PS-'+'INICIO')))" if errorlevel 1 pause exit /b #PS-INICIO # El resultado se abre en https://net.frody.cl y viaja en la dirección de la página, después del "#": # esa parte el navegador no la envía a ningún servidor. Todo el análisis ocurre en tu navegador. $ErrorActionPreference = 'SilentlyContinue' $ProgressPreference = 'SilentlyContinue' $destino = if ($env:NF_DESTINO) { $env:NF_DESTINO } else { 'https://net.frody.cl/' } # NF_DESTINO y NF_NOABRIR: solo para pruebas $total = 4 function Paso($n, $texto) { Write-Host (" [{0}/{1}] {2}" -f $n, $total, $texto) -ForegroundColor Cyan } function Texto($bloque) { (& $bloque 2>$null | Out-String -Width 8192).TrimEnd() } function Lanzar($exe, $argumentos) { $i = New-Object Diagnostics.ProcessStartInfo $exe, $argumentos $i.UseShellExecute = $false; $i.RedirectStandardOutput = $true $i.StandardOutputEncoding = [Console]::OutputEncoding $p = [Diagnostics.Process]::Start($i) @{ p = $p; salida = $p.StandardOutput.ReadToEndAsync() } } Write-Host '' Write-Host ' NET.FRODY.CL // diagnóstico automático' -ForegroundColor Red Write-Host ' Solo lee la configuración y mide la red. No cambia nada y no pide administrador.' Write-Host ' Tarda unos 40 segundos. Para que la medición sirva, cierra descargas y streaming.' Write-Host '' $activos = @(Get-NetAdapter -Physical | Where-Object Status -eq 'Up') if (-not $activos.Count) { Write-Host ' No hay ninguna tarjeta de red conectada. Conéctate a internet y vuelve a abrir este archivo.' -ForegroundColor Yellow exit 1 } $nombres = $activos.Name # ---------- 1 · Wi-Fi: pide un escaneo nuevo (Windows guarda el anterior) y lee las redes ---------- Paso 1 'Wi-Fi y redes vecinas' $wifi = '' if ($activos | Where-Object { $_.PhysicalMediaType -match '802\.11' }) { try { Add-Type -ErrorAction Stop -TypeDefinition @' using System; using System.Runtime.InteropServices; public static class NfWlan { [DllImport("wlanapi.dll")] static extern uint WlanOpenHandle(uint version, IntPtr reserved, out uint negotiated, out IntPtr handle); [DllImport("wlanapi.dll")] static extern uint WlanCloseHandle(IntPtr handle, IntPtr reserved); [DllImport("wlanapi.dll")] static extern uint WlanEnumInterfaces(IntPtr handle, IntPtr reserved, out IntPtr list); [DllImport("wlanapi.dll")] static extern uint WlanScan(IntPtr handle, ref Guid iface, IntPtr ssid, IntPtr ie, IntPtr reserved); [DllImport("wlanapi.dll")] static extern void WlanFreeMemory(IntPtr memory); public static int Escanear() { uint negotiated; IntPtr handle, list; int pedidos = 0; if (WlanOpenHandle(2, IntPtr.Zero, out negotiated, out handle) != 0) return -1; try { if (WlanEnumInterfaces(handle, IntPtr.Zero, out list) != 0) return -1; int n = Marshal.ReadInt32(list); for (int i = 0; i < n; i++) { // WLAN_INTERFACE_INFO: GUID (16) + descripción WCHAR[256] (512) + estado (4) = 532 bytes; la lista parte tras 2 DWORD Guid g = (Guid)Marshal.PtrToStructure(new IntPtr(list.ToInt64() + 8 + i * 532), typeof(Guid)); if (WlanScan(handle, ref g, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) == 0) pedidos++; } WlanFreeMemory(list); } finally { WlanCloseHandle(handle, IntPtr.Zero); } return pedidos; } } '@ if ([NfWlan]::Escanear() -gt 0) { Start-Sleep -Seconds 4 } } catch {} $wifi = Texto { netsh wlan show interfaces; netsh wlan show networks mode=bssid } } else { Write-Host ' Juegas por cable: se omite.' -ForegroundColor DarkGray } # ---------- 2 · Tarjeta de red ---------- Paso 2 'Tarjeta de red' $cfg = Texto { '===ADV===' Get-NetAdapterAdvancedProperty -Name $nombres | Select-Object Name,DisplayName,DisplayValue,RegistryKeyword,RegistryValue,ValidDisplayValues,ValidRegistryValues | ConvertTo-Json -Compress '===PWR===' Get-NetAdapterPowerManagement -Name $nombres | Format-List Name,AllowComputerToTurnOffDevice '===TCP===' netsh int tcp show global '===RSC===' Get-NetAdapterRsc -Name $nombres | Format-List Name,IPv4Enabled,IPv6Enabled } # ---------- 3 · Windows ---------- Paso 3 'Windows para jugar' $win = Texto { '===PLAN===' powercfg /getactivescheme '===GAME===' Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\GameDVR' | Format-List AppCaptureEnabled,HistoricalCaptureEnabled Get-ItemProperty 'HKCU:\Software\Microsoft\GameBar' | Format-List AutoGameModeEnabled '===DO===' try { 'DownloadModeName=' + (Get-DODownloadMode) } catch { 'DownloadModeName=?' } '===QOS===' Get-NetQosPolicy | Format-List Name,AppPathNameMatchCondition,DSCPAction '===DISPLAY===' Get-CimInstance Win32_VideoController | Format-List Name,CurrentRefreshRate,MaxRefreshRate,CurrentHorizontalResolution,CurrentVerticalResolution '===ENERGIA===' 'bateria=' + (Get-CimInstance Win32_Battery | Select-Object -First 1).BatteryStatus $energia = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes' 'modoAC=' + $energia.ActiveOverlayAcPowerScheme 'modoDC=' + $energia.ActiveOverlayDcPowerScheme '===DRIVERS===' Get-CimInstance Win32_VideoController | ForEach-Object { 'gpu|' + $_.Name + '|' + $_.DriverVersion + '|' + $(if ($_.DriverDate) { $_.DriverDate.ToString('yyyy-MM-dd') }) } $activos | ForEach-Object { 'red|' + $_.InterfaceDescription + '|' + $_.DriverVersionString + '|' + $_.DriverDate + '|' + $_.PhysicalMediaType } '===GPUPREF===' $preferencias = Get-ItemProperty 'HKCU:\Software\Microsoft\DirectX\UserGpuPreferences' if ($preferencias) { $preferencias.PSObject.Properties | Where-Object Name -match 'VALORANT' | ForEach-Object { $_.Name + '=' + $_.Value } } '===SALIDA===' $salida = Find-NetRoute -RemoteIPAddress 1.1.1.1 | Select-Object -First 1 'salida=' + $salida.InterfaceAlias 'fisica=' + [bool]($activos | Where-Object ifIndex -eq $salida.InterfaceIndex) 'desc=' + (Get-NetAdapter -IncludeHidden | Where-Object ifIndex -eq $salida.InterfaceIndex | Select-Object -First 1).InterfaceDescription '===SERVICIOS===' Get-Service | Where-Object { $_.Status -eq 'Running' -and ($_.Name + ' ' + $_.DisplayName) -match 'cFosSpeed|Killer|GameFirst|SmartByte|NetLimiter' } | ForEach-Object { $_.Name + '|' + $_.DisplayName } '===MEMORIA===' $sistema = Get-CimInstance Win32_OperatingSystem 'totalKB=' + $sistema.TotalVisibleMemorySize 'libreKB=' + $sistema.FreePhysicalMemory } # ---------- 4 · Ruta: 20 pings simultáneos al router, a Cloudflare y a Google, más los primeros saltos ---------- Paso 4 'Ruta: router, Cloudflare y Google (20 segundos)' $red = Texto { $activos | Select-Object Name,InterfaceDescription,LinkSpeed,PhysicalMediaType | Format-List } $gw = (Get-NetRoute -DestinationPrefix '0.0.0.0/0' | Sort-Object RouteMetric,InterfaceMetric | Select-Object -First 1).NextHop $pGw = if ($gw) { Lanzar 'ping.exe' "-n 20 $gw" } $pDns = Lanzar 'ping.exe' '-n 20 1.1.1.1' $pInet = Lanzar 'ping.exe' '-n 20 8.8.8.8' $pRuta = Lanzar 'tracert.exe' '-d -h 4 -w 800 8.8.8.8' $corriendo = @($pGw, $pDns, $pInet, $pRuta) | Where-Object { $_ } Write-Host ' ' -NoNewline while ($corriendo | Where-Object { -not $_.p.HasExited }) { Write-Host '.' -NoNewline -ForegroundColor DarkGray; Start-Sleep -Seconds 1 } Write-Host '' $game = @('===NET===', $red, '===GW===', "gateway=$gw", $(if ($pGw) { $pGw.salida.Result }), '===DNS===', $pDns.salida.Result, '===INET===', $pInet.salida.Result, '===TRACE===', $pRuta.salida.Result) -join "`r`n" # ---------- Entrega: JSON comprimido en la dirección de la página ---------- $medida = $false try { [void][Windows.Networking.Connectivity.NetworkInformation, Windows.Networking.Connectivity, ContentType = WindowsRuntime] $costo = [Windows.Networking.Connectivity.NetworkInformation]::GetInternetConnectionProfile().GetConnectionCost() $medida = "$($costo.NetworkCostType)" -ne 'Unrestricted' } catch {} $datos = @{ v = 1; t = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds(); medida = $medida; wifi = $wifi; cfg = $cfg; win = $win; game = $game } | ConvertTo-Json -Compress $bytes = [Text.Encoding]::UTF8.GetBytes($datos) $ms = New-Object IO.MemoryStream $dz = New-Object IO.Compression.DeflateStream $ms, ([IO.Compression.CompressionMode]::Compress) $dz.Write($bytes, 0, $bytes.Length); $dz.Close() $b64 = [Convert]::ToBase64String($ms.ToArray()).TrimEnd('=').Replace('+', '-').Replace('/', '_') # Una página local mínima hace el salto: así la dirección puede ser larga sin pasar por la línea de comandos $puente = Join-Path $env:TEMP ('netfrody-' + [Guid]::NewGuid().ToString('N').Substring(0, 8) + '.html') $html = '
Abriendo tu diagnóstico en net.frody.cl…
' + '' [IO.File]::WriteAllText($puente, $html, (New-Object Text.UTF8Encoding $false)) Write-Host '' if ($env:NF_NOABRIR) { Write-Host " Listo (sin abrir): $puente"; exit 0 } Write-Host ' Listo. Se abre tu navegador con el resultado.' -ForegroundColor Green Start-Process $puente Write-Host ' Esta ventana se cierra sola en unos segundos.' -ForegroundColor DarkGray Start-Sleep -Seconds 15 Remove-Item $puente -Force exit 0