AD帐户操作C#示例代码(一)——导入用户信息_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > AD帐户操作C#示例代码(一)——导入用户信息

AD帐户操作C#示例代码(一)——导入用户信息

 2014/4/5 18:16:45  C#开发人员  博客园  我要评论(0)
  • 摘要:最近写了一个AD帐户导入的小工具(为啥写作“帐”户呢?),跟大家分享下相关代码,欢迎各位高手提出批评建议!首先,我准备一个这样的Excel文件作为导入模版,并添加了一些测试数据。然后,我打开VisualStudio2012,新建一个Windows窗体应用程序。在主窗体界面,我放了一些Label、TextBox、Button控件,还有一个ProgressBar。开始写代码。首先写从Excel里读取数据的方法。privatestaticasyncTask<
  • 标签:C# 代码 用户 操作

    最近写了一个AD帐户导入的小工具(为啥写作“帐”户呢?),跟大家分享下相关代码,欢迎各位高手提出批评建议!

    首先,我准备一个这样的Excel文件作为导入模版,并添加了一些测试数据。

  

    然后,我打开Visual Studio 2012,新建一个Windows窗体应用程序。在主窗体界面,我放了一些Label、TextBox、Button控件,还有一个ProgressBar

 

      开始写代码。首先写从Excel里读取数据的方法。

        private static async Task<DataTable> GetTableFromExcelAsync(string fileName)
        {
            return await Task.Factory.StartNew<DataTable>(() => GetTableFromExcel(fileName));
        }

        private static DataTable GetTableFromExcel(string fileName)
        {
            DataTable dataTable = new DataTable();
            string connectionString = string.Format("Provider = Microsoft.ACE.OLEDB.12.0;Data Source ={0};Extended Properties='Excel 12.0 Xml;HDR=YES'", fileName);
            using (OleDbConnection oleDbConnection = new OleDbConnection(connectionString))
            {
                oleDbConnection.Open();
                DataTable schemaTable = oleDbConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new Object[] { null, null, null, "TABLE" });
                string sheetName = schemaTable.Rows[0].Field<string>("TABLE_NAME");
                string commandText = string.Format("select * from [{0}]", sheetName);
                using (OleDbDataAdapter adapter = new OleDbDataAdapter(commandText, oleDbConnection))
                {
                    adapter.Fill(dataTable);
                }
            }
            return dataTable;
        }


     这样调用,将结果保存在一个DataTable里:

       private async void btnImport_Click(object sender, EventArgs e)
       {
            DataTable dataTable = await GetTableFromExcelAsync(txtUserListPath.Text);
       }


     运行出现异常:“未在本地计算机上注册 Microsoft.ACE.OLEDB.12.0 提供程序”。

 

      我的系统是X64的Windows 8 ,下载AccessDatabaseEngine.exe安装后,成功读取数据。

      下载地址是:http://download.microsoft.com/download/7/0/3/703ffbcb-dc0c-4e19-b0da-1463960fdcdb/AccessDatabaseEngine.exe

      在.NET中访问AD服务可以用DirectoryEntry类,首先要提供LDAP地址,作为我们创建用户的根OU,当然还要有在这个OU下创建OU和帐户的权限。

                string ldapPath = txtLdapPath.Text;
                string userName = txtUserName.Text;
                string password = txtPassword.Text; 

DirectoryEntry rootDirectoryEntry;
if (userName != string.Empty) { rootDirectoryEntry = new DirectoryEntry(ldapPath, userName, password); } else { rootDirectoryEntry = new DirectoryEntry(ldapPath); }

     DirectoryEntry 类使用参考:http://msdn.microsoft.com/zh-cn/library/z9cddzaa(v=vs.110).aspx

     在创建用户帐户前,要先创建它们依赖的上级OU。创建OU的代码如下:

DirectoryEntry currentOuDirectoryEntry = currentOuDirectoryEntry.Children.Add("OU=" + currentValue, "organizationalUnit");
currentOuDirectoryEntry.Properties["name"].Add(currentValue);
currentOuDirectoryEntry.CommitChanges();

     创建用户的代码如下:

