📝 Gestion-linux-scripting
← Volver

Gestión de Active Directory, Linux y Scripting

Guía técnica completa: Usuarios, Grupos, GPO, Sistemas de Ficheros y Scripts de Administración


Índice

  1. Active Directory – Gestión de Usuarios
  2. Active Directory – Gestión de Grupos
  3. Active Directory – Directivas de Grupo (GPO)
  4. Linux – Gestión de Usuarios y Grupos
  5. Linux – Sistema de Ficheros y Permisos
  6. Scripting – PowerShell para Active Directory
  7. Scripting – Bash para Linux
  8. Casos de Uso Combinados

1. Active Directory – Gestión de Usuarios

1.1 Conceptos Clave

Término Descripción
DN (Distinguished Name) Ruta completa del objeto: CN=Juan,OU=Ventas,DC=empresa,DC=local
UPN (User Principal Name) Nombre de inicio de sesión: juan@empresa.local
SAMAccountName Login heredado (NetBIOS): EMPRESA\juan
SID Identificador único de seguridad, permanente e irrepetible
GUID Identificador global único del objeto en el directorio
OU (Organizational Unit) Contenedor lógico para organizar objetos y aplicar GPOs

1.2 Ciclo de Vida de un Usuario

Creación → Configuración → Habilitación → Uso → Bloqueo/Deshabilitación → Eliminación

1.3 Atributos Importantes de una Cuenta de Usuario

- displayName          → Nombre completo mostrado
- sAMAccountName       → Nombre de cuenta (único en el dominio)
- userPrincipalName    → UPN (único en el bosque)
- mail                 → Correo electrónico
- telephoneNumber      → Teléfono
- department           → Departamento
- title                → Cargo
- manager              → Jefe directo (referencia a otro objeto)
- memberOf             → Grupos a los que pertenece
- accountExpires       → Fecha de expiración de la cuenta
- pwdLastSet           → Última vez que se cambió la contraseña
- logonHours           → Horas permitidas de inicio de sesión
- userWorkstations     → Equipos desde los que puede iniciar sesión
- homeDirectory        → Ruta del directorio personal
- homeDrive            → Letra de unidad del directorio personal (ej: H:)
- scriptPath           → Script de inicio de sesión
- profilePath          → Perfil de usuario en red

1.4 Creación de Usuarios en Active Directory Users and Computers (ADUC)

  1. Abrir dsa.msc (Active Directory Users and Computers)
  2. Navegar a la OU destino
  3. Clic derecho → New → User
  4. Rellenar: First Name, Last Name, User Logon Name (UPN)
  5. Establecer contraseña y opciones:
    - User must change password at next logon
    - User cannot change password
    - Password never expires
    - Account is disabled
  6. Completar propiedades adicionales (departamento, teléfono, etc.)

1.5 Propiedades de Cuenta – Opciones de Contraseña

Opción Uso Recomendado
Cambiar contraseña en el próximo inicio Cuentas nuevas o restablecidas
Contraseña nunca caduca Cuentas de servicio (con precaución)
No puede cambiar contraseña Cuentas compartidas o de servicio
Cuenta deshabilitada Usuarios de baja o temporales
Cuenta bloqueada Visible solo si hay bloqueo activo

1.6 Perfiles de Usuario

Tipo Descripción
Local Almacenado en el equipo local
Móvil (Roaming) Sincronizado con un servidor al iniciar/cerrar sesión
Obligatorio Perfil móvil de solo lectura, no se guardan cambios
Temporal Se crea si el perfil asignado no está disponible
Ruta perfil móvil: \\servidor\perfiles$\%username%

2. Active Directory – Gestión de Grupos

2.1 Tipos de Grupos

Por Alcance (Scope)

Alcance Miembros pueden ser Ámbito de uso
Local de Dominio Usuarios, grupos globales y universales de cualquier dominio Solo en el dominio donde se define
Global Usuarios y grupos globales del mismo dominio Cualquier dominio del bosque
Universal Usuarios y grupos de cualquier dominio del bosque Cualquier dominio del bosque

Por Tipo

Tipo Uso
Seguridad Asignar permisos a recursos; también puede usarse como lista de distribución
Distribución Solo para listas de correo (sin permisos de seguridad)

2.2 Estrategia AGDLP

La mejor práctica de Microsoft para gestionar permisos:

A  → Accounts (Cuentas de usuario)
G  → Global Groups (Grupos Globales)
DL → Domain Local Groups (Grupos Locales de Dominio)
P  → Permissions (Permisos sobre el recurso)

Flujo:

Usuario → Grupo Global → Grupo Local de Dominio → Permiso en recurso

Ejemplo práctico:

Juan (cuenta)
  └─ G_Ventas (Grupo Global – todos los comerciales)
       └─ DL_CarpetaVentas_Escritura (Grupo Local de Dominio)
            └─ Permiso: Escritura en \\servidor\Ventas

Ventaja: Al añadir un empleado a G_Ventas, automáticamente obtiene todos los permisos asociados a ese grupo global.

2.3 Grupos Predeterminados Importantes

Grupo Descripción
Domain Admins Administradores del dominio (máximo privilegio en el dominio)
Enterprise Admins Administradores del bosque completo
Schema Admins Pueden modificar el esquema de AD
Domain Users Todos los usuarios del dominio (grupo predeterminado)
Domain Computers Todos los equipos unidos al dominio
Administrators Admins locales en todos los DCs
Backup Operators Pueden hacer copias sin ser administradores
Remote Desktop Users Acceso RDP a equipos
Group Policy Creator Owners Pueden crear y gestionar GPOs
Account Operators Pueden crear/gestionar cuentas (no admins)
Server Operators Pueden gestionar servidores

2.4 Grupos Especiales (Identidades Especiales)

Grupos implícitos que no se gestionan manualmente:

Grupo Descripción
Everyone Todos, incluidos usuarios no autenticados (con cuidado)
Authenticated Users Todos los usuarios autenticados en el dominio
CREATOR OWNER El propietario del objeto o archivo
NETWORK Usuarios que acceden a través de la red
INTERACTIVE Usuarios que inician sesión localmente
SYSTEM El propio sistema operativo
SERVICE Servicios del sistema

3. Active Directory – Directivas de Grupo (GPO)

3.1 Conceptos Fundamentales

Término Descripción
GPO Group Policy Object – Colección de configuraciones
GPMC Group Policy Management Console (gpmc.msc)
GPEdit Editor de directivas locales (gpedit.msc)
SYSVOL Carpeta compartida en DCs que contiene los archivos de GPO
ADMX Plantillas administrativas (formato XML moderno)
ADM Plantillas administrativas (formato antiguo)
Resultant Set of Policy (RSoP) Conjunto resultante de directivas aplicadas
Loopback Processing Aplica las GPO del equipo al usuario que inicia sesión

3.2 Estructura de una GPO

GPO
├── Computer Configuration (Configuración del equipo)
│   ├── Policies (Directivas)
│   │   ├── Software Settings
│   │   │   └── Software Installation
│   │   ├── Windows Settings
│   │   │   ├── Scripts (Startup/Shutdown)
│   │   │   ├── Security Settings
│   │   │   │   ├── Account Policies
│   │   │   │   │   ├── Password Policy
│   │   │   │   │   └── Account Lockout Policy
│   │   │   │   ├── Local Policies
│   │   │   │   ├── Windows Firewall
│   │   │   │   ├── Public Key Policies
│   │   │   │   └── Software Restriction Policies
│   │   │   └── Administrative Templates
│   │   └── Preferences
│   │       ├── Windows Settings
│   │       └── Control Panel Settings
└── User Configuration (Configuración del usuario)
    ├── Policies
    │   ├── Software Settings
    │   ├── Windows Settings
    │   │   ├── Scripts (Logon/Logoff)
    │   │   ├── Security Settings
    │   │   ├── Folder Redirection
    │   │   └── Administrative Templates
    │   └── Preferences
    └── Preferences

3.3 Orden de Aplicación de GPOs (LSDOU)

Las GPOs se aplican en este orden (cada nivel sobreescribe al anterior):

L → Local GPO           (equipo local)
S → Site GPO            (sitio de AD)
D → Domain GPO          (dominio)
O → Organizational Unit (OU padre → OU hijo, de más general a más específico)

Regla: La última en aplicarse tiene más prioridad. Dentro de cada nivel, el número de orden más bajo tiene más prioridad.

3.4 Herencia y Bloqueo

Opción Descripción
Enforced (Forzado) La GPO no puede ser bloqueada por niveles inferiores. Marca la GPO en el enlace.
Block Inheritance La OU bloquea todas las GPOs de niveles superiores (excepto las Enforced). Se aplica en la OU.
Disabled (Deshabilitado) El enlace de GPO está deshabilitado (no se aplica).

3.5 Filtrado de GPOs

Filtrado de Seguridad

Por defecto, una GPO se aplica a Authenticated Users. Se puede filtrar por:
- Usuarios específicos
- Grupos de seguridad
- Equipos

Para excluir un grupo: denegar el permiso Apply Group Policy.

Filtrado WMI (WMI Filters)

Aplica la GPO solo si se cumple una consulta WMI:

-- Ejemplo: Solo Windows 10
SELECT * FROM Win32_OperatingSystem WHERE Version LIKE "10.%" AND ProductType = "1"

-- Solo equipos con más de 4GB de RAM
SELECT * FROM Win32_ComputerSystem WHERE TotalPhysicalMemory >= 4294967296

-- Solo portátiles
SELECT * FROM Win32_SystemEnclosure WHERE ChassisTypes = 9 OR ChassisTypes = 10

3.6 Directivas de Contraseña

Fine-Grained Password Policies (PSO)

Permiten tener distintas políticas de contraseña para diferentes grupos/usuarios (desde Windows Server 2008):

Herramienta: ADSI Edit → CN=Password Settings Container,CN=System,DC=empresa,DC=local
Atributo PSO Descripción
msDS-PasswordSettingsPrecedence Prioridad (número menor = mayor prioridad)
msDS-PasswordReversibleEncryptionEnabled Cifrado reversible
msDS-PasswordHistoryLength Historial de contraseñas
msDS-PasswordComplexityEnabled Complejidad requerida
msDS-MinimumPasswordLength Longitud mínima
msDS-MinimumPasswordAge Edad mínima
msDS-MaximumPasswordAge Edad máxima
msDS-LockoutThreshold Intentos antes de bloqueo
msDS-LockoutObservationWindow Ventana de observación
msDS-LockoutDuration Duración del bloqueo

3.7 Configuraciones GPO Más Usadas

Seguridad de Cuentas

Computer Config → Windows Settings → Security Settings → Account Policies
├── Password Policy
│   ├── Enforce password history: 24 passwords
│   ├── Maximum password age: 60 days
│   ├── Minimum password age: 1 day
│   ├── Minimum password length: 12 characters
│   └── Password must meet complexity requirements: Enabled
└── Account Lockout Policy
    ├── Account lockout duration: 30 minutes
    ├── Account lockout threshold: 5 invalid attempts
    └── Reset account lockout counter after: 30 minutes

Redirección de Carpetas

User Config → Windows Settings → Folder Redirection
├── Desktop      → \\servidor\perfiles$\%username%\Desktop
├── Documents    → \\servidor\perfiles$\%username%\Documents
└── AppData      → \\servidor\perfiles$\%username%\AppData

Scripts de Inicio/Cierre de Sesión

User Config → Windows Settings → Scripts → Logon/Logoff
Computer Config → Windows Settings → Scripts → Startup/Shutdown

Mapeo de Unidades (Preferencias)

User Config → Preferences → Windows Settings → Drive Maps
→ New → Mapped Drive
  - Action: Create / Update / Replace / Delete
  - Location: \\servidor\compartido
  - Drive Letter: H:
  - Label: Datos personales
  - Item-level targeting: Grupo de seguridad

Restricciones de Software (AppLocker)

Computer Config → Windows Settings → Security Settings → Application Control Policies → AppLocker
├── Executable Rules (.exe, .com)
├── Windows Installer Rules (.msi, .msp)
├── Script Rules (.ps1, .bat, .vbs)
└── Packaged App Rules (UWP)

3.8 Comandos de GPO en el Equipo Cliente

:: Actualizar directivas inmediatamente
gpupdate /force

:: Ver directivas aplicadas (HTML)
gpresult /h C:\GPReport.html /f

:: Ver directivas de usuario actual
gpresult /r

:: Ver directivas de usuario específico
gpresult /user DOMINIO\usuario /r

:: Ver directivas de un equipo remoto
gpresult /s nombreequipo /r

:: Diagnóstico de RSoP (GUI)
rsop.msc

4. Linux – Gestión de Usuarios y Grupos

4.1 Archivos del Sistema

Archivo Contenido
/etc/passwd Información de usuarios (nombre, UID, GID, home, shell)
/etc/shadow Contraseñas cifradas y políticas de expiración
/etc/group Información de grupos
/etc/gshadow Contraseñas cifradas de grupos
/etc/skel/ Plantilla para el directorio home de nuevos usuarios
/etc/login.defs Configuración global de usuarios (UID/GID range, políticas)
/etc/default/useradd Valores por defecto al crear usuarios

4.2 Estructura de /etc/passwd

usuario:x:1001:1001:Nombre Completo,,,:/home/usuario:/bin/bash
   1    2   3    4         5              6         7

1 - Nombre de usuario
2 - Contraseña (x = en /etc/shadow)
3 - UID (User ID)
4 - GID (Group ID principal)
5 - GECOS (información adicional: nombre, teléfono, etc.)
6 - Directorio home
7 - Shell por defecto

4.3 Estructura de /etc/shadow

usuario:$6$sal$hash:18500:0:99999:7:::
   1         2        3   4   5   6 7 8 9

1 - Usuario
2 - Contraseña cifrada ($6$ = SHA-512, $5$ = SHA-256, $1$ = MD5)
3 - Días desde epoch del último cambio
4 - Días mínimos antes de poder cambiar contraseña
5 - Días máximos de validez de contraseña
6 - Días de aviso antes de expiración
7 - Días de gracia tras expiración
8 - Fecha de expiración de cuenta (días desde epoch, vacío = nunca)
9 - Reservado

4.4 Gestión de Usuarios – Comandos

Crear Usuarios

# Sintaxis básica
useradd [opciones] nombre_usuario

# Opciones importantes
useradd -m             # Crear directorio home
useradd -d /ruta/home  # Especificar ruta del home
useradd -s /bin/bash   # Shell por defecto
useradd -g grupo       # Grupo principal
useradd -G g1,g2,g3    # Grupos secundarios
useradd -u 1500        # UID específico
useradd -c "Nombre Completo" # Comentario/GECOS
useradd -e 2025-12-31  # Fecha de expiración (YYYY-MM-DD)
useradd -r             # Cuenta de sistema (UID < 1000, sin home)
useradd -M             # NO crear directorio home
useradd -N             # No crear grupo con el mismo nombre
useradd -k /ruta/skel  # Plantilla skel alternativa
useradd -p 'hash'      # Contraseña ya cifrada

# Ejemplo completo
useradd -m -d /home/jgarcia -s /bin/bash \
        -g empleados -G sudo,docker \
        -c "Juan García,Ventas,+34912345678" \
        -e 2026-06-30 jgarcia

Establecer/Cambiar Contraseña

# Establecer contraseña (interactivo)
passwd nombre_usuario

# Generar contraseña aleatoria y asignarla
openssl rand -base64 12 | passwd --stdin nombre_usuario  # RHEL/CentOS
echo "nuevapass" | chpasswd                               # Debian/Ubuntu

# Forzar cambio de contraseña en próximo login
passwd -e nombre_usuario
chage -d 0 nombre_usuario

# Bloquear/desbloquear cuenta
passwd -l nombre_usuario   # Lock (añade ! al hash)
passwd -u nombre_usuario   # Unlock

# Ver estado de contraseña
passwd -S nombre_usuario
chage -l nombre_usuario

Modificar Usuarios

# Sintaxis: usermod [opciones] usuario
usermod -l nuevo_nombre viejo_nombre  # Cambiar nombre de usuario
usermod -d /nueva/ruta -m usuario     # Mover directorio home
usermod -s /bin/zsh usuario           # Cambiar shell
usermod -g nuevo_grupo usuario        # Cambiar grupo principal
usermod -G g1,g2,g3 usuario          # Reemplazar grupos secundarios
usermod -aG grupo usuario             # AÑADIR a grupo secundario (sin borrar otros)
usermod -u 1600 usuario               # Cambiar UID
usermod -L usuario                    # Bloquear cuenta
usermod -U usuario                    # Desbloquear cuenta
usermod -e 2026-12-31 usuario         # Cambiar fecha expiración
usermod -e "" usuario                 # Quitar expiración
usermod -c "Nuevo comentario" usuario # Cambiar GECOS

Eliminar Usuarios

userdel usuario          # Eliminar usuario (mantiene home y archivos)
userdel -r usuario       # Eliminar usuario + home + archivos de correo
userdel -f usuario       # Forzar eliminación aunque el usuario tenga sesión activa

# Buena práctica: antes de eliminar, buscar archivos del usuario
find / -user nombre_usuario 2>/dev/null
find / -uid 1001 2>/dev/null  # Por UID (más seguro si el nombre cambió)

4.5 Políticas de Contraseña – chage

# Ver políticas actuales
chage -l usuario

# Establecer políticas
chage -m 1    usuario   # Mínimo 1 día entre cambios
chage -M 90   usuario   # Contraseña expira en 90 días
chage -W 14   usuario   # Avisar 14 días antes de expirar
chage -I 7    usuario   # 7 días de gracia tras expirar antes de bloquear
chage -E 2026-12-31 usuario  # Fecha de expiración de la cuenta

# Forzar cambio en próximo login
chage -d 0 usuario

# Modo interactivo
chage usuario

4.6 Gestión de Grupos

# Crear grupo
groupadd nombre_grupo
groupadd -g 2000 nombre_grupo    # GID específico
groupadd -r nombre_grupo         # Grupo del sistema

# Modificar grupo
groupmod -n nuevo_nombre viejo_nombre  # Renombrar
groupmod -g 2001 nombre_grupo          # Cambiar GID

# Eliminar grupo
groupdel nombre_grupo

# Añadir usuario a grupo
usermod -aG nombre_grupo usuario
gpasswd -a usuario nombre_grupo

# Eliminar usuario de grupo
gpasswd -d usuario nombre_grupo

# Ver miembros de un grupo
getent group nombre_grupo
grep "^nombre_grupo:" /etc/group
members nombre_grupo  # si el paquete 'members' está instalado

# Cambiar grupo principal temporalmente (sesión)
newgrp nombre_grupo

4.7 Consultar Información de Usuarios

# Información del usuario actual
whoami          # Nombre de usuario
id              # UID, GID y grupos
id usuario      # Info de otro usuario

# Usuarios conectados
who             # Usuarios con sesión activa
w               # Más detallado (procesos, tiempo inactivo)
last            # Historial de logins
lastlog         # Último login de todos los usuarios
users           # Lista simple de usuarios conectados

# Cambiar de usuario
su - usuario              # Cambiar a usuario (con entorno)
su -c "comando" usuario   # Ejecutar comando como otro usuario
sudo -u usuario comando   # Ejecutar como usuario (con sudo)
sudo -i                   # Shell de root

# Información de cuenta
finger usuario   # Si está instalado
getent passwd usuario

5. Linux – Sistema de Ficheros y Permisos

5.1 Tipos de Permisos

- rwx rwx rwx
│  │   │   └── Otros (Others)
│  │   └────── Grupo (Group)
│  └────────── Propietario (User/Owner)
└────────────── Tipo: - (fichero), d (directorio), l (enlace), b (bloque), c (carácter), p (pipe), s (socket)
Símbolo Octal Fichero Directorio
r 4 Leer contenido Listar contenido (ls)
w 2 Escribir/modificar Crear/eliminar archivos en él
x 1 Ejecutar Acceder/entrar (cd)
- 0 Sin permiso Sin permiso

5.2 Notación Octal

rwxr-xr--  =  7 5 4
───┬─── ─┬─ ─┬─
   7     5   4

r=4, w=2, x=1

Ejemplos:
777 = rwxrwxrwx  (todos los permisos a todos)
755 = rwxr-xr-x  (común en directorios y ejecutables)
644 = rw-r--r--  (común en ficheros)
600 = rw-------  (ficheros privados: SSH keys)
700 = rwx------  (directorios privados)
640 = rw-r-----  (ficheros de grupo)

5.3 Permisos Especiales

Permiso Octal En ficheros En directorios
SUID (Set User ID) 4000 Se ejecuta con los permisos del propietario Sin efecto especial
SGID (Set Group ID) 2000 Se ejecuta con los permisos del grupo Nuevos archivos heredan el grupo del directorio
Sticky Bit 1000 Obsoleto Solo el propietario puede eliminar sus archivos
# SUID en notación simbólica: s en posición de x del propietario
-rwsr-xr-x   # SUID activo (x presente)
-rwSr-xr-x   # SUID activo (x ausente) → Inútil

# SGID: s en posición de x del grupo
drwxrwsr-x   # SGID en directorio

# Sticky Bit: t en posición de x de otros
drwxrwxrwt   # Sticky bit activo (ej: /tmp)

# Ejemplos de archivos con SUID en el sistema
ls -la /usr/bin/passwd      # -rwsr-xr-x → necesita escribir /etc/shadow
ls -la /usr/bin/sudo        # -rwsr-xr-x
ls -la /tmp                 # drwxrwxrwt → sticky bit

5.4 Comandos de Permisos

chmod – Cambiar Permisos

# Notación octal
chmod 755 fichero
chmod 644 fichero
chmod -R 750 directorio   # Recursivo

# Notación simbólica
# [ugoa][+-=][rwxXstugo]
chmod u+x fichero         # Añadir ejecución al propietario
chmod g-w fichero         # Quitar escritura al grupo
chmod o=r fichero         # Establecer solo lectura para otros
chmod a+r fichero         # Añadir lectura a todos (a = ugo)
chmod u=rwx,g=rx,o= fichero  # Múltiples en una línea

# Permisos especiales
chmod u+s fichero         # SUID
chmod g+s directorio      # SGID
chmod +t directorio       # Sticky bit
chmod 4755 fichero        # SUID + 755
chmod 2775 directorio     # SGID + 775
chmod 1777 directorio     # Sticky + 777

# Solo cambiar directorios (no ficheros)
chmod -R u+X directorio   # X mayúscula: ejecutar solo si es directorio o ya es ejecutable

chown – Cambiar Propietario

chown usuario fichero                  # Cambiar propietario
chown usuario:grupo fichero            # Cambiar propietario y grupo
chown :grupo fichero                   # Cambiar solo grupo
chown -R usuario:grupo directorio      # Recursivo
chown --from=viejo_usuario nuevo_usuario fichero  # Cambiar solo si es propietario X

chgrp – Cambiar Grupo

chgrp grupo fichero
chgrp -R grupo directorio

5.5 Permisos Especiales Avanzados – ACLs

Las ACLs (Access Control Lists) permiten permisos más granulares que el modelo UGO clásico.

# Ver ACLs
getfacl fichero
getfacl -R directorio

# Establecer ACL para usuario
setfacl -m u:usuario:rwx fichero
setfacl -m u:usuario:r-- fichero

# Establecer ACL para grupo
setfacl -m g:grupo:rx fichero

# ACL por defecto en directorio (se heredan los nuevos archivos)
setfacl -d -m u:usuario:rwx directorio
setfacl -d -m g:grupo:rx directorio

# Eliminar ACL de usuario/grupo
setfacl -x u:usuario fichero
setfacl -x g:grupo fichero

# Eliminar TODAS las ACLs
setfacl -b fichero

# Copiar ACLs de un fichero a otro
getfacl fichero_origen | setfacl --set-file=- fichero_destino

# Aplicar recursivamente
setfacl -R -m u:usuario:rwX directorio

# Ejemplo: Directorio compartido de proyecto
setfacl -m g:proyectoA:rwx /datos/proyectoA
setfacl -d -m g:proyectoA:rwx /datos/proyectoA  # Heredar a nuevos archivos
setfacl -m u:auditor:r-x /datos/proyectoA       # Solo lectura para auditor

Indicador en ls -la: Un + al final de los permisos indica que tiene ACLs:

-rw-rw-r--+ 1 usuario grupo 0 ene 1 10:00 fichero

5.6 Atributos Inmutables – chattr

# Hacer fichero inmutable (ni root puede modificarlo)
chattr +i fichero

# Quitar inmutabilidad
chattr -i fichero

# Solo permite añadir datos (logs)
chattr +a fichero

# Ver atributos
lsattr fichero
lsattr -R directorio

5.7 umask – Permisos por Defecto

La umask define qué permisos se restan al crear nuevos ficheros/directorios.

# Ver umask actual
umask          # octal: 0022
umask -S       # simbólico: u=rwx,g=rx,o=rx

# Permisos máximos base:
# Ficheros:    666 (rw-rw-rw-)
# Directorios: 777 (rwxrwxrwx)

# Con umask 022:
# Ficheros:    666 - 022 = 644 (rw-r--r--)
# Directorios: 777 - 022 = 755 (rwxr-xr-x)

# Con umask 027:
# Ficheros:    666 - 027 = 640 (rw-r-----)
# Directorios: 777 - 027 = 750 (rwxr-x---)

# Establecer umask
umask 027

# Umask permanente para usuario
echo "umask 027" >> ~/.bashrc

# Umask permanente para el sistema
echo "umask 022" >> /etc/profile

5.8 Jerarquía del Sistema de Ficheros (FHS)

/
├── bin/       → Binarios esenciales (ls, cp, mv, bash...)
├── boot/      → Archivos de arranque (kernel, GRUB)
├── dev/       → Dispositivos (discos, terminales...)
├── etc/       → Configuración del sistema
├── home/      → Directorios de usuarios
├── lib/       → Bibliotecas compartidas
├── media/     → Puntos de montaje para medios extraíbles
├── mnt/       → Montajes temporales
├── opt/       → Software opcional/de terceros
├── proc/      → Sistema de ficheros virtual (procesos, kernel)
├── root/      → Home del usuario root
├── run/       → Datos en tiempo de ejecución
├── sbin/      → Binarios del sistema (para administración)
├── srv/       → Datos de servicios (web, FTP...)
├── sys/       → Sistema de ficheros virtual (kernel, hardware)
├── tmp/       → Archivos temporales (sticky bit)
├── usr/       → Aplicaciones y datos de usuario
│   ├── bin/   → Binarios de usuario
│   ├── lib/   → Bibliotecas
│   ├── local/ → Software instalado localmente
│   └── share/ → Datos independientes de arquitectura
└── var/       → Datos variables (logs, spool, bases de datos)
    ├── log/   → Registros del sistema
    ├── spool/ → Colas de impresión y correo
    └── www/   → Datos web (en muchas distros)

6. Scripting – PowerShell para Active Directory

6.1 Módulo RSAT y Conexión

# Importar módulo AD (necesario en algunos casos)
Import-Module ActiveDirectory

# Verificar módulo disponible
Get-Module -ListAvailable -Name ActiveDirectory

# Conectar a un dominio específico (o DC específico)
Get-ADUser -Identity "jgarcia" -Server "dc01.empresa.local"

# Ver el dominio actual
Get-ADDomain
Get-ADForest

6.2 Scripts de Gestión de Usuarios

Crear Usuario Completo

function New-ADUserCompleto {
    param(
        [Parameter(Mandatory)][string]$Nombre,
        [Parameter(Mandatory)][string]$Apellido,
        [Parameter(Mandatory)][string]$Departamento,
        [Parameter(Mandatory)][string]$OU,
        [string]$Dominio = "empresa.local",
        [string]$Servidor = "\\Servidor01\Perfiles$"
    )

    # Generar nombre de usuario
    $Username = ($Nombre.Substring(0,1) + $Apellido).ToLower() -replace '[áàâä]','a' -replace '[éèêë]','e' -replace '[íìîï]','i' -replace '[óòôö]','o' -replace '[úùûü]','u' -replace '[ñ]','n' -replace '\s',''

    # Verificar si ya existe
    if (Get-ADUser -Filter "SamAccountName -eq '$Username'" -ErrorAction SilentlyContinue) {
        $Username = $Username + (Get-Random -Minimum 1 -Maximum 99)
        Write-Warning "Usuario duplicado. Usando: $Username"
    }

    # Generar contraseña segura
    $Password = ConvertTo-SecureString "Contraseña@$(Get-Random -Min 1000 -Max 9999)" -AsPlainText -Force

    # Parámetros del usuario
    $Params = @{
        Name                  = "$Nombre $Apellido"
        GivenName             = $Nombre
        Surname               = $Apellido
        SamAccountName        = $Username
        UserPrincipalName     = "$Username@$Dominio"
        DisplayName           = "$Apellido, $Nombre"
        Department            = $Departamento
        Path                  = $OU
        AccountPassword       = $Password
        ChangePasswordAtLogon = $true
        Enabled               = $true
        HomeDirectory         = "$Servidor\$Username"
        HomeDrive             = "H:"
        ProfilePath           = "$Servidor\Profiles\$Username"
        Description           = "Creado por script el $(Get-Date -Format 'dd/MM/yyyy')"
    }

    try {
        New-ADUser @Params
        Write-Host "✓ Usuario '$Username' creado correctamente." -ForegroundColor Green

        # Crear directorio home
        $HomeDir = "$Servidor\$Username"
        if (-not (Test-Path $HomeDir)) {
            New-Item -ItemType Directory -Path $HomeDir | Out-Null
            # Asignar permisos al usuario en su home
            $Acl = Get-Acl $HomeDir
            $Rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
                "$Username", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"
            )
            $Acl.SetAccessRule($Rule)
            Set-Acl -Path $HomeDir -AclObject $Acl
            Write-Host "✓ Directorio home creado: $HomeDir" -ForegroundColor Green
        }

        return $Username
    }
    catch {
        Write-Error "Error al crear usuario: $_"
    }
}

# Uso
New-ADUserCompleto -Nombre "Juan" -Apellido "García" -Departamento "Ventas" -OU "OU=Ventas,DC=empresa,DC=local"

Creación Masiva desde CSV

# CSV esperado: Nombre,Apellido,Departamento,OU,Email,Telefono,Manager
function Import-ADUsersFromCSV {
    param(
        [Parameter(Mandatory)][string]$CsvPath,
        [string]$Dominio = "empresa.local",
        [string]$LogPath = "C:\Logs\CreacionUsuarios_$(Get-Date -Format 'yyyyMMdd_HHmm').log"
    )

    # Crear directorio de logs si no existe
    $LogDir = Split-Path $LogPath
    if (-not (Test-Path $LogDir)) { New-Item -ItemType Directory -Path $LogDir | Out-Null }

    $Usuarios = Import-Csv -Path $CsvPath -Encoding UTF8
    $Resultados = @()

    foreach ($U in $Usuarios) {
        $Username = ($U.Nombre.Substring(0,1) + $U.Apellido).ToLower()
        $Password = ConvertTo-SecureString "Temporal@2024" -AsPlainText -Force

        try {
            $Params = @{
                Name              = "$($U.Nombre) $($U.Apellido)"
                GivenName         = $U.Nombre
                Surname           = $U.Apellido
                SamAccountName    = $Username
                UserPrincipalName = "$Username@$Dominio"
                EmailAddress      = $U.Email
                OfficePhone       = $U.Telefono
                Department        = $U.Departamento
                Path              = $U.OU
                AccountPassword   = $Password
                ChangePasswordAtLogon = $true
                Enabled           = $true
            }

            # Añadir manager si se especifica
            if ($U.Manager) {
                $ManagerObj = Get-ADUser -Filter "SamAccountName -eq '$($U.Manager)'" -ErrorAction SilentlyContinue
                if ($ManagerObj) { $Params.Manager = $ManagerObj.DistinguishedName }
            }

            New-ADUser @Params
            $Estado = "OK"
            Write-Host "✓ $Username" -ForegroundColor Green
        }
        catch {
            $Estado = "ERROR: $_"
            Write-Host "✗ $Username - $_" -ForegroundColor Red
        }

        $Resultados += [PSCustomObject]@{
            Usuario    = $Username
            NombreCompleto = "$($U.Nombre) $($U.Apellido)"
            Estado     = $Estado
            Fecha      = (Get-Date -Format "dd/MM/yyyy HH:mm:ss")
        }
    }

    # Exportar resultados
    $Resultados | Export-Csv -Path $LogPath -NoTypeInformation -Encoding UTF8
    Write-Host "`nInforme guardado en: $LogPath" -ForegroundColor Cyan
    return $Resultados
}

# Uso
Import-ADUsersFromCSV -CsvPath "C:\Datos\nuevos_empleados.csv"

Deshabilitar Cuentas Inactivas

