La gestión manual de Active Directory no escala. Cuando el alta de un usuario tarda 30 minutos o las bajas son inconsistentes, es hora de automatizar. Estos scripts de PowerShell gestionan de forma fiable todo el ciclo de vida del usuario.
Requisitos previos
- Windows Server con el rol AD DS (o RSAT en Windows 10/11)
- PowerShell 5.1+ con el módulo ActiveDirectory
- Permisos de administrador de dominio o de OU delegados
# Verificar que el módulo de AD está disponible
Import-Module ActiveDirectory
Get-Module ActiveDirectoryAprovisionamiento de usuarios: script de alta
# New-ADUserFromTemplate.ps1
param(
[Parameter(Mandatory)]
[string]$FirstName,
[Parameter(Mandatory)]
[string]$LastName,
[Parameter(Mandatory)]
[string]$Department,
[Parameter(Mandatory)]
[string]$Title,
[string]$Manager,
[string]$OU = "OU=Users,OU=Company,DC=contoso,DC=com"
)
$SamAccountName = ($FirstName.Substring(0,1) + $LastName).ToLower() -replace '[^a-z0-9]', ''
$UPN = "$SamAccountName@contoso.com"
$DisplayName = "$FirstName $LastName"
# Comprobar si ya existe un duplicado
if (Get-ADUser -Filter "SamAccountName -eq '$SamAccountName'" -ErrorAction SilentlyContinue) {
Write-Error "El usuario $SamAccountName ya existe"
exit 1
}
# Generar una contraseña inicial segura
$InitialPassword = [System.Web.Security.Membership]::GeneratePassword(12, 2)
$SecurePassword = ConvertTo-SecureString $InitialPassword -AsPlainText -Force
# Crear el usuario
New-ADUser `
-SamAccountName $SamAccountName `
-UserPrincipalName $UPN `
-Name $DisplayName `
-GivenName $FirstName `
-Surname $LastName `
-DisplayName $DisplayName `
-Department $Department `
-Title $Title `
-Manager $Manager `
-Path $OU `
-AccountPassword $SecurePassword `
-ChangePasswordAtLogon $true `
-Enabled $true
# Añadir al grupo del departamento
$GroupName = "GRP_$Department"
if (Get-ADGroup -Filter "Name -eq '$GroupName'" -ErrorAction SilentlyContinue) {
Add-ADGroupMember -Identity $GroupName -Members $SamAccountName
}
Write-Host "Usuario creado: $UPN | Contraseña inicial: $InitialPassword" -ForegroundColor GreenAprovisionamiento masivo desde CSV
# bulk-provision.ps1
$Users = Import-Csv -Path ".\new-hires.csv"
# Columnas del CSV: FirstName, LastName, Department, Title, Manager
$Results = foreach ($User in $Users) {
try {
.\New-ADUserFromTemplate.ps1 `
-FirstName $User.FirstName `
-LastName $User.LastName `
-Department $User.Department `
-Title $User.Title `
-Manager $User.Manager
[PSCustomObject]@{
Name = "$($User.FirstName) $($User.LastName)"
Status = 'Success'
Error = ''
}
} catch {
[PSCustomObject]@{
Name = "$($User.FirstName) $($User.LastName)"
Status = 'Failed'
Error = $_.Exception.Message
}
}
}
$Results | Export-Csv -Path ".\provisioning-results.csv" -NoTypeInformation
$Results | Format-Table -AutoSizeBaja de usuarios: workflow de deshabilitación de cuenta
# Disable-ADUserOffboard.ps1
param(
[Parameter(Mandatory)]
[string]$SamAccountName,
[string]$DisabledOU = "OU=Disabled,OU=Company,DC=contoso,DC=com"
)
$User = Get-ADUser -Identity $SamAccountName -Properties MemberOf, Description
# 1. Deshabilitar la cuenta
Disable-ADAccount -Identity $SamAccountName
# 2. Restablecer la contraseña a un valor aleatorio (evita reactivarla sin pasar por IT)
$RandomPass = [System.Web.Security.Membership]::GeneratePassword(24, 4)
Set-ADAccountPassword -Identity $SamAccountName `
-NewPassword (ConvertTo-SecureString $RandomPass -AsPlainText -Force) `
-Reset
# 3. Eliminar de todos los grupos (guardando antes un registro)
$Groups = $User.MemberOf | ForEach-Object { (Get-ADGroup $_).Name }
$Groups | ForEach-Object {
Remove-ADGroupMember -Identity $_ -Members $SamAccountName -Confirm:$false
}
# 4. Actualizar la descripción con la fecha de baja
Set-ADUser -Identity $SamAccountName `
-Description "Deshabilitado el $(Get-Date -Format 'yyyy-MM-dd') | Era miembro de: $($Groups -join ', ')"
# 5. Mover a la OU de deshabilitados
Move-ADObject -Identity $User.DistinguishedName -TargetPath $DisabledOU
Write-Host "Baja completada para $SamAccountName. Eliminado de $($Groups.Count) grupos." -ForegroundColor YellowAuditoría programada: informe de cuentas inactivas
# Get-StaleAccountsReport.ps1
$ThresholdDays = 90
$Threshold = (Get-Date).AddDays(-$ThresholdDays)
$StaleUsers = Get-ADUser -Filter {
Enabled -eq $true -and LastLogonDate -lt $Threshold
} -Properties LastLogonDate, Department, Manager | Where-Object {
$_.LastLogonDate -ne $null
} | Select-Object `
SamAccountName, Name, Department,
@{N='Manager'; E={ (Get-ADUser $_.Manager -ErrorAction SilentlyContinue).Name }},
LastLogonDate,
@{N='DaysSinceLogin'; E={ ((Get-Date) - $_.LastLogonDate).Days }}
$ReportPath = ".\stale-accounts-$(Get-Date -Format 'yyyyMMdd').csv"
$StaleUsers | Sort-Object DaysSinceLogin -Descending | Export-Csv $ReportPath -NoTypeInformation
Write-Host "Se encontraron $($StaleUsers.Count) cuentas inactivas. Informe: $ReportPath"
# Enviar por correo (requiere SMTP configurado)
Send-MailMessage `
-To "it-team@contoso.com" `
-Subject "Informe de cuentas AD inactivas - $(Get-Date -Format 'yyyy-MM-dd')" `
-Body "Adjunto: cuentas sin inicio de sesión en más de $ThresholdDays días." `
-Attachments $ReportPath `
-SmtpServer "smtp.contoso.com"Notificación de expiración de contraseña
# Send-PasswordExpiryWarning.ps1
$MaxAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days
$WarningDays = 14
Get-ADUser -Filter { Enabled -eq $true -and PasswordNeverExpires -eq $false } `
-Properties PasswordLastSet, EmailAddress | ForEach-Object {
$ExpiresIn = $MaxAge - ((Get-Date) - $_.PasswordLastSet).Days
if ($ExpiresIn -le $WarningDays -and $ExpiresIn -gt 0 -and $_.EmailAddress) {
Send-MailMessage `
-To $_.EmailAddress `
-Subject "Tu contraseña expira en $ExpiresIn día(s)" `
-Body "Cambia tu contraseña en https://account.contoso.com antes de que expire." `
-SmtpServer "smtp.contoso.com"
Write-Host "Notificado: $($_.SamAccountName) (quedan $ExpiresIn días)"
}
}Errores comunes
- Ejecutar sin probar: prueba siempre los scripts primero en una OU que no sea de producción — usa
-WhatIfen los cmdlets destructivos - Sin logging de errores: envuelve las operaciones masivas en try/catch y exporta los resultados a CSV para auditoría
- Credenciales hardcodeadas: usa credenciales almacenadas o el Windows Credential Manager, nunca contraseñas en texto plano dentro de los scripts
- Sin esperar la replicación: tras crear un usuario, añade
Start-Sleep -Seconds 5antes de añadirlo a grupos para dar tiempo a la replicación de AD