<# .SYNOPSIS Configura el acceso remoto por SSH (-> PowerShell) en un PC Windows. .DESCRIPTION Idempotente. Deja listo el equipo para conectarse desde otro (p. ej. el portatil) con `ssh usuario@equipo` y caer directamente en PowerShell. Hace: 1. Instala la capacidad OpenSSH.Server (si falta). 2. Pone y arranca los servicios sshd y ssh-agent (Automatico). 3. Deja PowerShell como shell por defecto de SSH. 4. Crea una regla de firewall para el puerto 22, restringida a Tailscale y LAN. 5. Instala la clave publica recibida en authorized_keys (o administrators_authorized_keys). Requiere PowerShell ELEVADO (se auto-eleva si hace falta). .EXAMPLE powershell -ExecutionPolicy Bypass -File setup_ssh_server.ps1 -PublicKey "ssh-ed25519 AAAA... juanm@portatil" #> [CmdletBinding()] param( [string]$PublicKey = '', [string[]]$AllowedNetworks = @('100.64.0.0/10', '192.168.1.0/24', '192.168.50.0/24') ) $ErrorActionPreference = 'Stop' # --- Auto-elevacion ------------------------------------------------------- $esAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $esAdmin) { Write-Host 'Requiere administrador. Reabriendo elevado...' -ForegroundColor Yellow $argsList = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', "`"$PSCommandPath`"") if ($PublicKey) { $argsList += @('-PublicKey', "`"$PublicKey`"") } Start-Process powershell -Verb RunAs -ArgumentList $argsList exit } Write-Host '== Configurando OpenSSH Server (acceso remoto -> PowerShell) ==' -ForegroundColor Cyan # 1) Capacidad OpenSSH.Server ---------------------------------------------- $cap = Get-WindowsCapability -Online -Name 'OpenSSH.Server*' | Select-Object -First 1 if ($cap.State -ne 'Installed') { Write-Host ' - Instalando OpenSSH.Server...' -ForegroundColor Yellow Add-WindowsCapability -Online -Name $cap.Name | Out-Null } Write-Host ' - OpenSSH.Server instalado.' -ForegroundColor Green # 2) Servicios -------------------------------------------------------------- foreach ($svc in @('sshd', 'ssh-agent')) { if (Get-Service $svc -ErrorAction SilentlyContinue) { Set-Service -Name $svc -StartupType Automatic if ((Get-Service $svc).Status -ne 'Running') { Start-Service $svc } Write-Host " - Servicio '$svc' -> Automatico y en marcha." -ForegroundColor Green } } # 3) Shell por defecto = PowerShell ---------------------------------------- if (-not (Test-Path 'HKLM:\SOFTWARE\OpenSSH')) { New-Item -Path 'HKLM:\SOFTWARE\OpenSSH' -Force | Out-Null } $pwsh = Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe' New-ItemProperty -Path 'HKLM:\SOFTWARE\OpenSSH' -Name 'DefaultShell' -Value $pwsh -PropertyType String -Force | Out-Null Write-Host " - Shell por defecto: $pwsh" -ForegroundColor Green # 4) Firewall (solo Tailscale + LAN) --------------------------------------- $ruleName = 'OpenSSH Server (sshd) - acceso remoto' Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue | Remove-NetFirewallRule New-NetFirewallRule -DisplayName $ruleName -Direction Inbound -Protocol TCP -Action Allow ` -LocalPort 22 -RemoteAddress $AllowedNetworks -Profile Any | Out-Null Write-Host " - Firewall: puerto 22 permitido desde $($AllowedNetworks -join ', ')." -ForegroundColor Green # 5) Clave publica ---------------------------------------------------------- if ($PublicKey) { $usuarioEsAdmin = $null -ne (Get-LocalGroupMember -Group (Get-LocalGroup -SID 'S-1-5-32-544').Name | Where-Object { $_.Name -like "*\$env:USERNAME" }) if ($usuarioEsAdmin) { $keyFile = Join-Path $env:ProgramData 'ssh\administrators_authorized_keys' $dir = Split-Path $keyFile if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } } else { $keyFile = Join-Path $env:USERPROFILE '.ssh\authorized_keys' $dir = Split-Path $keyFile if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } } $contenido = if (Test-Path $keyFile) { Get-Content -LiteralPath $keyFile -ErrorAction SilentlyContinue } else { @() } if ($contenido -notcontains $PublicKey.Trim()) { Add-Content -LiteralPath $keyFile -Value $PublicKey.Trim() -Encoding ascii Write-Host " - Clave publica anadida a $keyFile" -ForegroundColor Green } else { Write-Host " - La clave publica ya estaba en $keyFile" -ForegroundColor Green } if ($usuarioEsAdmin) { icacls $keyFile /inheritance:r 2>$null | Out-Null icacls $keyFile /grant 'SYSTEM:F' 'BUILTIN\Administradores:F' 'BUILTIN\Administrators:F' 2>$null | Out-Null } Restart-Service sshd Write-Host ' - sshd reiniciado para aplicar la clave.' -ForegroundColor Green } $ips = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -notlike '127.*' }).IPAddress -join ', ' Write-Host '' Write-Host 'Listo. Datos de conexion:' -ForegroundColor Cyan Write-Host " Usuario : $env:USERNAME" Write-Host " IPs : $ips" Write-Host " Prueba : ssh $env:USERNAME@"