Normalt används funktionen NetUserChangePassword för att programmatiskt byta lösenord. Dock finns inte den exponerad i .Nets klassbibliotek. Man använder då "interop" (interoperability) eller mer specifikt P/Invoke för att komma åt den som en vanlig C-funktioner från en dll.
NetUserChangePassword finns i Netapi32.dll, och du måste då i din klass berätta att du vill komma åt den. Såhär:
[DllImport("Netapi32.dll", EntryPoint="NetUserChangePassword", SetLastError=false, CharSet=CharSet.Unicode, ExactSpelling=true)]
private static extern NET_API_STATUS NetUserChangePassword(String domainname, String username, String oldpassword, String newpassword);
Nu vet .Net runtimen att den ska använda den NetUserChangePassword som finns i NetApi32.dll från din C# kod. Dock finns inte NET_API_STATUS i .Nets klassbibliotek, men från <LMCons.h> ser man att det är en DWORD, vilket i C# motsvarar en uint.
Det är smidigt att lägga in returvärdena i en enum. Dessutom tycker jag det är trevligare att wrappa all funktionalitet i en klass så att användaren av klassen inte ser vad som ligger bakom. Klassen har statiska publika metoder för att byta lösenord och kastar exception om något går fel. All kod är *givetvis* helt otestad.
using System;
using System.Runtime.InteropServices;
public sealed class NetApi
{
#region P/Invoke
private const uint NERR_BASE = 2100; // från <LMErr.h>
private enum NET_API_STATUS : uint
{
NERR_Success = 0,
ERROR_ACCESS_DENIED = 5,
ERROR_INVALID_PASSWORD = 86,
NERR_InvalidComputer = NERR_BASE+251,
NERR_NotPrimary = NERR_BASE+126,
NERR_UserNotFound = NERR_BASE+121,
NERR_PasswordTooShort = NERR_BASE+145,
}
[DllImport("Netapi32.dll", EntryPoint="NetUserChangePassword", SetLastError=false, CharSet=CharSet.Unicode, ExactSpelling=true)]
private static extern NET_API_STATUS NetUserChangePassword(String domainname, String username, String oldpassword, String newpassword);
#endregion
// Den här klassen vill vi inte skapa instanser av. En privat konstruktor
// stoppar det.
private NetApi() {}
#region Exceptions
// Just nu har vi bara password-funktionalitet, men senare kanske du
// vill lägga till mer från NetApi. Därför har vi ett bas-exception
// för framtida bruk.
public class NetApiException : Exception
{
}
// Detta kastas om password-bytet gått fel
public sealed class PasswordException : NetApiException
{
public enum ExceptionReason
{
OldPasswordRejected,
NewPasswordRejected,
InvalidUserName,
DomainNotFound,
NotPrimary,
UnknownError,
};
ExceptionReason m_Reason;
ExceptionReason Reason { get { return m_Reason; } }
public PasswordException(ExceptionReason reason)
{
m_Reason = reason;
}
public override string ToString()
{
return "Failed to change password: " + Reason.ToString();
}
}
#endregion
/// <summary>
/// Byter lösenord för angiven användare
/// </summary>
public static void ChangePassword(String domainname, String username, String oldpassword, String newpassword)
{
if (oldpassword == null) throw new ArgumentNullException("oldpassword");
if (newpassword == null) throw new ArgumentNullException("newpassword");
switch (NetUserChangePassword(domainname, username, oldpassword, newpassword))
{
case NET_API_STATUS.NERR_Success:
break;
case NET_API_STATUS.NERR_UserNotFound:
throw new PasswordException(PasswordException.ExceptionReason.InvalidUserName);
case NET_API_STATUS.ERROR_INVALID_PASSWORD:
throw new PasswordException(PasswordException.ExceptionReason.OldPasswordRejected);
case NET_API_STATUS.NERR_PasswordTooShort:
throw new PasswordException(PasswordException.ExceptionReason.NewPasswordRejected);
case NET_API_STATUS.NERR_InvalidComputer:
throw new PasswordException(PasswordException.ExceptionReason.DomainNotFound);
case NET_API_STATUS.NERR_NotPrimary:
throw new PasswordException(PasswordException.ExceptionReason.NotPrimary);
default:
throw new PasswordException(PasswordException.ExceptionReason.UnknownError);
}
}
/// <summary>
/// Byter lösenord för användaren som kör detta.
/// </summary>
public static void ChangePassword(String oldpassword, String newpassword)
{
ChangePassword(null, null, oldpassword, newpassword);
}
}
Mer information om interop finns bland annat här: