Active Directory: Avisar por mail a los usuarios de la caducidad de sus contraseñas

Desde Windows Vista, la advertencia de caducidad de contraseña es mucho menos agresiva que con XP.

Algunos usuarios que obvien esta viñeta recordatoria, o no suelan abrir sesion localmente (citrix, owa...) se encuentran con que la contraseña les ha expirado sin haberse dado cuenta.
Con este script powershell podemos avisar por mail de la caducidad de contraseñas con n dias de antelación a todos los usuarios.
Function Get-UAC($uac)
{
$flags=@()
if ((65536 -band $uac) -ne "0"){$flags+="DONT_EXPIRE_PASSWORD"}
return $flags
}
Function enviar-mail($mail,$body)
{
$subject="Aviso caducidad contraseña"
$smtpServer = "SRVEXCH.DOMINIO.LOCAL"
$emailFrom = "soporte@dominio.com"
$smtp = new-object Net.Mail.SmtpClient($smtpServer,587)
$mailAuthentication = new-object System.Net.NetworkCredential("mailcredentials", "password")
$smtp.UseDefaultCredentials = $False 
$smtp.Credentials =$mailAuthentication
$MailMessage = new-object Net.Mail.MailMessage($emailFrom, $mail, $subject, $body)
$MailMessage.IsBodyHtml = $true
$smtp.Send($MailMessage)
}
##### main #####
out-file "mailing_caducidad_contraseñas.csv" -input "usuario;ultimocambio;fechacaducidad;dias;avisado"
$SECS_IN_A_DAY=86400
$domain = [ADSI]"WinNT://$env:userdomain"
$intMaxPwdAge =($domain.maxpasswordage.value)/$SECS_IN_A_DAY
$ahora=get-date
#lista los datos de todos los usuarios del dominio
$searcher = New-Object DirectoryServices.DirectorySearcher([adsi]"")
$searcher.filter = "(&(objectclass=user)(objectcategory=person)(mail=*)(!userAccountControl:1.2.840.113556.1.4.803:=2))" 
$users = $searcher.findall() 

Foreach($user in $users) 
{
$TheUser=$user.GetDirectoryEntry()

$usuario=$theuser.samaccountname
$nombre=$theuser.givenname
$apellidos=$theuser.sn
$mail=$theuser.mail
$uac=$theUser.userAccountControl
$flags=Get-Uac("$uac")
 if ($flags -notcontains "DONT_EXPIRE_PASSWORD")
 {
 $PasswordLastChanged =$theuser.PasswordLastChanged
 $intTimeInterval = [int32]($ahora - $PasswordLastChanged).days
  If ($intTimeInterval -ge $intMaxPwdAge)
  {
  $strExpiringDays="CADUCADA"
  $avisar=0
  }
  else
  {
  $ExpiringDate = $PasswordLastChanged.addDays($intMaxPwdAge)
  $fechacaducidad=$Expiringdate.toString("dd/MM/yyyy")
  $ExpiringDays = [int32]($ExpiringDate - $ahora).days 
  $strExpiringDays= "$ExpiringDays dias"
#Avisar con 7 dias de antelacion
   if ($ExpiringDays -le 7)
   {
   $avisar=1
   $body= "$nombre $apellidos, usuario del sistema $usuario. Tu contraseña va a caducar dentro de " +  $ExpiringDays + " días (" + $fechacaducidad + "). 
Puedes cambiarla conectándote al correo OWA. 
Si no lo haces, tu cuenta se bloqueará y deberás abrir incidencia en 'soporte' para que la vuelvan a habilitar.

Soporte Sistemas"
   enviar-mail $mail $body
   }
   else
   {
   $avisar=0
   }#fin de if 7 dias
  }#fin de if caducada
 write-host "$usuario - $PasswordLastChanged - $strExpiringDays ($avisar)" -fore cyan
 out-file ".\mailing_caducidad_contraseñas.csv" -input "$usuario;$PasswordLastChanged;$fechacaducidad;$strExpiringDays;$avisar" -append
 
 }#fin de flags uac validos

}#fin foreach
El atributo userAccountControl es el encargado de almacenar las opciones de cuenta de usuario: ACCOUNTDISABLE, DONT_EXPIRE_PASSWORD, SMARTCARD_REQUIRED, PASSWD_NOTREQD... asignando valores decimales acumulativos a cada opción.
Para mas información sobre los diferentes valores de este atributo: http://support.microsoft.com/kb/305144/en-us

Comentarios

  1. Hola, tengo un escenario con windows 2008 R2 y lotus como servidor de correo. Este scrip no me sirve, no?

    ResponderEliminar
  2. Ya lo probe y funciona correctamente dentro de mi escenario, solo hay que cambiar el valor de $smtpServer.
    Colocando la ip del servidor de correo funciono correctamente.

    ResponderEliminar
  3. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  4. Buenos Tardes,
    Me gustaría avisar a los usuarios por mail de la caducidad de sus contraseñas, donde debería poner este script.
    Como podría hacer la prueba para ver si funciona.
    Gracias

    ResponderEliminar
    Respuestas
    1. crea una tarea programada en cualquier servidor miembro y ejecuta el script powershell.
      o bien ejecutas powershell.exe y pasas como parametro la ruta del script o haz un bat que invoca al script y ejecuta el bat en la tarea programada.
      Para que envie los correos tendras que corregir el servidor de correo en la linea 10 del script

      Eliminar
  5. Buenas Tardes. ¿ Se podría hacer lo mismo pero que es su certificado digital lo que se le va a acabar ? Un saludo y gracias.

    ResponderEliminar
    Respuestas
    1. claro, una fecha es una fecha, da igual que queden 7 dias para que expire una contraseña o que caduque un certificado. podrias reutilizar la mayor parte del script del articulo

      Eliminar
  6. Tengo varios errores al ejecutar este script, me podría ayudar a validar que puede estar sucediendo??? Muchas gracias.

    Cannot convert value to type System.String.
    At line:73 char:2
    + out-file "C:\Bats\mailing_caducidad_contraseñas_07032023.csv" -input ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvalidCastFromAnyTypeToString

    ResponderEliminar
  7. Este error también se presenta...

    Cannot convert value to type System.String.
    At line:72 char:2
    + write-host "$usuario - $PasswordLastChanged - $strExpiringDays ($avi ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvalidCastFromAnyTypeToString

    ResponderEliminar
  8. Exception calling "Send" with "1" argument(s): "Failure sending mail."
    At line:18 char:1
    + $smtp.Send($MailMessage)
    + ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SmtpException

    ResponderEliminar
  9. Method invocation failed because [System.Management.Automation.PSMethod] does not contain a method named 'addDays'.
    At line:52 char:3
    + $ExpiringDate = $PasswordLastChanged.addDays($intMaxPwdAge)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

    ResponderEliminar
  10. Cannot find an overload for "op_Subtraction" and the argument count: "2".
    At line:44 char:2
    + $intTimeInterval = [int32]($ahora - $PasswordLastChanged).days
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBest

    ResponderEliminar

Publicar un comentario