Files
crbWinConf/setup.ps1
2026-09-24 15:30:36 +02:00

1116 lines
25 KiB
PowerShell

```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
}
```