Cuando se definen contraseñas que caducan, después de cierto número de días en Active Directory, los usuarios remotos sufren porque no reciben una notificación como los usuarios locales y que hacen que su contraseña caduque. Finalmente, es demasiado tarde para que puedan cambiar sus contraseñas y se estas se bloquean. La solución fue que a través de una secuencia de comando o manualmente enviar un mail avisando que sus contraseñas van expirar .

 

Hay VB Scripts sencillos, que hacen este tipo de cosas.

o http://msdn.microsoft.com/en-us/library/ms974598.aspx

o http://techontip.wordpress.com/2009/12/27/sending-active-directory-domain-password-expiration-notification-to-end-users/

o http://www.carltoncolter.com/development/2-scripts/13-password-expiration-notification-by-email

o http://www.messageops.com/improved-password-expiration-notification-script

o http://geekswithblogs.net/bullpit/archive/2009/10/30/automated-password-expiration-notice-for-remote-active-directory-users.aspx

o http://www.brianmadden.com/forums/t/43205.aspx

 

Adicionalmente he encontrado una aplicación de consola de aplicación en C# que envía correos electrónicos a los usuarios si su contraseña va a caducar, y también correo al administrador. Puede programar que se ejecute cada día como una tarea programada de Windows y esto enviará un correo electrónico a los usuarios cuando faltan 15 días (valor predeterminado) .

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.DirectoryServices;

using ActiveDs;

using System.DirectoryServices.ActiveDirectory;

using System.IO;

using System.Configuration;

using System.Net.Mail;

using System.Resources;

using System.Reflection;

using System.Security.Principal;

namespace PasswordNotification

