<# Perfiles WiFi: listar, exportar e importar Herramientas BAIT · https://bait.cl/herramientas/script-perfiles-wifi/ Qué hace (menú): 1. Listar las redes WiFi guardadas en este equipo con su clave. 2. Exportar todas las redes a una carpeta (un archivo .xml por red), para llevarlas a otro equipo. 3. Importar las redes desde una carpeta con esos archivos .xml. ATENCIÓN: al exportar, las claves quedan escritas en texto legible dentro de los .xml. Guarda esa carpeta en un lugar seguro y bórrala cuando termines de importar. Requiere administrador para leer las claves y para importar las redes para todos los usuarios. Usa netsh, que viene con Windows. No se conecta a internet. Uso: Clic derecho > Ejecutar con PowerShell o bien: powershell -ExecutionPolicy Bypass -File .\perfiles-wifi.ps1 #> $Host.UI.RawUI.WindowTitle = 'Perfiles WiFi (BAIT)' function Test-Administrador { $principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } if (-not (Test-Administrador)) { Write-Host '' Write-Host 'Para leer las claves WiFi se necesitan permisos de administrador.' -ForegroundColor Yellow if ($PSCommandPath -and ((Read-Host '¿Abrir de nuevo como administrador? (S/N)') -match '^[sS]')) { Start-Process -FilePath 'powershell.exe' -ArgumentList @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', "`"$PSCommandPath`"") -Verb RunAs } else { Write-Host 'Abre PowerShell como administrador y vuelve a ejecutar el script.' Read-Host 'Presiona Enter para cerrar' | Out-Null } exit } # Revisa que el servicio de WiFi exista (un PC sin tarjeta WiFi no lo tiene activo) $servicio = Get-Service -Name WlanSvc -ErrorAction SilentlyContinue if (-not $servicio -or $servicio.Status -ne 'Running') { Write-Host 'El servicio de WiFi (WLAN AutoConfig) no está en ejecución. ¿Este equipo tiene WiFi?' -ForegroundColor Red Read-Host 'Presiona Enter para cerrar' | Out-Null exit } # Lee un .xml de perfil y devuelve nombre, seguridad y clave. # Se leen los XML en vez del texto de netsh para que funcione con Windows en cualquier idioma. function Leer-Perfil([string]$Archivo) { try { [xml]$x = Get-Content -LiteralPath $Archivo -Raw -Encoding UTF8 $seg = $x.WLANProfile.MSM.security [pscustomobject]@{ Red = $x.WLANProfile.name Seguridad = [string]$seg.authEncryption.authentication Clave = [string]$seg.sharedKey.keyMaterial Archivo = $Archivo } } catch { $null } } # Exporta todos los perfiles a una carpeta. key=clear deja las claves legibles. function Exportar-A([string]$Carpeta) { New-Item -ItemType Directory -Path $Carpeta -Force | Out-Null netsh wlan export profile key=clear folder="$Carpeta" | Out-Null return @(Get-ChildItem -LiteralPath $Carpeta -Filter '*.xml' -ErrorAction SilentlyContinue) } function Listar { # Exporta a una carpeta temporal, lee y borra la carpeta temporal al final $temp = Join-Path $env:TEMP ('wifi-' + [guid]::NewGuid().ToString('N')) $archivos = Exportar-A $temp if (-not $archivos) { Write-Host 'No hay redes WiFi guardadas.' -ForegroundColor Yellow; return } $perfiles = $archivos | ForEach-Object { Leer-Perfil $_.FullName } | Where-Object { $_ } | Sort-Object Red Write-Host '' $perfiles | ForEach-Object { $clave = $_.Clave if (-not $clave) { $clave = '(sin clave o red empresarial)' } [pscustomobject]@{ 'Red' = $_.Red; 'Seguridad' = $_.Seguridad; 'Clave' = $clave } } | Format-Table -AutoSize | Out-Host Remove-Item -LiteralPath $temp -Recurse -Force -ErrorAction SilentlyContinue } function Exportar { Write-Host '' Write-Host 'Las claves quedarán escritas en texto legible dentro de los archivos.' -ForegroundColor Yellow Write-Host 'Cualquiera que tenga la carpeta podrá conectarse a esas redes.' -ForegroundColor Yellow $porDefecto = Join-Path ([Environment]::GetFolderPath('Desktop')) ("Redes-WiFi-{0}" -f $env:COMPUTERNAME) $carpeta = Read-Host "Carpeta de destino (Enter para usar $porDefecto)" if (-not $carpeta) { $carpeta = $porDefecto } $archivos = Exportar-A $carpeta if (-not $archivos) { Write-Host 'No se exportó ninguna red.' -ForegroundColor Yellow; return } Write-Host ("Se exportaron {0} red(es) a {1}" -f $archivos.Count, $carpeta) -ForegroundColor Green Write-Host 'Cuando termines de importarlas en el otro equipo, borra esta carpeta.' } function Importar { Write-Host '' $carpeta = Read-Host 'Carpeta con los archivos .xml exportados' $carpeta = $carpeta.Trim('"') if (-not $carpeta -or -not (Test-Path -LiteralPath $carpeta)) { Write-Host 'La carpeta no existe.' -ForegroundColor Red; return } $archivos = @(Get-ChildItem -LiteralPath $carpeta -Filter '*.xml') if (-not $archivos) { Write-Host 'No hay archivos .xml en esa carpeta.' -ForegroundColor Yellow; return } $bien = 0 foreach ($a in $archivos) { $p = Leer-Perfil $a.FullName $nombre = $a.Name if ($p) { $nombre = $p.Red } # user=all: la red queda disponible para todos los usuarios del equipo netsh wlan add profile filename="$($a.FullName)" user=all | Out-Null if ($LASTEXITCODE -eq 0) { Write-Host "Importada: $nombre" -ForegroundColor Green; $bien++ } else { Write-Host "No se pudo importar: $nombre" -ForegroundColor Red } } Write-Host ("{0} de {1} redes importadas." -f $bien, $archivos.Count) if ($bien -gt 0 -and ((Read-Host '¿Borrar la carpeta con las claves ahora? (S/N)') -match '^[sS]')) { Remove-Item -LiteralPath $carpeta -Recurse -Force Write-Host 'Carpeta borrada.' } } do { Write-Host '' Write-Host '=== Perfiles WiFi ===' -ForegroundColor Cyan Write-Host '1. Listar redes guardadas con su clave' Write-Host '2. Exportar todas las redes a una carpeta' Write-Host '3. Importar redes desde una carpeta' Write-Host '0. Salir' $opcion = Read-Host 'Elige una opción' switch ($opcion) { '1' { Listar } '2' { Exportar } '3' { Importar } '0' { } default { Write-Host 'Opción no válida.' -ForegroundColor Yellow } } } while ($opcion -ne '0')