Para ello es puede ser muy util el siguiente Powershell Script que realiza las siguientes funciones:
- Muestra sólo los usuarios bloqueados (pudiendo omitir ciertos powerusers)
- Permite desbloquear usuario
- Permite cambiar contraseña usuario
- Permite desbloquear y cambiar contraseña
- Permite desbloquear, cambiar contraseña y marcar cambiar contraseña en el siguiente logon
Todo ello con un array de nuestros controladores de dominio, útil si hay dispersión geografica y algún que otro control de errores básico.
<#
Author: Miguel Varona - Alberto Molero
Date: 05/10/2016
Version: 2.0
Descripción
Herramienta para identificar bloqueos en AD, desbloquear usuario y porporcionarle nueva contraseña.
UPDATED 06/10/2016
Añadimos opción de cambiar password, establecer cambio en siguiente logon y desbloquear.
UPDATED 05/10/2016
Añadimos los usuarios a excluir en la lista de bloqueos.
#>
#Importa el modulo de Active Directory
Import-Module ActiveDirectory
Write-Host ""
Write-Host "PowerShell AD Password Tool"
Write-Host ""
Write-Host "Herramienta de comprobación de expiración y bloqueo de cuentas de AD"
Write-Host "Status. Te permitirá desbloquear y/o establecer una nueva contraseña"
Write-Host ""
Write-Host ""
###########################
## FUNCIONES ##
###########################
#################################
### unlockAndCheck function ###
#################################
#Esta funcion desbloquea el usuario definido el los DCs de la lista $servers array, despues comprueba que esta desbloqueado.
function unlockAndCheck {
foreach ($server in $servers) {
Try {
Write-Host "Desbloqueando usuario en $server"
Unlock-ADAccount -Identity $user -server $server
}catch{
}
}
#Consigue el status de bloqueo y lo marca en la variable $Lock
$Lock = (Get-ADUser -Filter {samAccountName -eq $user } -Properties * |
Select-Object -expand lockedout)
Write-Host ""
#Dependiendo del estatus, muestra si el usuario esta bloqueado o no.
switch ($Lock) {
"False" { Write-Host "$user El usuario está BLOQUEADO." }
"True" { Write-Host "$user El usuario no está bloqueado." }
}
}
############################
### resetPass function ###
############################
#Esta función cambia la contraseña del usuario definicdo en los DCs del $server array.
function resetPass {
$newpass = (Read-Host -AsSecureString "Introduzaca nueva contraseña")
foreach ($server in $servers) {
Write-Host "Cambiando Contraseña en $server"
Set-ADAccountPassword -Server $server -Identity $user -NewPassword $newpass
}
Write-Host ""
Write-Host "Contraseña de $user cambiada."
Write-Host ""
}
##################################################
### resetPassand changenextlogon function ###
##################################################
##Esta función cambia la contraseña del usuario definicdo en los DCs del $server array y añade la opción de cambiar contrasseña en el siguiente logon.
function resetPasschange {
$newpass = (Read-Host -AsSecureString "Introduzaca nueva contraseña")
foreach ($server in $servers) {
Write-Host "Cambiando Contraseña en $server"
Set-ADAccountPassword -Server $server -Identity $user -NewPassword $newpass ; Set-ADUser -Identity $user -ChangePasswordAtLogon $true
}
Write-Host ""
Write-Host "Contraseña de $user cambiada."
Write-Host ""
}
###########################
## End FUNCTIONS ##
###########################
#############################################
## Definir los Controladores de Dominio ##
#############################################
<#
Si disponemos de mas de un DC y repartidos Geográficamente esta lista nos ahorra
el tiempo de replica para el cambio y desbloqueo de contraseña.
----> Importante: Mantener la lista si los mismos cambian.
#>
#Creating Empty $servers Array
$servers = New-Object System.Collections.ArrayList
#Creating Empty $unavailable Array
$unavailable = New-Object System.Collections.ArrayList
#Assign Domain Controllers to $servers Array
$servers.add("servidor.dominio.local") | out-null
# NOTA: Puedes añadir más, copiando la linea justo debajo.
##################################################
## Comprobacion de usuarios bloqueados en AD ##
##################################################
#Cuenta cuantas cuentas bloqueadas hay en DC local y lo establece en la variable $count
$count = Search-ADAccount –LockedOut | where { $_.Name -ne "Administrator" -and $_.Name -ne "Guest" -and $_.Name -ne "SAU" -and $_.Name -ne "Otrousuario" -and $_.Name -ne "Otrousuario" -and $_.Name -ne "obs_int_svc" -and $_.Name -ne "Otrousuario" -and $_.Name -ne "Invitado" } |
Measure-Object | Select-Object -expand Count
#Si hay cuentas bloqueadas (exceptuando administrator, invitado y otras,las muestra.
If ( $count -gt 0 ) {
Write-Host "Cuentas Bloqueadas actualmente en el Dominio:"
Search-ADAccount –LockedOut | where { $_.Name -ne "Administrator" -and $_.Name -ne "Guest" -and $_.Name -ne "SAU" -and $_.Name -ne "Seguridad" -and $_.Name -ne "Formacion" -and $_.Name -ne "obs_int_svc" -and $_.Name -ne "test.operador" -and $_.Name -ne "Invitado" } |
Select-Object Name, @{Expression={$_.SamAccountName};Label="Username"},@{Expression={$_.physicalDeliveryOfficeName};Label="Office Location"},@{Expression={$_.LastLogonDate};Label="Fecha de último acceso."} | Format-Table -AutoSize
}else{
# Write-Host "No tiene cuentas bloqueadas en el dominio."
}
Write-Host ""
###########################################
## Pregunta por el nombre del usuario ##
###########################################
#Pregunta por el nombre de usuario
$user = Read-Host "Introduzca el nombre de usuario que quieres comprobar o pulsa [CTR+C] para salir."
[int]$Checker1 = 0
# Control de errores
Do {
# Try to retrieve info for given user, catch error if unalbe to retrieve
Try {
# Attempt to retrieve info about user and suppress output
Get-ADUser -Identity $user | Out-Null
# If successful, set Checker to 1 to exi do loop.
$Checker1 = 1
}catch{
# If Attempt to retrieve info fails, run code in this catch block
#Username entered was not found. Have user try again.
cls
Write-Host ""
Write-Host ""
Write-Host "Cuenta de usuario no encontrada! - Comprueba el nombre y vuelve a intentar." -BackgroundColor Red -ForegroundColor White
Write-Host ""
$user = Read-Host "Introduzca el nombre de usuario que quieres comprobar o pulsa [CTR+C] para salir."
}
# If Checker1 is equal to zero, then redo Do loop.
}While ($Checker1 -eq 0)
#############################################################
## HAce un get para mostrar la informacion del usuario ##
#############################################################
#Once a valid user is entered, proceed with remaining code
cls
Write-Host ""
Write-Host ""
# Hace un get para el nombre de usuario
$Name = (Get-ADUser -Filter {samAccountName -eq $user } -Properties * | Select-Object -expand DisplayName)
# Gets Phone number of entered user (linea comentada porque no utilizamos el campo, puede ser útil en un futuro.)
#$phone = (Get-ADUser -Filter {samAccountName -eq $user } -Properties * | Select-Object -expand telephoneNumber)
# Displays the Display Name and Phone number of user - I use this to verify I have the correct user and
# to have the phone number available, if I need to contact the user.
#Write-Host "$Name's phone number is: $phone"
Write-Host ""
Write-Host ""
####################################################################
## Hace un get para la antiguedad de la contraseña y la muestra ##
####################################################################
# Get-date para Fecha de hoy
[datetime]$today = (get-date)
#Get pwdlastset fecha del AD para la variable $passdate2
$passdate2 = [datetime]::fromfiletime((Get-ADUser -Filter {samAccountName -eq $user } -Properties * |
Select-Object -expand pwdlastset))
#Calcula la contraseña en dias
$PwdAge = ($today - $passdate2).Days
#Comprueba si es mas antigua de 30 dias
If ($PwdAge -gt 31){
# Si es mas antigua de 30 días informa que está expirada y la muestra
Write-Host "Contraseña de $user ha EXPIRADO!"
Write-Host "Contrasela de $user tiene una antiguedad de $PwdAge dias "
}else{
# Si es menor de 30 dias muestra la antiguedad
Write-Host "COntraseña de $user tiene una antiguedad de $PwdAge dias "
}
Write-Host ""
Write-Host ""
########################################################
## Estado del bloqueo en cada servidor disponible ##
########################################################
#Comprueba la disponibilidad de los servidores y el estado del bloqueo de la cuenta de usuario. (ojo ping trafico permitido)
foreach ($object in $servers) {
# ERROR CHECKING
Try{
# Check to see if server is available via a ping
ping $object -n 1 | Out-Null
# If server is available, complete code:
switch (Get-ADUser -server $object -Filter {samAccountName -eq $user } -Properties * |
Select-Object -expand lockedout) {
"False" {"$object `t `t Not Locked"}
"True" {"$object `t `t LOCKED"}
}
}catch{
# If server is not available, alert admin that it will be skipped.
Write-host "$object `t `t NOT Found - Skipping" -ForegroundColor white -BackgroundColor red
# Add unavailible server to $unavailible array
$unavailable.add($object) | out-null
}
}
##############################################################
## $servers Control de disponibilidad de servidores ##
##############################################################
<#
Para cada servidor en el array que no este disponible lo elimina del array
con el fin de que el script no de error por time out. Otro pequeño control
de errores.
#>
foreach ($server in $unavailable){
$servers.Remove($server)
}
##############################################
## Preguntar que opción quiere escoger ##
##############################################
Write-Host ""
Write-Host ""
$option = Read-Host "¿Quieres (1) Desbloquear el usuario, (2) Resetear la contraseña del usuario, (3) Desbloquear y resetear contraseña o (4) Desbloquear, resetear y cambiar en el logon siguiente (5) Salir?"
##########################################
## Llevar a cabo la opción escogida ##
##########################################
cls
[int]$checker2 = 0
While ($checker2 -eq 0) {
switch ($option){
"1" {
#Call unlockAndCheck Function
unlockAndCheck
Write-Host ""
Write-Host "Pulsa cualqueir tecla para salir."
$checker2 +=6
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
"2" {
#call resetPass function
resetPass
Write-Host ""
Write-Host "Pulsa cualqueir tecla para salir."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
$checker2 += 6
}
"3" {
#call resetPass function
resetPass
#Call unlockAndCheck Function
unlockAndCheck
Write-Host ""
Write-Host "Pulsa cualqueir tecla para salir."
$checker2 += 6
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
"4" {
#call resetPasschange function
resetPasschange
#Call unlockAndCheck Function
unlockAndCheck
Write-Host ""
Write-Host "Pulsa cualqueir tecla para salir."
$checker2 += 6
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
"5" {
#exit code
$checker2 += 6
}
default {
Write-Host ""
Write-Host ""
Write-Host "Ha seleccionado un número incorrecto." -BackgroundColor Red -ForegroundColor White
Write-Host ""
$option = Read-Host "¿Quieres (1) Desbloquear el usuario, (2) Resetear la contraseña del usuario, (3) Desbloquear y resetear contraseña o (4) Desbloquear, resetear y cambiar en el logon siguiente (5) Salir?"
}
}
}