{

class Program

{

public static string GetAdministratorEmail()

{

return SettingsProvider.Get(“AdministratorEmail”, “”);

}

public static string GetMailServer()

{

return SettingsProvider.Get(“MailServer”, “”);

}

public static string GetCountdown()

{

return SettingsProvider.Get(“Countdown”, “15″);

}

static void Main(string[] args)

{

try

{

GetPasswordExpirationSendEmailNotifications();

}

catch (System.Exception ex)

{

SendEmail(“<AdminEmail>”, “<AdminEmail>”, “Exception: Password Notification”, ex.Message, MailPriority.High);

}

}

// This method checks for flags like PasswordDoesNotExpire

private static bool CheckAdsFlag(AdsUserFlags flagToCheck, DirectoryEntry user)

{

AdsUserFlags userFlags = (AdsUserFlags)user.Properties[“userAccountControl”].Value;

return userFlags.ToString().Contains(flagToCheck.ToString()); }

// This method gets the password expiration and sends email to
// the users and a report to the Administrator

private static void GetPasswordExpirationSendEmailNotifications()

{

string adminEmail = GetAdministratorEmail();

// Get the DOMAIN

//ActiveDs.ADSystemInfoClass objUserInformation = new ActiveDs.ADSystemInfoClass();

//string sDomain = objUserInformation.DomainDNSName;

string sDomain = Environment.UserDomainName;

// Since maxPwdAge is the Domain policy, it has to be retrieved for the
// domain

TimeSpan maxPwdAge = TimeSpan.MinValue;

int maxPwdAgeDays = 0;

using (DirectoryEntry domain = new DirectoryEntry(“LDAP://” + sDomain))

{

DirectorySearcher ds = new DirectorySearcher(

domain,

“(objectClass=*)”,

null,

SearchScope.Base

);

SearchResult sr = ds.FindOne();

if (sr.Properties.Contains(“maxPwdAge”))

{

maxPwdAge = TimeSpan.FromTicks((long)sr.Properties[“maxPwdAge”][0]);

maxPwdAgeDays = maxPwdAge.Days;

}
// maxPwdAge is in negative, make it positive

if (maxPwdAgeDays < 0)

{

maxPwdAgeDays *= -1;

}

}

//Define the filter for your LDAP query

string filter = “(&(objectCategory=person)(objectClass=user))”;

DirectorySearcher search = new DirectorySearcher(filter);

StringBuilder sb = new StringBuilder();

sb.Append(“<u>User Password Expiration Report</u><br/><br/>”);

int count = 0;

bool sendReport = false;

// Read file EmailBody.txt

string filePath = String.Format(“{0}\\EmailBody.txt”, Directory.GetCurrentDirectory());

string fileContents = TextFileReader(filePath);

foreach (SearchResult result in search.FindAll())

{

// Do work with data returned for each address entry

DirectoryEntry entry = result.GetDirectoryEntry();

// ActiveDs.LargeInteger needs to be used to manipulate pwdLastSet value

LargeInteger liAcctPwdChange = entry.Properties[“pwdLastSet”].Value as LargeInteger;

string mailValue = “”;

if (entry.Properties[“mail”].Value != null)

{

mailValue = entry.Properties[“mail”].Value.ToString();

}

// Skip the user if there is no email id

if (string.IsNullOrEmpty(mailValue))

{

continue;

}

// Skip the user if PasswordDoesNotExpire is set

if(CheckAdsFlag(AdsUserFlags.PasswordDoesNotExpire, entry))

{

continue;

}

// Manipulate LargeInteger liAcctPwdChange

long dateAcctPwdChange = (((long)(liAcctPwdChange.HighPart) << 32) + (long)liAcctPwdChange.LowPart);

// Convert FileTime to DateTime and get what today’s date is.

DateTime dtNow = DateTime.Now;

// Add maxPwdAgeDays to dtAcctPwdChange

DateTime dtAcctPwdChange = DateTime.FromFileTime(dateAcctPwdChange).AddDays(maxPwdAgeDays);

// Calculate the difference between the date the pasword was changed, and

// what day it is now.

TimeSpan timeRemaining;

timeRemaining = dtAcctPwdChange – dtNow;

// Send email to users if their password is going to expire

int countdown = Convert.ToInt32(GetCountdown());

int daysRemaining = timeRemaining.Days;

if (daysRemaining <= countdown)

{

sendReport = true;

count++;

string displayName = “”;

if (entry.Properties[“displayname”].Value != null)

{

displayName = entry.Properties[“displayname”].Value.ToString();

}

// DisplayName, Email, DaysRemaining

sb.AppendFormat(“{0}. {1} {2}: {3} days remaining.{4}”, count.ToString(), displayName, mailValue, daysRemaining.ToString(), “<br/>”);

string toEmail = mailValue;

string subject = String.Format(“Password Expiration in {0} days”, daysRemaining.ToString());

string body = fileContents.Replace(“[DAYCOUNT]“, daysRemaining.ToString());

body = body.Replace(“[USERNAME]“, displayName);

body = body.Replace(“\r\n”, “<br />”);

Console.Write(String.Format(“Sending email to {0}…”, toEmail));

SendEmail(adminEmail, toEmail, subject, body, MailPriority.High);

Console.WriteLine(“Done.”);

}

}

// Only send email report to Administrator if required

if (sendReport)

{

Console.Write(String.Format(“Sending email to {0}…”, adminEmail));

SendEmail(adminEmail, adminEmail, “User Password Expiration Report”, sb.ToString(), MailPriority.Normal);

Console.WriteLine(“Done.”);

}

}

private static void SendEmail(string fromEmail, string toEmail, string subject, string body, MailPriority priority)

{

string mailServer = GetMailServer();

//create the mail message

MailMessage mail = new MailMessage();

//set the addresses

mail.From = new MailAddress(fromEmail);

mail.To.Add(toEmail);

//set the content

mail.Subject = subject;

mail.Body = body;

mail.IsBodyHtml = true;

//send the message

SmtpClient smtp = new SmtpClient(mailServer);

smtp.Send(mail);

}

private static string TextFileReader(string filePath)

{

string fileContents = “”;

// create reader & open file

using (TextReader tr = new StreamReader(filePath))

{

// read a line of text

fileContents = tr.ReadToEnd();

}

return fileContents;

}

[Flags]

internal enum AdsUserFlags

{

Script = 1, // 0×1

AccountDisabled = 2, // 0×2

HomeDirectoryRequired = 8, // 0×8

AccountLockedOut = 16, // 0×10

PasswordNotRequired = 32, // 0×20

PasswordCannotChange = 64, // 0×40

EncryptedTextPasswordAllowed = 128, // 0×80

TempDuplicateAccount = 256, // 0×100

NormalAccount = 512, // 0×200

InterDomainTrustAccount = 2048, // 0×800

WorkstationTrustAccount = 4096, // 0×1000

ServerTrustAccount = 8192, // 0×2000

PasswordDoesNotExpire = 65536, // 0×10000

MnsLogonAccount = 131072, // 0×20000

SmartCardRequired = 262144, // 0×40000

TrustedForDelegation = 524288, // 0×80000

AccountNotDelegated = 1048576, // 0×100000

UseDesKeyOnly = 2097152, // 0×200000

DontRequirePreauth = 4194304, // 0×400000

PasswordExpired = 8388608, // 0×800000

TrustedToAuthenticateForDelegation = 16777216, // 0×1000000

NoAuthDataRequired = 33554432 // 0×2000000

}

}

}

 

Fuente: http://geekswithblogs.net/bullpit/archive/2009/10/30/automated-password-expiration-notice-for-remote-active-directory-users.aspx

https://i1.wp.com/www.portalti.com/wp-content/uploads/2016/05/mail-protegido.png?fit=233%2C216https://i1.wp.com/www.portalti.com/wp-content/uploads/2016/05/mail-protegido.png?resize=150%2C139David Aponte ManzevitschWindows ServerActive Directory,Contraseña,Directorio Activo,Windows Server
Cuando se definen contraseñas que caducan, después de cierto número de días en Active Directory, los usuarios remotos sufren porque no reciben una notificación como los usuarios locales y que hacen que su contraseña caduque. Finalmente, es demasiado tarde para que puedan cambiar sus contraseñas y se estas se...