我工作的公司有一个 Web 服务,可以根据输入的信息创建新的 Active Directory 帐户,例如用户名、名字、姓氏、OU1、OU2 等。
此 Web 服务在 Windows Server 2003 上运行良好。现在我正在努力将 Web 服务移至 2008 R2 服务器。但是,某些功能不再起作用,即当它尝试为新创建的帐户设置随机初始密码时。
引发的异常是 TargetInvocationException,其中包含 COMException 的内部异常,并带有“RPC 服务器不可用”消息。
Imports System.DirectoryServices
Dim ldapPath As String = "..." 'assume valid LDAP path
Dim objContainer As DirectoryEntry = New DirectoryEntry(ldapPath, vbNullString, vbNullString, AuthenticationTypes.Secure)
objUser = objContainer.Children.Add("cn=" & Username.Trim, "user")
'sets objUser.Properties e.g. givenName, displayName, userPrincipalName, samAccountName, etc. Not important...
objUser.CommitChanges()
strPassword = RandomPassword() 'function that generates random password
objUser.Invoke("SetPassword", New Object() {strPassword})
objUser.Properties("useraccountcontrol").Value = "512" ' set as normal account
objUser.CommitChanges()
'and so on...
错误发生在以下行: objUser.Invoke("SetPassword", New Object() {strPassword})
奇怪的是,帐户创建本身有效,我可以从 Active Directory 用户和计算机中看到新用户。我咨询了几个管理 DC 和 Web 服务器安全性的人,他们真的不知道为什么......
最后,我想出了另一种设置密码的方法,即使用 System.DirectoryServices.AccountManagement 库。
所以代码变成了这样:
Imports System.DirectoryServices
Imports System.DirectoryServices.AccountManagement
Dim ldapPath As String = "..." 'assume valid LDAP path
Dim objContainer As DirectoryEntry = New DirectoryEntry(ldapPath, vbNullString, vbNullString, AuthenticationTypes.Secure)
Dim objUser As DirectoryEntry = objContainer.Children.Add("cn=" & Username.Trim, "user")
'sets objUser.Properties e.g. givenName, displayName, userPrincipalName, samAccountName, etc. Not important...
objUser.CommitChanges()
Dim domainContext As PrincipalContext = New PrincipalContext(ContextType.Domain, ...)
Dim user As UserPrincipal = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, Trim(Username))
strPassword = RandomPassword() 'function that generates random password
user.SetPassword(strPassword)
user.Enabled = True 'setting these two properties
user.PasswordNotRequired = False 'result in useraccountcontrol value = 512 (normal account)
user.Save()
'and so on...
我将旧代码与新代码混合在一起,但它似乎在新服务器上运行良好。需要注意的一件事是,有时 UserPrincipal.FindByIdentity 调用最初会返回 Nothing,我相信这是由于帐户创建或复制延迟所致。所以我必须通过多次尝试 FindByIdentity 来确保用户对象不是 Nothing,直到我得到对象。
尽管找到了解决问题的方法(更像是一种解决方法),但我仍然对为什么旧代码不能在新服务器上运行而感到困惑,但新代码却可以。该错误非常普遍,在互联网上搜索线索只会导致更多混乱。
如果那里的专家可以阐明一些观点,甚至评论我的新代码的外观,我会非常感激,有什么问题吗?
提前致谢。