function Disable-InactiveADAccounts {
    param(
        [int]$DiasInactividad = 90,
        [string]$OUExcluir = "OU=ServiceAccounts,DC=empresa,DC=local",
        [string]$OUMover = "OU=Deshabilitadas,DC=empresa,DC=local",
        [switch]$WhatIf
    )

    $FechaLimite = (Get-Date).AddDays(-$DiasInactividad)

    # Buscar usuarios habilitados sin login en X días
    $InactiveUsers = Get-ADUser -Filter {
        Enabled -eq $true -and
        LastLogonDate -lt $FechaLimite -and
        LastLogonDate -ne $null
    } -Properties LastLogonDate, Description, DistinguishedName |
    Where-Object { $_.DistinguishedName -notlike "*$OUExcluir*" }

    Write-Host "Usuarios inactivos encontrados: $($InactiveUsers.Count)" -ForegroundColor Yellow

    foreach ($User in $InactiveUsers) {
        $Descripcion = "Deshabilitado automáticamente el $(Get-Date -Format 'dd/MM/yyyy'). Último login: $($User.LastLogonDate)"

        if (-not $WhatIf) {
            # Deshabilitar cuenta
            Disable-ADAccount -Identity $User.SamAccountName

            # Actualizar descripción
            Set-ADUser -Identity $User.SamAccountName -Description $Descripcion

            # Mover a OU de deshabilitadas
            Move-ADObject -Identity $User.DistinguishedName -TargetPath $OUMover

            Write-Host "Deshabilitado: $($User.SamAccountName) | Último login: $($User.LastLogonDate)" -ForegroundColor Yellow
        } else {
            Write-Host "[WHATIF] Deshabilitaría: $($User.SamAccountName) | Último login: $($User.LastLogonDate)"
        }
    }
}

# Simulación primero
Disable-InactiveADAccounts -DiasInactividad 90 -WhatIf
# Ejecución real
# Disable-InactiveADAccounts -DiasInactividad 90

6.3 Scripts de Gestión de Grupos

# Añadir usuarios a grupo desde CSV
function Add-ADGroupMembersFromCSV {
    param(
        [Parameter(Mandatory)][string]$CsvPath,   # CSV con columna 'Usuario' y 'Grupo'
        [string]$GrupoFijo = ""                    # Grupo único para todos si se especifica
    )

    $Datos = Import-Csv -Path $CsvPath -Encoding UTF8

    foreach ($Fila in $Datos) {
        $Grupo = if ($GrupoFijo) { $GrupoFijo } else { $Fila.Grupo }
        try {
            Add-ADGroupMember -Identity $Grupo -Members $Fila.Usuario
            Write-Host "✓ $($Fila.Usuario) → $Grupo" -ForegroundColor Green
        }
        catch {
            Write-Warning "✗ $($Fila.Usuario) → $Grupo : $_"
        }
    }
}

# Generar informe de miembros de grupos
function Export-ADGroupMembersReport {
    param(
        [string[]]$Grupos,
        [string]$OutputPath = "C:\Informes\Grupos_$(Get-Date -Format 'yyyyMMdd').csv"
    )

    $Resultados = @()
    foreach ($Grupo in $Grupos) {
        try {
            $Miembros = Get-ADGroupMember -Identity $Grupo -Recursive |
                        Where-Object { $_.objectClass -eq "user" } |
                        Get-ADUser -Properties DisplayName, Department, Enabled, LastLogonDate

            foreach ($M in $Miembros) {
                $Resultados += [PSCustomObject]@{
                    Grupo          = $Grupo
                    SamAccount     = $M.SamAccountName
                    NombreCompleto = $M.DisplayName
                    Departamento   = $M.Department
                    Habilitado     = $M.Enabled
                    UltimoLogin    = $M.LastLogonDate
                }
            }
        }
        catch {
            Write-Warning "No se pudo obtener miembros de '$Grupo': $_"
        }
    }

    $Resultados | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
    Write-Host "Informe exportado: $OutputPath ($($Resultados.Count) registros)" -ForegroundColor Cyan
}

6.4 Scripts de Gestión de GPOs

# Exportar configuración de todas las GPOs
function Export-AllGPOReports {
    param([string]$OutputDir = "C:\Informes\GPO_$(Get-Date -Format 'yyyyMMdd')")

    Import-Module GroupPolicy
    New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null

    $GPOs = Get-GPO -All
    foreach ($GPO in $GPOs) {
        $SafeName = $GPO.DisplayName -replace '[\\/:*?"<>|]', '_'
        Get-GPOReport -Guid $GPO.Id -ReportType HTML -Path "$OutputDir\$SafeName.html"
        Write-Host "Exportada: $($GPO.DisplayName)" -ForegroundColor Green
    }

    # También exportar listado general
    $GPOs | Select-Object DisplayName, Id, GpoStatus, CreationTime, ModificationTime |
        Export-Csv -Path "$OutputDir\_ListadoGPOs.csv" -NoTypeInformation -Encoding UTF8

    Write-Host "`nTotal GPOs exportadas: $($GPOs.Count)" -ForegroundColor Cyan
    Write-Host "Directorio: $OutputDir" -ForegroundColor Cyan
}

# Hacer backup de todas las GPOs
function Backup-AllGPOs {
    param([string]$BackupDir = "C:\Backup\GPO_$(Get-Date -Format 'yyyyMMdd_HHmm')")

    Import-Module GroupPolicy
    New-Item -ItemType Directory -Path $BackupDir -Force | Out-Null

    $GPOs = Get-GPO -All
    foreach ($GPO in $GPOs) {
        Backup-GPO -Guid $GPO.Id -Path $BackupDir -Comment "Backup automático $(Get-Date -Format 'dd/MM/yyyy')"
        Write-Host "Backup: $($GPO.DisplayName)" -ForegroundColor Green
    }

    Write-Host "`nBackup completado en: $BackupDir" -ForegroundColor Cyan
}

# Restaurar GPO desde backup
function Restore-GPOFromBackup {
    param(
        [Parameter(Mandatory)][string]$NombreGPO,
        [Parameter(Mandatory)][string]$BackupDir
    )

    Import-Module GroupPolicy
    Restore-GPO -Name $NombreGPO -Path $BackupDir
    Write-Host "GPO '$NombreGPO' restaurada desde $BackupDir" -ForegroundColor Green
}

6.5 Informes y Auditoría

# Informe completo de usuarios AD
function Export-ADUsersFullReport {
    param([string]$OutputPath = "C:\Informes\Usuarios_AD_$(Get-Date -Format 'yyyyMMdd').csv")

    $Propiedades = @(
        'SamAccountName', 'DisplayName', 'GivenName', 'Surname',
        'UserPrincipalName', 'EmailAddress', 'Department', 'Title',
        'Manager', 'Enabled', 'PasswordExpired', 'PasswordNeverExpires',
        'PasswordLastSet', 'LastLogonDate', 'AccountExpirationDate',
        'LockedOut', 'Created', 'Modified', 'DistinguishedName',
        'MemberOf', 'HomeDirectory', 'ProfilePath', 'Description'
    )

    Get-ADUser -Filter * -Properties $Propiedades |
    Select-Object @{N='Usuario';E={$_.SamAccountName}},
                  @{N='Nombre';E={$_.DisplayName}},
                  @{N='Email';E={$_.EmailAddress}},
                  @{N='Departamento';E={$_.Department}},
                  @{N='Cargo';E={$_.Title}},
                  @{N='Manager';E={ if($_.Manager){(Get-ADUser $_.Manager).SamAccountName} }},
                  @{N='Habilitado';E={$_.Enabled}},
                  @{N='PasswordCaduca';E={-not $_.PasswordNeverExpires}},
                  @{N='UltimoCambioPass';E={$_.PasswordLastSet}},
                  @{N='UltimoLogin';E={$_.LastLogonDate}},
                  @{N='ExpiracionCuenta';E={$_.AccountExpirationDate}},
                  @{N='Bloqueado';E={$_.LockedOut}},
                  @{N='Creado';E={$_.Created}},
                  @{N='OU';E={ ($_.DistinguishedName -split ',',2)[1] }},
                  @{N='Grupos';E={ ($_.MemberOf | ForEach-Object { (Get-ADGroup $_).Name }) -join '; ' }} |
    Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8

    Write-Host "Informe exportado: $OutputPath" -ForegroundColor Cyan
}

7. Scripting – Bash para Linux

7.1 Script de Gestión de Usuarios

#!/usr/bin/env bash
# =============================================================================
# Script: gestionar_usuarios.sh
# Descripción: Gestión completa de usuarios Linux
# Uso: ./gestionar_usuarios.sh [crear|modificar|eliminar|listar|bloquear|informe]
# Requiere: root o sudo
# =============================================================================

