```powershell #Requires -Version 5.1 <# .SYNOPSIS Configuración inicial de Windows 10. .DESCRIPTION Este script configura una cuenta técnica llamada "tecnica" y habilita Escritorio Remoto. Características: - Se autoeleva a Administrador. - Crea el usuario "tecnica" si no existe. - Solicita la contraseña dos veces al crear el usuario. - NO cambia la contraseña si el usuario ya existe. - Añade el usuario al grupo Administradores. - Activa Escritorio Remoto. - Configura el Firewall para RDP. - Añade el usuario al grupo Usuarios de escritorio remoto. - Oculta el usuario de la pantalla de inicio de sesión. - Verifica al final que cada configuración está realmente aplicada. - Devuelve código de salida 0 si todo está correcto. - Devuelve código de salida 1 si hay algún error. .NOTES Diseñado para Windows 10 / PowerShell 5.1. IMPORTANTE: Ocultar una cuenta de la pantalla de login NO es una medida de seguridad. La cuenta sigue existiendo. Este script NO cambia la configuración de Network Level Authentication ni abre RDP fuera del Firewall de Windows. #> # ============================================================ # CONFIGURACIÓN # ============================================================ $Username = "tecnica" # ============================================================ # CONFIGURACIÓN DE ERRORES # ============================================================ $ErrorActionPreference = "Stop" # ============================================================ # FUNCIONES AUXILIARES # ============================================================ function Write-Step { param ( [string]$Message ) Write-Host "" Write-Host "--------------------------------------------------" ` -ForegroundColor DarkGray Write-Host $Message ` -ForegroundColor Cyan Write-Host "--------------------------------------------------" ` -ForegroundColor DarkGray } function Write-Ok { param ( [string]$Message ) Write-Host "[OK] $Message" ` -ForegroundColor Green } function Write-WarningMessage { param ( [string]$Message ) Write-Host "[AVISO] $Message" ` -ForegroundColor Yellow } function Write-ErrorMessage { param ( [string]$Message ) Write-Host "[ERROR] $Message" ` -ForegroundColor Red } # ============================================================ # COMPROBAR ADMINISTRADOR # ============================================================ function Test-IsAdministrator { $identity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object Security.Principal.WindowsPrincipal($identity) return $principal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator ) } # ============================================================ # AUTOELEVAR # ============================================================ function Ensure-Administrator { if (Test-IsAdministrator) { return } Write-Host "" Write-WarningMessage "Este script necesita permisos de Administrador." Write-Host "Solicitando elevación..." -ForegroundColor Yellow Write-Host "" # Si el script está siendo ejecutado desde un archivo .ps1, # volvemos a abrir el mismo archivo como Administrador. if (-not $PSCommandPath) { Write-ErrorMessage ` "No se puede determinar la ruta del script." exit 1 } $arguments = @( "-NoProfile" "-ExecutionPolicy" "Bypass" "-File" "`"$PSCommandPath`"" ) try { $process = Start-Process ` -FilePath "powershell.exe" ` -ArgumentList $arguments ` -Verb RunAs ` -Wait ` -PassThru # Propagamos el código de salida de la instancia elevada. exit $process.ExitCode } catch { Write-ErrorMessage ` "No se pudo obtener permisos de Administrador." Write-ErrorMessage $_.Exception.Message exit 1 } } # ============================================================ # COMPROBAR EXISTENCIA DEL USUARIO # ============================================================ function Get-LocalUserSafe { param ( [Parameter(Mandatory)] [string]$Name ) try { return Get-LocalUser ` -Name $Name ` -ErrorAction Stop } catch { return $null } } # ============================================================ # COMPROBAR SI UN USUARIO EXISTE # ============================================================ function Test-LocalUserExists { param ( [Parameter(Mandatory)] [string]$Name ) $user = Get-LocalUserSafe -Name $Name return ($null -ne $user) } # ============================================================ # OBTENER GRUPO LOCAL MEDIANTE SID # # Los grupos integrados de Windows tienen SIDs conocidos: # # Administradores: # S-1-5-32-544 # # Usuarios de escritorio remoto: # S-1-5-32-555 # # De esta forma no dependemos del idioma de Windows. # ============================================================ function Get-LocalGroupBySid { param ( [Parameter(Mandatory)] [string]$Sid ) try { $group = Get-LocalGroup | Where-Object { $_.SID.Value -eq $Sid } | Select-Object -First 1 if ($null -eq $group) { throw "No se encontró el grupo con SID $Sid." } return $group } catch { throw $_ } } # ============================================================ # COMPROBAR SI UN USUARIO ESTÁ EN UN GRUPO # ============================================================ function Test-UserInGroup { param ( [Parameter(Mandatory)] [string]$Username, [Parameter(Mandatory)] [Microsoft.PowerShell.Commands.LocalGroup]$Group ) try { $members = Get-LocalGroupMember ` -Group $Group.Name ` -ErrorAction Stop foreach ($member in $members) { # El miembro normalmente aparece como: # # EQUIPO\tecnica # # Comparamos la parte final. $memberName = $member.Name.Split("\")[-1] if ($memberName -ieq $Username) { return $true } } return $false } catch { return $false } } # ============================================================ # AÑADIR USUARIO A GRUPO DE FORMA IDEMPOTENTE # ============================================================ function Ensure-UserInGroup { param ( [Parameter(Mandatory)] [string]$Username, [Parameter(Mandatory)] [Microsoft.PowerShell.Commands.LocalGroup]$Group ) if (Test-UserInGroup ` -Username $Username ` -Group $Group) { Write-Ok ` "'$Username' ya pertenece a '$($Group.Name)'." return } Write-Host ` "Añadiendo '$Username' a '$($Group.Name)'..." ` -ForegroundColor Cyan Add-LocalGroupMember ` -Group $Group.Name ` -Member $Username ` -ErrorAction Stop # VERIFICACIÓN INMEDIATA if (-not ( Test-UserInGroup ` -Username $Username ` -Group $Group )) { throw ` "El usuario no aparece en el grupo después de añadirlo." } Write-Ok ` "'$Username' pertenece ahora a '$($Group.Name)'." } # ============================================================ # PEDIR CONTRASEÑA Y CONFIRMARLA # ============================================================ function Read-ConfirmedPassword { while ($true) { Write-Host "" Write-Host ` "Introduce la contraseña para '$Username'." ` -ForegroundColor Cyan $password1 = Read-Host ` "Contraseña" ` -AsSecureString $password2 = Read-Host ` "Repite la contraseña" ` -AsSecureString $ptr1 = [IntPtr]::Zero $ptr2 = [IntPtr]::Zero try { $ptr1 = [Runtime.InteropServices.Marshal]::SecureStringToBSTR( $password1 ) $ptr2 = [Runtime.InteropServices.Marshal]::SecureStringToBSTR( $password2 ) $plain1 = [Runtime.InteropServices.Marshal]::PtrToStringBSTR( $ptr1 ) $plain2 = [Runtime.InteropServices.Marshal]::PtrToStringBSTR( $ptr2 ) if ([string]::IsNullOrWhiteSpace($plain1)) { Write-ErrorMessage ` "La contraseña no puede estar vacía." continue } if ($plain1 -cne $plain2) { Write-ErrorMessage ` "Las contraseñas no coinciden." continue } return $password1 } finally { if ($ptr1 -ne [IntPtr]::Zero) { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR( $ptr1 ) } if ($ptr2 -ne [IntPtr]::Zero) { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR( $ptr2 ) } $plain1 = $null $plain2 = $null } } } # ============================================================ # CREAR USUARIO # ============================================================ function Ensure-TechnicalUser { param ( [Parameter(Mandatory)] [string]$Name ) $existingUser = Get-LocalUserSafe -Name $Name # -------------------------------------------------------- # EL USUARIO YA EXISTE # -------------------------------------------------------- if ($null -ne $existingUser) { Write-Ok ` "El usuario '$Name' ya existe." return $existingUser } # -------------------------------------------------------- # CREAR USUARIO # -------------------------------------------------------- Write-Host "" Write-Host ` "El usuario '$Name' no existe." ` -ForegroundColor Yellow $password = Read-ConfirmedPassword Write-Host "" Write-Host ` "Creando usuario '$Name'..." ` -ForegroundColor Cyan try { $newUser = New-LocalUser ` -Name $Name ` -Password $password ` -Description "Cuenta técnica de administración" ` -AccountNeverExpires ` -PasswordNeverExpires:$true ` -ErrorAction Stop # VERIFICACIÓN INMEDIATA $verifiedUser = Get-LocalUserSafe -Name $Name if ($null -eq $verifiedUser) { throw ` "New-LocalUser terminó correctamente pero el usuario no aparece." } Write-Ok ` "Usuario '$Name' creado correctamente." return $verifiedUser } catch { throw ` "No se pudo crear el usuario '$Name': $($_.Exception.Message)" } } # ============================================================ # ACTIVAR ESCRITORIO REMOTO # ============================================================ function Enable-RemoteDesktop { Write-Host "" Write-Host ` "Activando Escritorio remoto..." ` -ForegroundColor Cyan # -------------------------------------------------------- # REGISTRO DE WINDOWS # # fDenyTSConnections: # # 1 = RDP desactivado # 0 = RDP activado # -------------------------------------------------------- $rdpRegistryPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" Set-ItemProperty ` -Path $rdpRegistryPath ` -Name "fDenyTSConnections" ` -Type DWord ` -Value 0 ` -ErrorAction Stop # Verificación. $rdpValue = ( Get-ItemProperty ` -Path $rdpRegistryPath ` -Name "fDenyTSConnections" ` -ErrorAction Stop ).fDenyTSConnections if ($rdpValue -ne 0) { throw ` "No se pudo activar RDP en el registro." } Write-Ok ` "Windows tiene Escritorio remoto activado." # -------------------------------------------------------- # SERVICIO TermService # -------------------------------------------------------- $service = Get-Service ` -Name "TermService" ` -ErrorAction Stop # No necesitamos forzar "Automático". # Manual es suficiente y Windows lo inicia cuando corresponde. Set-Service ` -Name "TermService" ` -StartupType Manual ` -ErrorAction Stop # Arrancamos el servicio si está parado. $service = Get-Service ` -Name "TermService" ` -ErrorAction Stop if ($service.Status -ne "Running") { Start-Service ` -Name "TermService" ` -ErrorAction Stop } # Verificación. $service = Get-Service ` -Name "TermService" ` -ErrorAction Stop if ($service.Status -ne "Running") { throw ` "El servicio TermService no está ejecutándose." } Write-Ok ` "Servicio de Escritorio remoto funcionando." # -------------------------------------------------------- # FIREWALL # -------------------------------------------------------- $firewallRules = Get-NetFirewallRule ` -ErrorAction Stop | Where-Object { $_.DisplayGroup -eq "Remote Desktop" -or $_.DisplayGroup -eq "Escritorio remoto" } if ($null -eq $firewallRules) { throw ` "No se encontraron las reglas de Firewall de Escritorio remoto." } $firewallRules | Enable-NetFirewallRule ` -ErrorAction Stop # Verificar que al menos una regla está habilitada. $enabledRules = $firewallRules | Where-Object { $_.Enabled -eq "True" } if ($null -eq $enabledRules) { throw ` "No se pudo habilitar ninguna regla de Firewall de RDP." } Write-Ok ` "Firewall de Escritorio remoto configurado." } # ============================================================ # OCULTAR USUARIO DEL LOGIN # ============================================================ function Hide-UserFromLogin { param ( [Parameter(Mandatory)] [string]$Username ) Write-Host "" Write-Host ` "Ocultando '$Username' de la pantalla de login..." ` -ForegroundColor Cyan $registryPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" # Crear la clave si no existe. if (-not (Test-Path $registryPath)) { New-Item ` -Path $registryPath ` -Force ` -ErrorAction Stop | Out-Null } # 0 = no mostrar el usuario en la lista. New-ItemProperty ` -Path $registryPath ` -Name $Username ` -PropertyType DWord ` -Value 0 ` -Force ` -ErrorAction Stop | Out-Null # VERIFICACIÓN $value = ( Get-ItemProperty ` -Path $registryPath ` -Name $Username ` -ErrorAction Stop ).$Username if ($value -ne 0) { throw ` "No se pudo ocultar '$Username' de la pantalla de login." } Write-Ok ` "'$Username' está oculto de la lista de usuarios del login." } # ============================================================ # VERIFICACIÓN FINAL COMPLETA # ============================================================ function Test-FinalConfiguration { Write-Step ` "VERIFICACIÓN FINAL DEL SISTEMA" $allOk = $true # -------------------------------------------------------- # USUARIO # -------------------------------------------------------- $user = Get-LocalUserSafe -Name $Username if ($null -ne $user) { Write-Ok "Usuario '$Username': EXISTE" } else { Write-ErrorMessage "Usuario '$Username': NO EXISTE" $allOk = $false } # -------------------------------------------------------- # GRUPO ADMINISTRADORES # -------------------------------------------------------- try { $administratorsGroup = Get-LocalGroupBySid "S-1-5-32-544" if (Test-UserInGroup ` -Username $Username ` -Group $administratorsGroup) { Write-Ok ` "Administrador: SI" } else { Write-ErrorMessage ` "Administrador: NO" $allOk = $false } } catch { Write-ErrorMessage ` "No se pudo comprobar el grupo Administradores." $allOk = $false } # -------------------------------------------------------- # RDP # -------------------------------------------------------- try { $rdpRegistryPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" $rdpValue = ( Get-ItemProperty ` -Path $rdpRegistryPath ` -Name "fDenyTSConnections" ` -ErrorAction Stop ).fDenyTSConnections if ($rdpValue -eq 0) { Write-Ok ` "Escritorio remoto de Windows: ACTIVADO" } else { Write-ErrorMessage ` "Escritorio remoto de Windows: DESACTIVADO" $allOk = $false } } catch { Write-ErrorMessage ` "No se pudo comprobar la configuración RDP." $allOk = $false } # -------------------------------------------------------- # SERVICIO RDP # -------------------------------------------------------- try { $service = Get-Service ` -Name "TermService" ` -ErrorAction Stop if ($service.Status -eq "Running") { Write-Ok ` "Servicio TermService: EJECUTÁNDOSE" } else { Write-ErrorMessage ` "Servicio TermService: $($service.Status)" $allOk = $false } } catch { Write-ErrorMessage ` "No se pudo comprobar TermService." $allOk = $false } # -------------------------------------------------------- # USUARIO EN GRUPO RDP # -------------------------------------------------------- try { $rdpGroup = Get-LocalGroupBySid "S-1-5-32-555" if (Test-UserInGroup ` -Username $Username ` -Group $rdpGroup) { Write-Ok ` "Usuario autorizado para RDP: SI" } else { Write-ErrorMessage ` "Usuario autorizado para RDP: NO" $allOk = $false } } catch { Write-ErrorMessage ` "No se pudo comprobar el grupo de usuarios RDP." $allOk = $false } # -------------------------------------------------------- # USUARIO OCULTO # -------------------------------------------------------- try { $loginPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" $hiddenValue = ( Get-ItemProperty ` -Path $loginPath ` -Name $Username ` -ErrorAction Stop ).$Username if ($hiddenValue -eq 0) { Write-Ok ` "Usuario oculto del login: SI" } else { Write-ErrorMessage ` "Usuario oculto del login: NO" $allOk = $false } } catch { Write-ErrorMessage ` "No se pudo comprobar la ocultación del usuario." $allOk = $false } # -------------------------------------------------------- # RESULTADO # -------------------------------------------------------- Write-Host "" if ($allOk) { Write-Host ` "==================================================" ` -ForegroundColor Green Write-Host ` " TODO CORRECTO" ` -ForegroundColor Green Write-Host ` "==================================================" ` -ForegroundColor Green return $true } else { Write-Host ` "==================================================" ` -ForegroundColor Red Write-Host ` " HAY ERRORES" ` -ForegroundColor Red Write-Host ` "==================================================" ` -ForegroundColor Red return $false } } # ============================================================ # PROGRAMA PRINCIPAL # ============================================================ try { Clear-Host Write-Host "" Write-Host ` "==================================================" ` -ForegroundColor Cyan Write-Host ` " WINDOWS 10 - CONFIGURACIÓN INICIAL" ` -ForegroundColor Cyan Write-Host ` "==================================================" ` -ForegroundColor Cyan Write-Host "" Write-Host "Usuario técnico: $Username" Write-Host "" # -------------------------------------------------------- # 0. ADMINISTRADOR # -------------------------------------------------------- Ensure-Administrator Write-Ok ` "El script se está ejecutando como Administrador." # -------------------------------------------------------- # 1. OBTENER GRUPOS # -------------------------------------------------------- Write-Step ` "COMPROBANDO GRUPOS LOCALES" $administratorsGroup = Get-LocalGroupBySid "S-1-5-32-544" $rdpGroup = Get-LocalGroupBySid "S-1-5-32-555" Write-Ok ` "Grupo Administradores: $($administratorsGroup.Name)" Write-Ok ` "Grupo Escritorio remoto: $($rdpGroup.Name)" # -------------------------------------------------------- # 2. CREAR USUARIO # -------------------------------------------------------- Write-Step ` "CREANDO / COMPROBANDO USUARIO" Ensure-TechnicalUser ` -Name $Username | Out-Null # -------------------------------------------------------- # 3. ADMINISTRADORES # -------------------------------------------------------- Write-Step ` "CONFIGURANDO PRIVILEGIOS DE ADMINISTRADOR" Ensure-UserInGroup ` -Username $Username ` -Group $administratorsGroup # -------------------------------------------------------- # 4. ESCRITORIO REMOTO # -------------------------------------------------------- Write-Step ` "ACTIVANDO ESCRITORIO REMOTO" Enable-RemoteDesktop # -------------------------------------------------------- # 5. AUTORIZAR USUARIO PARA RDP # -------------------------------------------------------- Write-Step ` "AUTORIZANDO USUARIO PARA ESCRITORIO REMOTO" Ensure-UserInGroup ` -Username $Username ` -Group $rdpGroup # -------------------------------------------------------- # 6. OCULTAR USUARIO # -------------------------------------------------------- Write-Step ` "OCULTANDO USUARIO DE LA PANTALLA DE LOGIN" Hide-UserFromLogin ` -Username $Username # -------------------------------------------------------- # 7. VERIFICACIÓN FINAL # -------------------------------------------------------- $result = Test-FinalConfiguration # -------------------------------------------------------- # SALIDA # -------------------------------------------------------- Write-Host "" if ($result) { Write-Host ` "La configuración se ha completado correctamente." ` -ForegroundColor Green Write-Host "" Write-Host ` "Puedes volver a ejecutar este script sin problema." ` -ForegroundColor Green Write-Host "" exit 0 } else { Write-Host "" Write-Host ` "La configuración NO se ha completado correctamente." ` -ForegroundColor Red Write-Host "" Write-Host ` "Revisa los errores mostrados arriba." ` -ForegroundColor Yellow Write-Host "" exit 1 } } catch { # ======================================================== # ERROR NO CONTROLADO # ======================================================== Write-Host "" Write-Host ` "==================================================" ` -ForegroundColor Red Write-Host ` " ERROR FATAL" ` -ForegroundColor Red Write-Host ` "==================================================" ` -ForegroundColor Red Write-Host "" Write-ErrorMessage ` $_.Exception.Message Write-Host "" Write-Host ` "El script se ha detenido para evitar continuar" ` -ForegroundColor Yellow Write-Host ` "con una configuración incompleta." ` -ForegroundColor Yellow Write-Host "" exit 1 } ```