C# 以编程方式锁定 Active Directory 帐户
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/178730/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Lock Active Directory accounts programmatically
提问by Markus Dulghier
I have to lock user accounts in Active Directory programmatically in C#.
我必须在 C# 中以编程方式锁定 Active Directory 中的用户帐户。
Unfortunately it doesn't work via the userAccountControl attribute. Every time I set userAccountControl to 528 (=normal account w/ lockout flag), Active Directory won't accept the value and resets it without further notice to 512 (=normal account).
不幸的是,它不能通过 userAccountControl 属性工作。每次我将 userAccountControl 设置为 528(=带锁定标志的普通帐户)时,Active Directory 将不接受该值并将其重置为 512(=普通帐户),恕不另行通知。
Now I tried to lock the account by providing incorrect credentials (see below), but this doesn't work either.
现在我试图通过提供不正确的凭据来锁定帐户(见下文),但这也不起作用。
int retries = 0;
while (!adsUser.IsAccountLocked && retries < MAX_LOCK_RETRIES)
{
retries++;
try
{
new DirectoryEntry(userPath, logonName, incorrectPassword).RefreshCache();
}
catch (Exception)
{
/* ... */
}
adsUser.GetInfo();
}
Any ideas?
有任何想法吗?
采纳答案by Nick DeVore
Make sure the account you're using to disable the account has sufficient privileges to disable accounts. See this examplefrom Microsoft.
确保您用于禁用帐户的帐户具有足够的权限来禁用帐户。请参阅Microsoft 的此示例。
回答by Robert Seitz
This will work once you have the directory entry object.
一旦您拥有目录条目对象,这将起作用。
DirectoryEntry de = result.GetDirectoryEntry();
int val = (int)de.Properties["userAccountControl"].Value;
de.Properties["userAccountControl"].Value = val | 0x0002;
回答by user489041
This code will work to lock a user in AD
此代码将用于锁定 AD 中的用户
/// <summary>
/// Locks a user account
/// </summary>
/// <param name="userName">The name of the user whose account you want to unlock</param>
/// <remarks>
/// This actually trys to log the user in with a wrong password.
/// This in turn will lock the user out
/// </remarks>
public void LockAccount(string userName)
{
DirectoryEntry user = GetUser(userName);
string path = user.Path;
string badPassword = "SomeBadPassword";
int maxLoginAttempts = 10;
for (int i = 0; i < maxLoginAttempts; i++)
{
try
{
new DirectoryEntry(path, userName, badPassword).RefreshCache();
}
catch (Exception e)
{
}
}
user.Close();
}
回答by obsoleter
Depending on your Active Directory policies, interactive login attempts may be required to lock an account. You can simulate those using the LogonUser
method of advapi32.dll. In my tests, I have seen that running this loop 100 times does not guarantee 100 bad password attempts at the domain controller, so you should check the user is locked outand make more attempts if necessary.
根据您的 Active Directory 策略,可能需要尝试交互式登录才能锁定帐户。您可以使用LogonUser
advapi32.dll的方法模拟那些。在我的测试中,我已经看到运行这个循环 100 次并不能保证在域控制器上尝试 100 次错误的密码,因此您应该检查用户是否被锁定,并在必要时进行更多尝试。
The bottom line for this is that you should be disabling the account instead of trying to lock it. There is no functional difference between locked and disabled accounts. The code below is a hack.
这样做的底线是您应该禁用该帐户而不是尝试锁定它。有锁定并禁用帐户的功能没有差异。下面的代码是一个黑客。
using System;
using System.Runtime.InteropServices;
namespace Test
{
class Program
{
static void Main(string[] args)
{
IntPtr token = IntPtr.Zero;
string userPrincipalName = "[email protected]";
string authority = null; // Can be null when using UPN (user principal name)
string badPassword = "bad";
int maxTries = 100;
bool res = false;
for (var i = 0; i < maxTries; i++)
{
res = LogonUser(userPrincipalName, authority, badPassword, LogonSessionType.Interactive, LogonProvider.Default, out token);
CloseHandle(token);
}
}
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool LogonUser(
string principal,
string authority,
string password,
LogonSessionType logonType,
LogonProvider logonProvider,
out IntPtr token);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
enum LogonSessionType : uint
{
Interactive = 2,
Network,
Batch,
Service,
NetworkCleartext = 8,
NewCredentials
}
enum LogonProvider : uint
{
Default = 0, // default for platform (use this!)
WinNT35, // sends smoke signals to authority
WinNT40, // uses NTLM
WinNT50 // negotiates Kerb or NTLM
}
}
}