We used the following ADSI (System.DirectoryServices in .NET) call to reliably detect password expiration date, regardless whether the user account was a local or domain account and regardless of which security policy applies to the given user (see IAdsUser interface reference):
static DateTime PasswordExpiryTime(string domainOrMachine, string userName)
{
using (var directoryEntry = new System.DirectoryServices.DirectoryEntry("WinNT://" + domainOrMachineName + '/' + userName + ",user"))
{
try
{
return (DateTime)directoryEntry.InvokeGet("PasswordExpirationDate");
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
}
}
Initially we also used ADSI to perform the password change:
static void ChangePassword(string domainOrMachine, string userName, string oldPassword, string newPassword)
{
using (var directoryEntry = new System.DirectoryServices.DirectoryEntry("WinNT://" + domainOrMachineName + '/' + userName + ",user"))
{
try
{
directoryEntry.Invoke("ChangePassword", oldPassword, newPassword);
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
}
}
However, after a password change via ADSI we often encountered problems when connecting to for example SQL Server databases using integrated security. It seems that certain cached credentials didn't get refreshed. Ultimately, the resolution for this problem was to directly call the Windows NetUserChangePassword API:
static void ChangePassword(string domainOrMachine, string userName, string oldPassword, string newPassword)
{
uint returnValue = NetUserChangePassword(domainOrMachine, userName, oldPassword, newPassword);
if (returnValue != 0) throw new Win32Exception();
}
No comments:
Post a Comment