set -euo pipefail   # Salir en error, variables no definidas, pipelines
IFS=$'\n\t'

# ── Colores ────────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; CYAN='\033[0;36m'; NC='\033[0m'

# ── Configuración ──────────────────────────────────────────────────────────────
LOG_FILE="/var/log/gestion_usuarios.log"
BACKUP_DIR="/root/backups/usuarios"
GRUPOS_BASE="usuarios,cdrom,plugdev"  # Grupos secundarios por defecto

# ── Logging ────────────────────────────────────────────────────────────────────
log() {
    local nivel="$1"; shift
    local mensaje="$*"
    local timestamp
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo "[$timestamp] [$nivel] $mensaje" | tee -a "$LOG_FILE"
}

log_info()    { log "INFO " "$@"; echo -e "${GREEN}[✓] $*${NC}"; }
log_warn()    { log "WARN " "$@"; echo -e "${YELLOW}[!] $*${NC}"; }
log_error()   { log "ERROR" "$@"; echo -e "${RED}[✗] $*${NC}" >&2; }

# ── Verificar root ─────────────────────────────────────────────────────────────
verificar_root() {
    if [[ $EUID -ne 0 ]]; then
        log_error "Este script debe ejecutarse como root"
        exit 1
    fi
}

# ── Crear usuario ──────────────────────────────────────────────────────────────
crear_usuario() {
    local usuario="${1:-}"
    local nombre_completo="${2:-}"
    local grupo_principal="${3:-usuarios}"
    local shell="${4:-/bin/bash}"
    local expiracion="${5:-}"  # Formato YYYY-MM-DD, vacío = nunca

    # Validar nombre de usuario
    if [[ -z "$usuario" ]]; then
        read -rp "Nombre de usuario: " usuario
    fi

    if ! echo "$usuario" | grep -qE '^[a-z_][a-z0-9_-]{0,31}$'; then
        log_error "Nombre de usuario inválido: '$usuario' (solo minúsculas, números, _ y -)"
        return 1
    fi

    # Verificar si ya existe
    if id "$usuario" &>/dev/null; then
        log_warn "El usuario '$usuario' ya existe"
        return 1
    fi

    # Solicitar datos faltantes
    [[ -z "$nombre_completo" ]] && read -rp "Nombre completo: " nombre_completo

    # Verificar/crear grupo principal
    if ! getent group "$grupo_principal" &>/dev/null; then
        groupadd "$grupo_principal"
        log_info "Grupo '$grupo_principal' creado"
    fi

    # Crear usuario
    local cmd_args="-m -s $shell -g $grupo_principal -c '$nombre_completo'"
    [[ -n "$expiracion" ]] && cmd_args+=" -e $expiracion"

    eval useradd $cmd_args "$usuario"

    # Grupos secundarios
    for grupo in ${GRUPOS_BASE//,/ }; do
        if getent group "$grupo" &>/dev/null; then
            usermod -aG "$grupo" "$usuario"
        fi
    done

    # Establecer contraseña
    local intentos=0
    while [[ $intentos -lt 3 ]]; do
        if passwd "$usuario"; then
            break
        fi
        ((intentos++))
        [[ $intentos -eq 3 ]] && { log_error "No se pudo establecer contraseña"; return 1; }
    done

    # Forzar cambio de contraseña
    chage -d 0 "$usuario"

    # Establecer políticas de contraseña
    chage -m 1 -M 90 -W 14 -I 7 "$usuario"

    # Ajustar permisos del home
    chmod 700 "/home/$usuario"

    log_info "Usuario '$usuario' creado correctamente"
    log_info "  Home: /home/$usuario"
    log_info "  Shell: $shell"
    log_info "  Grupo principal: $grupo_principal"
    [[ -n "$expiracion" ]] && log_info "  Expira: $expiracion"
}

# ── Eliminar usuario ───────────────────────────────────────────────────────────
eliminar_usuario() {
    local usuario="${1:-}"
    [[ -z "$usuario" ]] && read -rp "Usuario a eliminar: " usuario

    if ! id "$usuario" &>/dev/null; then
        log_error "El usuario '$usuario' no existe"
        return 1
    fi

    # Mostrar información antes de eliminar
    echo -e "${YELLOW}Información del usuario '$usuario':${NC}"
    id "$usuario"
    echo "Home: $(getent passwd "$usuario" | cut -d: -f6)"
    echo "Último login: $(lastlog -u "$usuario" | tail -1)"

    read -rp "¿Eliminar usuario y su home? [s/N]: " confirmar
    if [[ "$confirmar" =~ ^[Ss]$ ]]; then
        # Backup del home antes de eliminar
        mkdir -p "$BACKUP_DIR"
        local home
        home=$(getent passwd "$usuario" | cut -d: -f6)
        if [[ -d "$home" ]]; then
            tar czf "$BACKUP_DIR/${usuario}_$(date +%Y%m%d_%H%M%S).tar.gz" -C "$(dirname $home)" "$(basename $home)" 2>/dev/null || true
            log_info "Backup del home guardado en $BACKUP_DIR"
        fi

        # Matar procesos del usuario
        pkill -u "$usuario" 2>/dev/null || true

        userdel -r "$usuario"
        log_info "Usuario '$usuario' eliminado"
    else
        log_warn "Operación cancelada"
    fi
}

# ── Bloquear/desbloquear ───────────────────────────────────────────────────────
toggle_usuario() {
    local usuario="${1:-}"
    [[ -z "$usuario" ]] && read -rp "Usuario: " usuario

    if ! id "$usuario" &>/dev/null; then
        log_error "El usuario '$usuario' no existe"
        return 1
    fi

    # Ver estado actual
    local estado
    estado=$(passwd -S "$usuario" | awk '{print $2}')

    if [[ "$estado" == "L" ]]; then
        passwd -u "$usuario"
        log_info "Usuario '$usuario' DESBLOQUEADO"
    else
        passwd -l "$usuario"
        log_info "Usuario '$usuario' BLOQUEADO"
    fi
}

# ── Listar usuarios ────────────────────────────────────────────────────────────
listar_usuarios() {
    echo -e "\n${CYAN}═══════════════════════════════════════════════════════════════${NC}"
    echo -e "${CYAN}  USUARIOS DEL SISTEMA (UID >= 1000)${NC}"
    echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}"
    printf "%-20s %-6s %-20s %-10s %-15s\n" "USUARIO" "UID" "HOME" "SHELL" "ESTADO"
    echo -e "${CYAN}───────────────────────────────────────────────────────────────${NC}"

    while IFS=: read -r user pass uid gid gecos home shell; do
        [[ $uid -lt 1000 || $uid -eq 65534 ]] && continue

        local estado
        estado=$(passwd -S "$user" 2>/dev/null | awk '{print $2}' || echo "?")
        local color
        case "$estado" in
            P) color="$GREEN" ;;
            L) color="$RED" ;;
            *)  color="$YELLOW" ;;
        esac

        printf "${color}%-20s %-6s %-20s %-10s %-15s${NC}\n" \
            "$user" "$uid" "${home:0:19}" "${shell##*/}" "$estado"
    done < /etc/passwd

    echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}"
    echo "  Estado: P=Activo, L=Bloqueado, NP=Sin contraseña"
}

# ── Informe de seguridad ───────────────────────────────────────────────────────
informe_seguridad() {
    local output_file="/tmp/informe_seguridad_$(date +%Y%m%d_%H%M%S).txt"

    {
        echo "═══════════════════════════════════════════════════════════"
        echo "  INFORME DE SEGURIDAD DE USUARIOS"
        echo "  Generado: $(date '+%d/%m/%Y %H:%M:%S')"
        echo "  Servidor: $(hostname -f)"
        echo "═══════════════════════════════════════════════════════════"

        echo -e "\n── CUENTAS CON UID=0 (privilegio root) ──────────────────────"
        awk -F: '$3==0 {print "  [!] " $1}' /etc/passwd

        echo -e "\n── CUENTAS SIN CONTRASEÑA ────────────────────────────────────"
        awk -F: '($2==""|$2=="!"|$2=="*") && $3>=1000 && $3!=65534 {print "  [!] " $1}' /etc/shadow

        echo -e "\n── CUENTAS BLOQUEADAS ────────────────────────────────────────"
        while IFS=: read -r user pass uid _; do
            [[ $uid -lt 1000 || $uid -eq 65534 ]] && continue
            [[ "$pass" =~ ^! ]] && echo "  [-] $user (bloqueada)"
        done < /etc/shadow

        echo -e "\n── CUENTAS CON CONTRASEÑA CADUCADA ──────────────────────────"
        while IFS=: read -r user _ uid _; do
            [[ $uid -lt 1000 || $uid -eq 65534 ]] && continue
            if chage -l "$user" 2>/dev/null | grep -q "password expired"; then
                echo "  [!] $user"
            fi
        done < /etc/passwd

        echo -e "\n── SHELLS INUSUALES ──────────────────────────────────────────"
        awk -F: '$3>=1000 && $3!=65534 && $7!="/bin/bash" && $7!="/bin/sh" && $7!="/usr/bin/zsh" {print "  [?] " $1 " → " $7}' /etc/passwd

        echo -e "\n── MIEMBROS DEL GRUPO SUDO/WHEEL ────────────────────────────"
        getent group sudo wheel 2>/dev/null | awk -F: '{print "  " $1 ": " $4}'

        echo -e "\n── ÚLTIMOS LOGINS ────────────────────────────────────────────"
        last -n 20 | head -25

        echo -e "\n── USUARIOS CON SESIÓN ACTIVA AHORA ─────────────────────────"
        who

    } | tee "$output_file"

    echo -e "\n${GREEN}Informe guardado en: $output_file${NC}"
}

# ── Menú principal ─────────────────────────────────────────────────────────────
main() {
    verificar_root
    mkdir -p "$(dirname $LOG_FILE)" 2>/dev/null || true

    local accion="${1:-menu}"

    case "$accion" in
        crear)    crear_usuario "${@:2}" ;;
        eliminar) eliminar_usuario "${@:2}" ;;
        listar)   listar_usuarios ;;
        bloquear) toggle_usuario "${@:2}" ;;
        informe)  informe_seguridad ;;
        menu|*)
            echo -e "\n${BLUE}Gestión de Usuarios Linux${NC}"
            echo "1) Crear usuario"
            echo "2) Eliminar usuario"
            echo "3) Listar usuarios"
            echo "4) Bloquear/desbloquear usuario"
            echo "5) Informe de seguridad"
            echo "0) Salir"
            read -rp "Opción: " opcion
            case "$opcion" in
                1) crear_usuario ;;
                2) eliminar_usuario ;;
                3) listar_usuarios ;;
                4) toggle_usuario ;;
                5) informe_seguridad ;;
                0) exit 0 ;;
                *) log_error "Opción inválida" ;;
            esac
            ;;
    esac
}

main "$@"

7.2 Script de Gestión de Permisos

#!/usr/bin/env bash
# =============================================================================
# Script: gestionar_permisos.sh
# Descripción: Auditoría y gestión de permisos en el sistema de ficheros
# =============================================================================

set -euo pipefail

# ── Auditar SUID/SGID/Sticky ───────────────────────────────────────────────────
auditar_permisos_especiales() {
    local directorio="${1:-/}"
    local output_file="/tmp/auditoria_permisos_$(date +%Y%m%d).txt"

    {
        echo "AUDITORÍA DE PERMISOS ESPECIALES"
        echo "Fecha: $(date '+%d/%m/%Y %H:%M:%S')"
        echo "Directorio: $directorio"
        echo "═══════════════════════════════════════════"

        echo -e "\n── Archivos con SUID ────────────────────"
        find "$directorio" -xdev -perm -4000 -type f 2>/dev/null \
            -exec ls -la {} \; | sort

        echo -e "\n── Archivos con SGID ────────────────────"
        find "$directorio" -xdev -perm -2000 2>/dev/null \
            -exec ls -la {} \; | sort

        echo -e "\n── Directorios con Sticky Bit ───────────"
        find "$directorio" -xdev -perm -1000 -type d 2>/dev/null \
            -exec ls -lad {} \; | sort

        echo -e "\n── Archivos sin propietario ─────────────"
        find "$directorio" -xdev -nouser -o -nogroup 2>/dev/null \
            -exec ls -la {} \; | sort

        echo -e "\n── Archivos con permisos 777 ────────────"
        find "$directorio" -xdev -perm 777 2>/dev/null \
            -exec ls -la {} \; | sort

        echo -e "\n── Archivos world-writable (excl. sticky/sys) ──"
        find "$directorio" -xdev -perm -o+w -not -perm -1000 \
            -not -path "*/proc/*" -not -path "*/sys/*" 2>/dev/null \
            -exec ls -la {} \; | sort

    } | tee "$output_file"

    echo -e "\nInforme guardado en: $output_file"
}

# ── Corregir permisos de directorio ───────────────────────────────────────────
corregir_permisos_web() {
    local directorio="${1:-/var/www/html}"
    local propietario="${2:-www-data}"
    local grupo="${3:-www-data}"

    echo "Corrigiendo permisos en: $directorio"
    echo "Propietario: $propietario:$grupo"

    # Propietario y grupo
    chown -R "$propietario:$grupo" "$directorio"

    # Directorios: 755
    find "$directorio" -type d -exec chmod 755 {} \;

    # Ficheros regulares: 644
    find "$directorio" -type f -exec chmod 644 {} \;

    # Scripts PHP/ejecutables: 755 (si los hubiera)
    # find "$directorio" -name "*.php" -exec chmod 644 {} \;

    echo "✓ Permisos corregidos"
}

# ── Configurar directorio compartido con SGID ─────────────────────────────────
setup_directorio_compartido() {
    local directorio="$1"
    local grupo="$2"
    local permiso="${3:-2775}"   # SGID + rwxrwxr-x

    # Crear directorio si no existe
    mkdir -p "$directorio"

    # Crear grupo si no existe
    if ! getent group "$grupo" &>/dev/null; then
        groupadd "$grupo"
        echo "✓ Grupo '$grupo' creado"
    fi

    # Asignar propietario
    chown root:"$grupo" "$directorio"

    # Aplicar permisos con SGID
    chmod "$permiso" "$directorio"

    # ACL por defecto para heredar grupo
    if command -v setfacl &>/dev/null; then
        setfacl -d -m g:"$grupo":rwx "$directorio"
        setfacl -d -m o::0 "$directorio"
        echo "✓ ACL heredadas configuradas"
    fi

    echo "✓ Directorio '$directorio' configurado para grupo '$grupo'"
    ls -lad "$directorio"
}

# ── Backup de permisos y restauración ─────────────────────────────────────────
backup_permisos() {
    local directorio="$1"
    local backup_file="${2:-/root/backup_permisos_$(date +%Y%m%d).acl}"

    # Guardar ACLs y permisos
    getfacl -R "$directorio" > "$backup_file"
    echo "✓ Permisos guardados en: $backup_file"
}

restaurar_permisos() {
    local backup_file="$1"

    if [[ ! -f "$backup_file" ]]; then
        echo "Error: No existe el archivo $backup_file"
        return 1
    fi

    setfacl --restore="$backup_file"
    echo "✓ Permisos restaurados desde: $backup_file"
}

# ── Buscar archivos por propietario ───────────────────────────────────────────
buscar_archivos_usuario() {
    local usuario="$1"
    local directorio="${2:-/home}"

    echo "Buscando archivos de '$usuario' en '$directorio'..."
    find "$directorio" -user "$usuario" 2>/dev/null -exec ls -la {} \;
}

7.3 Script de Creación Masiva desde CSV

#!/usr/bin/env bash
# =============================================================================
# Script: crear_usuarios_csv.sh
# Uso: ./crear_usuarios_csv.sh usuarios.csv
# CSV: usuario,nombre,apellido,grupo,shell,expiracion
# =============================================================================

set -euo pipefail

CSV_FILE="${1:-}"
LOG_FILE="/var/log/creacion_masiva_$(date +%Y%m%d_%H%M%S).log"
CONTRASENA_TEMPORAL="Temporal@$(date +%Y)"

[[ -z "$CSV_FILE" ]] && { echo "Uso: $0 <fichero.csv>"; exit 1; }
[[ ! -f "$CSV_FILE" ]] && { echo "Error: Fichero no encontrado: $CSV_FILE"; exit 1; }
[[ $EUID -ne 0 ]] && { echo "Requiere root"; exit 1; }

CREADOS=0; ERRORES=0; OMITIDOS=0

