Files
crbWinConf/setup.ps1
2026-09-24 16:02:34 +02:00

997 lines
24 KiB
PowerShell

#Requires -Version 5.1
<#
.SYNOPSIS
Configuración inicial de Windows 10.
.DESCRIPTION
Configura una cuenta técnica llamada "tecnica" y habilita
Escritorio Remoto.
Características:
- Se autoeleva a Administrador.
- Crea "tecnica" si no existe.
- Solicita y confirma la contraseña al crearla.
- NO cambia la contraseña si "tecnica" ya existe.
- Añade "tecnica" al grupo Administradores.
- Activa Escritorio Remoto.
- Configura el Firewall para RDP.
- Añade "tecnica" al grupo Usuarios de escritorio remoto.
- Oculta "tecnica" de la lista de usuarios del login.
- Verifica el estado real al finalizar.
- Devuelve 0 si todo está correcto.
- Devuelve 1 si hay algún error.
.NOTES
Compatible con Windows 10 / PowerShell 5.1.
#>
# ============================================================
# CONFIGURACIÓN
# ============================================================
$Username = "tecnica"
# ============================================================
# CONFIGURACIÓN DE ERRORES
# ============================================================
$ErrorActionPreference = "Stop"
# ============================================================
# FUNCIONES DE SALIDA
# ============================================================
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 "Se necesitan permisos de Administrador."
Write-Host "Solicitando elevación mediante UAC..." -ForegroundColor Yellow
Write-Host ""
if (-not $PSCommandPath) {
Write-ErrorMessage "No se puede determinar la ruta del script."
exit 1
}
try {
$quotedScript = '"' + $PSCommandPath + '"'
$process = Start-Process `
-FilePath "powershell.exe" `
-ArgumentList @(
"-NoProfile"
"-ExecutionPolicy"
"Bypass"
"-File"
$quotedScript
) `
-Verb RunAs `
-Wait `
-PassThru `
-ErrorAction Stop
exit $process.ExitCode
}
catch {
Write-ErrorMessage "No se pudo obtener permisos de Administrador."
Write-ErrorMessage $_.Exception.Message
exit 1
}
}
# ============================================================
# OBTENER USUARIO LOCAL
# ============================================================
function Get-LocalUserSafe {
param (
[Parameter(Mandatory)]
[string]$Name
)
try {
return Get-LocalUser -Name $Name -ErrorAction Stop
}
catch {
return $null
}
}
# ============================================================
# OBTENER GRUPO LOCAL MEDIANTE SID
# ============================================================
function Get-LocalGroupBySid {
param (
[Parameter(Mandatory)]
[string]$Sid
)
$group = Get-LocalGroup -ErrorAction Stop |
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
}
# ============================================================
# COMPROBAR USUARIO EN GRUPO
# ============================================================
function Test-UserInGroup {
param (
[Parameter(Mandatory)]
[string]$Username,
[Parameter(Mandatory)]
$Group
)
try {
$members = Get-LocalGroupMember `
-Group $Group.Name `
-ErrorAction Stop
foreach ($member in $members) {
$memberName = $member.Name
if ($memberName -match "\\") {
$memberName = $memberName.Split("\")[-1]
}
if ($memberName -ieq $Username) {
return $true
}
}
return $false
}
catch {
return $false
}
}
# ============================================================
# AÑADIR USUARIO A GRUPO
# ============================================================
function Ensure-UserInGroup {
param (
[Parameter(Mandatory)]
[string]$Username,
[Parameter(Mandatory)]
$Group
)
if (Test-UserInGroup -Username $Username -Group $Group) {
Write-Ok "'$Username' ya pertenece a '$($Group.Name)'."
return
}
Write-Host ""
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 '$Username' no aparece en '$($Group.Name)' después de añadirlo."
}
Write-Ok "'$Username' pertenece ahora a '$($Group.Name)'."
}
# ============================================================
# PEDIR Y CONFIRMAR CONTRASEÑA
# ============================================================
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
$plain1 = $null
$plain2 = $null
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 / COMPROBAR USUARIO TÉCNICO
# ============================================================
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 {
New-LocalUser `
-Name $Name `
-Password $password `
-Description "Cuenta técnica de administración" `
-AccountNeverExpires `
-PasswordNeverExpires `
-ErrorAction Stop | Out-Null
# Verificación real.
$verifiedUser = Get-LocalUserSafe -Name $Name
if ($null -eq $verifiedUser) {
throw "New-LocalUser terminó pero el usuario '$Name' no existe."
}
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
# --------------------------------------------------------
$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 "Windows sigue teniendo RDP desactivado."
}
Write-Ok "RDP está activado en el registro de Windows."
# --------------------------------------------------------
# SERVICIO
# --------------------------------------------------------
$service = Get-Service `
-Name "TermService" `
-ErrorAction Stop
if ($service.StartType -ne "Manual") {
Set-Service `
-Name "TermService" `
-StartupType Manual `
-ErrorAction Stop
}
$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 TermService 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
# Verificación REAL de las reglas.
$enabledRules = Get-NetFirewallRule `
-ErrorAction Stop |
Where-Object {
(
$_.DisplayGroup -eq "Remote Desktop" -or
$_.DisplayGroup -eq "Escritorio remoto"
) -and
$_.Enabled -eq "True"
}
if ($null -eq $enabledRules) {
throw "No hay ninguna regla de Firewall de RDP habilitada."
}
Write-Ok "Firewall de Escritorio remoto habilitado."
}
# ============================================================
# OCULTAR USUARIO DE LA PANTALLA DE 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 = ocultar usuario.
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' del login."
}
Write-Ok "'$Username' está oculto de la lista de usuarios."
}
# ============================================================
# VERIFICACIÓN FINAL
# ============================================================
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
}
# --------------------------------------------------------
# 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 REGISTRO
# --------------------------------------------------------
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
# --------------------------------------------------------
try {
$service = Get-Service `
-Name "TermService" `
-ErrorAction Stop
if ($service.Status -eq "Running") {
Write-Ok "TermService: EJECUTÁNDOSE"
}
else {
Write-ErrorMessage "TermService: $($service.Status)"
$allOk = $false
}
}
catch {
Write-ErrorMessage "No se pudo comprobar TermService."
$allOk = $false
}
# --------------------------------------------------------
# FIREWALL
# --------------------------------------------------------
try {
$enabledRules = Get-NetFirewallRule `
-ErrorAction Stop |
Where-Object {
(
$_.DisplayGroup -eq "Remote Desktop" -or
$_.DisplayGroup -eq "Escritorio remoto"
) -and
$_.Enabled -eq "True"
}
if ($null -ne $enabledRules) {
Write-Ok "Firewall RDP: HABILITADO"
}
else {
Write-ErrorMessage "Firewall RDP: NO HABILITADO"
$allOk = $false
}
}
catch {
Write-ErrorMessage "No se pudo comprobar el Firewall de RDP."
$allOk = $false
}
# --------------------------------------------------------
# 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 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. COMPROBAR 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 / COMPROBAR USUARIO
# --------------------------------------------------------
Write-Step "CREANDO / COMPROBANDO USUARIO"
$user = Ensure-TechnicalUser -Name $Username
# --------------------------------------------------------
# 3. ASEGURAR USUARIO HABILITADO
# --------------------------------------------------------
if (-not $user.Enabled) {
Write-Host "La cuenta está deshabilitada. Habilitándola..." `
-ForegroundColor Yellow
Enable-LocalUser `
-Name $Username `
-ErrorAction Stop
$user = Get-LocalUserSafe -Name $Username
if ($null -eq $user -or -not $user.Enabled) {
throw "No se pudo habilitar el usuario '$Username'."
}
Write-Ok "Usuario '$Username' habilitado."
}
else {
Write-Ok "Usuario '$Username' está habilitado."
}
# --------------------------------------------------------
# 4. ADMINISTRADORES
# --------------------------------------------------------
Write-Step "CONFIGURANDO PRIVILEGIOS DE ADMINISTRADOR"
Ensure-UserInGroup `
-Username $Username `
-Group $administratorsGroup
# --------------------------------------------------------
# 5. ESCRITORIO REMOTO
# --------------------------------------------------------
Write-Step "ACTIVANDO ESCRITORIO REMOTO"
Enable-RemoteDesktop
# --------------------------------------------------------
# 6. USUARIO AUTORIZADO PARA RDP
# --------------------------------------------------------
Write-Step "AUTORIZANDO USUARIO PARA ESCRITORIO REMOTO"
Ensure-UserInGroup `
-Username $Username `
-Group $rdpGroup
# --------------------------------------------------------
# 7. OCULTAR USUARIO
# --------------------------------------------------------
Write-Step "OCULTANDO USUARIO DE LA PANTALLA DE LOGIN"
Hide-UserFromLogin `
-Username $Username
# --------------------------------------------------------
# 8. VERIFICACIÓN FINAL
# --------------------------------------------------------
$result = Test-FinalConfiguration
# --------------------------------------------------------
# RESULTADO
# --------------------------------------------------------
Write-Host ""
if ($result) {
Write-Host "La configuración se ha completado correctamente." `
-ForegroundColor Green
Write-Host ""
Write-Host "El script se puede ejecutar de nuevo sin cambiar" `
-ForegroundColor Green
Write-Host "la contraseña del usuario existente." `
-ForegroundColor Green
Write-Host ""
exit 0
}
else {
Write-Host "La configuración NO se ha completado correctamente." `
-ForegroundColor Red
Write-Host ""
Write-Host "Revisa los errores mostrados anteriormente." `
-ForegroundColor Yellow
Write-Host ""
exit 1
}
}
catch {
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
}