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://www.carltoncolter.com/development/2-scripts/13-password-expiration-notification-by-email
o http://www.messageops.com/improved-password-expiration-notification-script
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
}
}
}









Comentarios Via Facebook
One Comment »