while IFS=',' read -r usuario nombre apellido grupo shell expiracion; do
    # Saltar cabecera o líneas vacías
    [[ "$usuario" == "usuario" || -z "$usuario" ]] && continue
    # Limpiar espacios y retornos de carro (Windows)
    usuario=$(echo "$usuario" | tr -d '[:space:]' | tr -d '\r')
    grupo=$(echo "$grupo" | tr -d '[:space:]' | tr -d '\r')
    shell=$(echo "$shell" | tr -d '[:space:]' | tr -d '\r')
    expiracion=$(echo "$expiracion" | tr -d '[:space:]' | tr -d '\r')

    # Verificar si ya existe
    if id "$usuario" &>/dev/null; then
        echo "[OMITIDO] $usuario (ya existe)" | tee -a "$LOG_FILE"
        ((OMITIDOS++))
        continue
    fi

    # Crear grupo si no existe
    if ! getent group "$grupo" &>/dev/null; then
        groupadd "$grupo"
    fi

    # Construir comando
    CMD="useradd -m -g $grupo -s ${shell:-/bin/bash} -c '$nombre $apellido'"
    [[ -n "$expiracion" ]] && CMD+=" -e $expiracion"
    CMD+=" $usuario"

    if eval "$CMD" 2>>"$LOG_FILE"; then
        echo "$usuario:$CONTRASENA_TEMPORAL" | chpasswd
        chage -d 0 -m 1 -M 90 -W 14 "$usuario"
        echo "[OK] $usuario" | tee -a "$LOG_FILE"
        ((CREADOS++))
    else
        echo "[ERROR] $usuario" | tee -a "$LOG_FILE"
        ((ERRORES++))
    fi

done < "$CSV_FILE"

echo ""
echo "══════════════════════════════"
echo "  Resumen de creación masiva"
echo "══════════════════════════════"
echo "  Creados:  $CREADOS"
echo "  Errores:  $ERRORES"
echo "  Omitidos: $OMITIDOS"
echo "  Log:      $LOG_FILE"
echo "  Contraseña temporal: $CONTRASENA_TEMPORAL"

8. Casos de Uso Combinados

8.1 Integrar Linux con Active Directory (SSSD + Kerberos)

# Instalar paquetes (Debian/Ubuntu)
apt install -y sssd sssd-ad sssd-tools realmd adcli krb5-user packagekit

# Unir el equipo al dominio
realm discover empresa.local
realm join -U administrador empresa.local

# Verificar unión
realm list

# Obtener ticket Kerberos
kinit administrador@EMPRESA.LOCAL
klist

# Configurar acceso sudo a usuarios del dominio
echo "%domain\ admins@empresa.local ALL=(ALL) ALL" >> /etc/sudoers.d/dominio

# Archivo /etc/sssd/sssd.conf (configuración básica)
cat > /etc/sssd/sssd.conf << 'EOF'
[sssd]
domains = empresa.local
config_file_version = 2
services = nss, pam

[domain/empresa.local]
default_shell = /bin/bash
krb5_store_password_if_offline = True
cache_credentials = True
krb5_realm = EMPRESA.LOCAL
realmd_tags = manages-system joined-with-adcli
id_provider = ad
fallback_homedir = /home/%u@%d
ad_domain = empresa.local
use_fully_qualified_names = False
ldap_id_mapping = True
access_provider = ad
EOF

chmod 600 /etc/sssd/sssd.conf
systemctl restart sssd

8.2 Script de Auditoría Combinada

#!/usr/bin/env bash
# Genera informe de seguridad completo del sistema
# Incluye: usuarios, permisos, GPOs aplicadas (si unido a AD), etc.

generar_informe_completo() {
    local OUTPUT="/tmp/auditoria_completa_$(hostname)_$(date +%Y%m%d).txt"

    {
        echo "╔══════════════════════════════════════════════════════════════╗"
        echo "║         AUDITORÍA DE SEGURIDAD COMPLETA DEL SISTEMA         ║"
        echo "╚══════════════════════════════════════════════════════════════╝"
        echo "  Servidor  : $(hostname -f)"
        echo "  Fecha     : $(date '+%d/%m/%Y %H:%M:%S')"
        echo "  SO        : $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2 | tr -d '"')"
        echo "  Kernel    : $(uname -r)"

        echo -e "\n══ USUARIOS DEL SISTEMA ══════════════════════════════════════"
        awk -F: '$3>=1000 && $3!=65534 {printf "  %-20s UID=%-6s GID=%-6s Home=%-25s Shell=%s\n", $1,$3,$4,$6,$7}' /etc/passwd

        echo -e "\n══ GRUPOS Y MEMBRESÍAS ═══════════════════════════════════════"
        while IFS=: read -r grupo _ gid miembros; do
            [[ -n "$miembros" ]] && echo "  $grupo (GID=$gid): $miembros"
        done < /etc/group

        echo -e "\n══ USUARIOS CON ACCESO SUDO ══════════════════════════════════"
        grep -E '^\s*[^#]' /etc/sudoers /etc/sudoers.d/* 2>/dev/null | grep -v "^#" || true
        getent group sudo wheel 2>/dev/null | awk -F: '{print "  Grupo " $1 ": " $4}'

        echo -e "\n══ SERVICIOS EN ESCUCHA ══════════════════════════════════════"
        ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null

        echo -e "\n══ CONEXIONES ACTIVAS ════════════════════════════════════════"
        who -a

        echo -e "\n══ PERMISOS ESPECIALES (SUID/SGID) ══════════════════════════"
        find / -xdev \( -perm -4000 -o -perm -2000 \) -type f 2>/dev/null | sort

        echo -e "\n══ ARCHIVOS WORLD-WRITABLE ═══════════════════════════════════"
        find / -xdev -perm -o+w -not -path "*/proc/*" -not -path "*/sys/*" -not -perm -1000 2>/dev/null | sort

        echo -e "\n══ ÚLTIMOS 20 ACCESOS ════════════════════════════════════════"
        last -n 20

        echo -e "\n══ INTENTOS DE ACCESO FALLIDOS ═══════════════════════════════"
        lastb -n 20 2>/dev/null || grep "Failed password" /var/log/auth.log 2>/dev/null | tail -20

    } | tee "$OUTPUT"

    echo -e "\nInforme completo guardado en: $OUTPUT"
}

generar_informe_completo

Referencia Rápida

Comandos AD más usados (PowerShell)

# Usuarios
Get-ADUser -Filter * -Properties *
New-ADUser -Name "Nombre" -SamAccountName "usuario" ...
Set-ADUser -Identity "usuario" -Department "Ventas"
Disable-ADAccount -Identity "usuario"
Enable-ADAccount -Identity "usuario"
Unlock-ADAccount -Identity "usuario"
Remove-ADUser -Identity "usuario"
Set-ADAccountPassword -Identity "usuario" -Reset -NewPassword (Read-Host -AsSecureString)

# Grupos
Get-ADGroup -Filter * | Select Name, GroupScope, GroupCategory
Add-ADGroupMember -Identity "Grupo" -Members "usuario1","usuario2"
Remove-ADGroupMember -Identity "Grupo" -Members "usuario"
Get-ADGroupMember -Identity "Grupo" -Recursive

# GPOs
Get-GPO -All
New-GPO -Name "NuevaGPO" | New-GPLink -Target "OU=Ventas,DC=empresa,DC=local"
Get-GPOReport -Name "NombreGPO" -ReportType HTML -Path "C:\gpo.html"
Backup-GPO -Name "NombreGPO" -Path "C:\Backup"

# Dominio
Get-ADDomain
Get-ADForest
Get-ADDomainController -Filter *
Test-ComputerSecureChannel -Repair

Comandos Linux más usados

# Usuarios
useradd -m -s /bin/bash -G sudo usuario
passwd usuario
usermod -aG grupo usuario
userdel -r usuario
chage -l usuario

# Permisos
chmod 755 fichero
chown usuario:grupo fichero
setfacl -m u:usuario:rwx fichero
getfacl fichero

# Información
id usuario
getent passwd usuario
getent group grupo
last; lastlog; who; w

# Búsqueda
find / -user usuario 2>/dev/null
find / -perm -4000 -type f 2>/dev/null   # SUID
find / -perm -o+w -not -path "*/proc/*"  # World-writable

Documento generado automáticamente. Revisado para: Windows Server 2019/2022, RHEL 8/9, Ubuntu 22.04/24.04