DirectoryEntry currentUserDirectoryEntry = currentOuDirectoryEntry.Children.Add("CN=" + displayName, "user");
currentUserDirectoryEntry.Properties["sAMAccountName"].Value = sAMAccountName;
currentUserDirectoryEntry.Properties["userPrincipalName"].Value = string.Format(@"{0}@{1}", sAMAccountName, domainName);
currentUserDirectoryEntry.Properties["displayName"].Value = displayName;
currentUserDirectoryEntry.CommitChanges();

     DirectoryEntry类的Properties属性是一个集合,除了一些字符串类型的属性,还有几个我觉得操作比较麻烦的。

       例如"userAccountControl",看起来它只是一个整型字段,但是实际上它一个字段包含了很多属性信息,修改它需要做十六进制值的运算——这个我不擅长。(我见过有人设计数据库表的字段时,把几个维度的单据状态都存在一个int字段里,每次读取都要移位.....)还好我们可以直接用几个常用的,我创建的用户帐户不需要禁用,所以userAccountControl给512。

       使用userAccountControl标志请参考资料:http://support.microsoft.com/kb/305144/zh-cn。

       还有这些“System.__ComObject”类型的属性,操作起来太不方便了。我在网上找了一些资料,通常是引用了一个“Interop.ActiveDs.dll”的文件(不清楚是谁写的)。我这里只是希望新创建的用户下次登录时更改密码就要写:

currentUserDirectoryEntry.Properties["pwdLastSet"].Value = new LargeInteger() { HighPart = 0, LowPart = 0 };

      不过后来我不是用的上面代码而是这样写的,也成功了。

currentUserDirectoryEntry.Properties["pwdLastSet"].Value = 0;

     关于ADSI 对象属性有个参考资料:http://msdn.microsoft.com/zh-cn/library/ms180868(v=vs.90).aspx。

     如果您一次性把这几个属性都提交了,还可能会出现一个很有个性的异常:“该服务器不愿意处理该请求”。

     要想让“她”愿意,可以这样写:

using (DirectoryEntry currentUserDirectoryEntry = currentOuDirectoryEntry.Children.Add("CN=" + displayName, "user"))
                            {
                                currentUserDirectoryEntry.Properties["sAMAccountName"].Value = sAMAccountName;
                                currentUserDirectoryEntry.Properties["userPrincipalName"].Value = string.Format(@"{0}@{1}", sAMAccountName, domainName);
                                currentUserDirectoryEntry.Properties["displayName"].Value = displayName;
                                currentUserDirectoryEntry.CommitChanges();
                                currentUserDirectoryEntry.Properties["userAccountControl"].Value = userAccountControl;
                                currentUserDirectoryEntry.Properties["pwdLastSet"].Value = 0;
                                currentUserDirectoryEntry.Invoke("SetPassword", new object[] { newUserDefaultPassword });
                                currentUserDirectoryEntry.CommitChanges();
                            }

     因为我想给新导入的用户一个初始的密码,修改密码的操作这样写就可以了:

currentUserDirectoryEntry.Invoke("SetPassword", new object[] { newUserDefaultPassword });

     当用户是某个OU的管理员时,需要给它赋予权限。

                           if (string.Equals(currentDataRow[_isAdminColumnName] as string, @""))
                            {
                                IdentityReference newOwner = new NTAccount(domainName, sAMAccountName).Translate(typeof(SecurityIdentifier));
                                ActiveDirectoryAccessRule newRule = new ActiveDirectoryAccessRule(newOwner, ActiveDirectoryRights.GenericAll, AccessControlType.Allow);
                                currentOuDirectoryEntry.ObjectSecurity.SetAccessRule(newRule);
                                currentOuDirectoryEntry.CommitChanges();
                            }

     如果要导入的用户已经存在,就会出现异常。那么如何判断一个用户是否已存在呢?这时我们需要用到的是.NET的DirectorySearcher类型。这个类型的一个构造方法需要给一个搜索根路径、搜索筛选器、要检索的属性和搜索范围。

 DirectorySearcher userDirectorySearcher = new DirectorySearcher(currentOuDirectoryEntry, string.Format(@"(&(cn={0})(objectCategory=person)(objectClass=user))", displayName), new[] { "adspath" }, SearchScope.OneLevel);
 SearchResult searchResult = userDirectorySearcher.FindOne();
 if (searchResult != null)
 {
//TODO:......
}

     DirectorySearcher 类使用参考:http://msdn.microsoft.com/zh-cn/library/System.DirectoryServices.DirectorySearcher(v=vs.90).aspx    

     最后将这些零散的代码组合起来,就是我要做的工具了!

     看看导入的效果,算是成功导入了吧。

     当然这只是个很简单的小例子,日后还要继续完善,各位专家、高手如果看到我做的不好的地方也欢迎批评指正,多给些高大上的建议,非常感谢!

 

AD用户导入工具下载:

http://files.cnblogs.com/CSharpDevelopers/ADUserImportTool.zip
    

发表评论
用户名: 匿名