C# AD(Active Directory)域信息同步,组织单位、用户等信息查询


接上篇 Windows Server 2008 R2 配置AD(Active Directory)域控制器

对AD域结合常见需求用C#进行一些读取信息的操作^_^!

 

目录

 

 

示例准备
  • 打开上一篇文章配置好的AD域控制器
  • 开始菜单-->管理工具-->Active Directory 用户和计算机
  • 新建组织单位和用户

   

  • 新建层次关系如下:

  

 

知识了解

  我们要用C#访问Active Directory非常容易,主要用到

  轻量目录访问协议 (LDAP)

  System.DirectoryServices命名空间下的两个组件类

  DirectoryEntryDirectorySeacher

 

读取AD域信息示例

   示例在Framework 3.5下用Winform程序编写

   主要结合常见需求读取组织单位(OU)及用户(User)信息,以及同步组织单位和用户的层次关系;

     比较着重的还是用户的信息,特别是帐号、邮箱、SID等信息;

  

  • 下面我们开始连接域,并读取出示例准备中键好的组织单位和用户  

  首先编写代码用LDAP尝试对域进行访问

  形式:LDAP://Domain

复制代码
  #region## 是否连接到域
  /// <summary>
  /// 功能:是否连接到域
  /// 作者:Wilson
  /// 时间:2012-12-15
  /// http://msdn.microsoft.com/zh-cn/library/system.directoryservices.directoryentry.path(v=vs.90).aspx
  /// </summary>
  /// <param name="domainName">域名或IP</param>
  /// <param name="userName">用户名</param>
  /// <param name="userPwd">密码</param>
  /// <param name="entry">域</param>
  /// <returns></returns>
  private bool IsConnected(string domainName, string userName, string userPwd, out DirectoryEntry domain)
  {
      domain = new DirectoryEntry();
      try
      {
          domain.Path = string.Format("LDAP://{0}", domainName);
          domain.Username = userName;
          domain.Password = userPwd;
          domain.AuthenticationType = AuthenticationTypes.Secure;

          domain.RefreshCache();

          return true;
      }
      catch(Exception ex)
      {
          LogRecord.WriteLog("[IsConnected方法]错误信息:" + ex.Message);
          return false;
      }
  }
  #endregion
复制代码

   传用参数,调IsConnected方法,结果如下

  

  • 连接上AD域后,接着我们找到根OU
复制代码
  #region## 域中是否存在组织单位
  /// <summary>
  /// 功能:域中是否存在组织单位
  /// 作者:Wilson
  /// 时间:2012-12-15
  /// </summary>
  /// <param name="entry"></param>
  /// <param name="ou"></param>
  /// <returns></returns>
  private bool IsExistOU(DirectoryEntry entry, out DirectoryEntry ou)
  {
       ou = new DirectoryEntry();
       try
       {
           ou = entry.Children.Find("OU=" + txtRootOU.Text.Trim());

           return (ou != null);
       }
       catch(Exception ex)
       {
           LogRecord.WriteLog("[IsExistOU方法]错误信息:" + ex.Message);
           return false;
       }
   }
   #endregion
复制代码

  传入以数,调用IsExistOU方法,结果如下

  

  • 下面来开始读取组织单位及用户的信息。

   示例为了看出层次关系及导出信息是类型区分,给OU和User新建了一个实体类和一个类型的枚举 

复制代码
    #region## 类型
    /// <summary>
    /// 类型
    /// </summary>
    public enum TypeEnum : int
    {
        /// <summary>
        /// 组织单位
        /// </summary>
        OU = 1,

        /// <summary>
        /// 用户
        /// </summary>
        USER = 2
    }
    #endregion

    #region## Ad域信息实体
    /// <summary>
    /// Ad域信息实体
    /// </summary>
    public class AdModel
    {
        public AdModel(string id, string name, int typeId, string parentId)
        {
            Id = id;
            Name = name;
            TypeId = typeId;
            ParentId = parentId;
        }

        public string Id { get; set; }

        public string Name { get; set; }

        public int TypeId { get; set; }

        public string ParentId { get; set; }
    }
    #endregion
复制代码

   下面读取信息

复制代码
        private List<AdModel> list = new List<AdModel>();

     #region## 同步 /// <summary> /// 功能:同步 /// 创建人:Wilson /// 创建时间:2012-12-15 /// </summary> /// <param name="entryOU"></param> public void SyncAll(DirectoryEntry entryOU) { DirectorySearcher mySearcher = new DirectorySearcher(entryOU, "(objectclass=organizationalUnit)"); //查询组织单位 DirectoryEntry root = mySearcher.SearchRoot; //查找根OU SyncRootOU(root); StringBuilder sb = new StringBuilder(); sb.Append("\r\nID\t帐号\t类型\t父ID\r\n"); foreach (var item in list) { sb.AppendFormat("{0}\t{1}\t{2}\t{3}\r\n", item.Id, item.Name, item.TypeId, item.ParentId); } LogRecord.WriteLog(sb.ToString()); MessageBox.Show("同步成功", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); Application.Exit(); } #endregion #region## 同步根组织单位 /// <summary> /// 功能: 同步根组织单位 /// 创建人:Wilson /// 创建时间:2012-12-15 /// </summary> /// <param name="entry"></param> private void SyncRootOU(DirectoryEntry entry) { if (entry.Properties.Contains("ou") && entry.Properties.Contains("objectGUID")) { string rootOuName = entry.Properties["ou"][0].ToString(); byte[] bGUID = entry.Properties["objectGUID"][0] as byte[]; string id = BitConverter.ToString(bGUID); list.Add(new AdModel(id, rootOuName, (int)TypeEnum.OU, "0")); SyncSubOU(entry, id); } } #endregion #region## 同步下属组织单位及下属用户 /// <summary> /// 功能: 同步下属组织单位及下属用户 /// 创建人:Wilson /// 创建时间:2012-12-15 /// </summary> /// <param name="entry"></param> /// <param name="parentId"></param> private void SyncSubOU(DirectoryEntry entry, string parentId) { foreach (DirectoryEntry subEntry in entry.Children) { string entrySchemaClsName = subEntry.SchemaClassName; string[] arr = subEntry.Name.Split('='); string categoryStr = arr[0]; string nameStr = arr[1]; string id = string.Empty; if (subEntry.Properties.Contains("objectGUID")) //SID { byte[] bGUID = subEntry.Properties["objectGUID"][0] as byte[]; id = BitConverter.ToString(bGUID); } bool isExist = list.Exists(d => d.Id == id); switch (entrySchemaClsName) { case "organizationalUnit": if (!isExist) { list.Add(new AdModel(id, nameStr, (int)TypeEnum.OU, parentId)); } SyncSubOU(subEntry, id); break; case "user": string accountName = string.Empty; if (subEntry.Properties.Contains("samaccountName")) { accountName = subEntry.Properties["samaccountName"][0].ToString(); } if (!isExist) { list.Add(new AdModel(id, accountName, (int)TypeEnum.USER, parentId)); } break; } } } #endregion
复制代码

  调用SyncAll方法循环输出list,结果如下,很清楚的可以看出层次关系

复制代码
        //ID                                                 帐号             类型    父ID
        //58-D6-C4-32-6A-A1-99-48-A4-8B-C8-5D-BC-C9-3E-17    acompany        1       0
        //FB-44-91-AE-AC-73-2B-4D-9F-01-B1-E2-16-D3-CB-1B    department01    1       58-D6-C4-32-6A-A1-99-48-A4-8B-C8-5D-BC-C9-3E-17
        //47-9D-5B-91-60-22-D1-46-B0-CD-C7-B2-C7-D3-00-31    department03    1       FB-44-91-AE-AC-73-2B-4D-9F-01-B1-E2-16-D3-CB-1B
        //E3-AD-47-45-38-64-02-4D-B9-83-2C-50-67-50-4F-92    zw              2       47-9D-5B-91-60-22-D1-46-B0-CD-C7-B2-C7-D3-00-31
        //8A-D4-23-18-F3-6F-E1-47-93-7A-CC-07-76-4B-E7-86    zhongw          2       FB-44-91-AE-AC-73-2B-4D-9F-01-B1-E2-16-D3-CB-1B
        //BC-D0-34-85-67-2F-05-4D-B5-77-E3-F4-AD-51-45-02    department02    1       58-D6-C4-32-6A-A1-99-48-A4-8B-C8-5D-BC-C9-3E-17
        //1C-13-FA-66-E4-51-65-49-8B-DC-22-60-32-34-8F-22    wilson          2       BC-D0-34-85-67-2F-05-4D-B5-77-E3-F4-AD-51-45-02
        //84-E8-E5-9A-6B-56-E2-45-9A-87-54-D1-78-6B-D3-56    porschev        2       58-D6-C4-32-6A-A1-99-48-A4-8B-C8-5D-BC-C9-3E-17
复制代码

 

DirectorySearcher.Filter属性扩充说明

     DirectorySearcher mySearcher = new DirectorySearcher(entryOU, "(objectclass=organizationalUnit)"); //查询组织单位  

  第二个参数是一个filter,也可以根据需求输入其它筛选条件,下面列出几个常用的

筛选条件
用户 (&(objectCategory=person)(objectClass=user))
计算机 (objectCategory=computer)
(objectCategory=group)
联系人 (objectCategory=contact)
共享文件夹 (objectCategory=volume)
打印机 (objectCategory=printQueue)

    更多高级筛选请查看:http://msdn.microsoft.com/zh-cn/library/system.directoryservices.directorysearcher.filter(v=vs.80).aspx

 

 

用户属性扩充说明(含图文属性对照)

   示例中只对用户进行了读取了几个属性,用过AD域的应该都知道,用户的属性较多也比较常用。

  下面通过AD域的用户详细信来对照一下相应的属性名

  • 常项选项卡

  

对应编号 选项卡对应项名 属性名
姓(L) sn                                     
名(F) givenName                              
显示名称(S) displayName                            
描述(D) description                            
办公室(C) physicalDeliveryOfficeName             
英文缩写(I) initials                               
电话号码(T) telephoneNumber                        
电子邮件(M) mail                                   
网页(W) wWWHomePage                            
电话号码-其它(O)... otherTelephone                         
网页-其它(R)... url                                    

  

  • 地址选项卡

  

对应编号 选项卡对应项名 属性名
国家/地区(O) co                                      
省/自治区(V) st                                      
市/县(C) l
街道(S) streetAddress
邮政信箱(B) postOfficeBox
邮政编码(Z) postalCode

  

  • 帐户选项卡

  

对应编号 选项卡对应项名 属性名
用户登录名(U) userPrincipalName
用户登录名(Windows 2000 以前版本)(W) sAMAccountName

  

  • 电话选项卡

  

对应编号 选项卡对应项名 属性名
 家庭电话(M) homePhone                               
寻呼机(P) pager
移动电话(B) mobile
传真(F) facsimileTelephoneNumber
IP电话(I) ipPhone
注释 info
家庭电话-其它(O)  otherHomePhone                          
寻呼机-其它(T) otherPager                              
移动电话-其它(B) otherMobile                             
传真-其它(E) otherFacsimileTelephoneNumber           
IP电话-其它(R) otherIpPhone                            

 

  • 组织选项卡

  

对应编号 选项卡对应项名 属性名
公司(C)                               company                                  
部门(D)    department            
职务(J)                         title
经理-姓名(N)        manager                   
直接下属(E) directReports

  

  还有一些属性没有列出来,可以循环输出DirectoryEntry.Properties.PropertyNames来找

  比如用objectsid这也是个用户比较重要的属性,在设置Windows共享时会用到!

 

示例下载

 示例下载:http://files.cnblogs.com/zhongweiv/SynchronousAD.zip

 示例代码,写得比较简陋,有需要就下载了将就着看一下吧^_^!

 

 

 

作   者:   Porschev[钟慰] 
出   处:   http://www.cnblogs.com/zhongweiv/ 
微   博:     http://weibo.com/porschev 
欢迎任何形式的转载,但请务必注明原文详细链接

分类:  C#
标签:  AD活动目录
5
0
(请您对文章做出评价)
« 上一篇: Windows Server 2008 R2 配置AD(Active Directory)域控制器
» 下一篇: Windows Server 2008 R2 下配置证书服务器和HTTPS方式访问网站
posted @  2013-01-05 14:05  porschev 阅读( 2880) 评论( 31编辑  收藏
  
#1楼   2013-01-05 15:42  E2Home   
非常感谢,关于AD这块,资料还是比较少的,感谢LZ讲解这么详细!
  
#2楼   2013-01-05 15:53  Engineer   
mark,我正在做这一块
  
#3楼 [ 楼主2013-01-05 16:02  porschev   
@E2Home
确实没什么资料,这算是笔记吧
  
#4楼 [ 楼主2013-01-05 16:03  porschev   
@Engineer
谢谢支持,希望对你有用^_^!
  
#5楼   2013-01-05 17:35  伍华聪   
不错写的很详细
  
#6楼 [ 楼主2013-01-05 18:15  porschev   
@伍华聪
谢谢支持,常看LZ的Blog^_^!
  
#7楼   2013-01-05 23:47  6572789   
收藏了
  
#8楼   2013-01-07 16:16  acafaxy   
非常感谢,虽然没做这块,收藏下,说不定以后就能用到了。
  
#9楼   2013-01-07 18:53  通用信息化建设平台   
非常牛的文章,顶一下。
  
#10楼 [ 楼主2013-01-07 20:09  porschev   
@通用信息化建设平台
@acafaxy
谢谢支持
  
#11楼   2013-01-11 10:47  玉菜园   
这个很有用
  
#12楼   2013-02-25 10:35  小鸟不会飞   
怒收藏。
  
#13楼 [ 楼主2013-02-25 10:38  porschev   
@小鸟不会飞
@玉菜园
谢谢支持 ^_^!
  
#14楼   2013-03-20 10:42  我从草原来   
楼主问个问题,我最近正在做这块,我用的webform。
我用:DirectoryEntry container = new DirectoryEntry("LDAP://servername,ou=测试,dc=XXX,dc=com");实例化时,告诉我用户名,密码错误。应该是找到了服务器,可是没有权限。我想问的是,实例化时管理员名称和密码是必须要有的么?如:DirectoryEntry container = new DirectoryEntry(path,admin,pwd);
  
#15楼 [ 楼主2013-03-20 11:37  porschev   
@我从草原来
你好,刚看到邮件提示,你要问的是下面代码片段中DirectoryEntry对象的UserName和Password属性吗?
domain = new DirectoryEntry();
try
{
domain.Path = string.Format("LDAP://{0}", domainName);
domain.Username = userName;
domain.Password = userPwd;


--------------------------------------------
如果是,用户名和密码是必须的,要不然会进异常,提示用户名密码错误;
此处登录的用户要属于Domain Admins组
  
#16楼   2013-03-20 11:41  我从草原来   
嗯 谢谢!问的是这个问题,就是说这个用户名和密码不是必须要AD服务器的管理员帐号和密码,只要属于Domain Admins组就可以 是么?
  
#17楼 [ 楼主2013-03-20 12:15  porschev   
@我从草原来
是的,可以去用户属性里看,隶属于中有 Domain Users 和 Domain Admins 
,那这个用户就可以
  
#18楼   2013-05-17 11:29  我从草原来   
楼主 之前问过你问题 感谢您的解答!你博文中IsExistOU(DirectoryEntry entry, out DirectoryEntry ou)方法判断是否存在组织单元。我再判断时提示我“在服务器上没有这样一个对象,可是我要查找的ou确定是存在的”。因此我怀疑我传入的entry参数不正确。我想问的是 这个entry对象是根ou那个对象么?要如何初始化呢?
  
#19楼 [ 楼主2013-05-17 11:43  porschev   
@我从草原来
你好,仔细看我的代码中用到的IsExistOU方中第一个参数传入的是什么,
是IsConnected方法中返回的DirectoryEntry....
  
#20楼   2013-05-17 11:46  我从草原来   
非常感谢!顶起
  
#21楼   2013-05-20 09:56  我从草原来   
楼主 还要问你个问题 !今天做变更OU时发现的
首先我根据commonName找到DirectoryEntry对象 方法是
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public  DirectoryEntry GetDirectoryEntry( string  commonName)
        {
            DirectoryEntry de = GetDirectoryObject();
            DirectorySearcher deSearch = new  DirectorySearcher(de);
            deSearch.Filter = "(&(&(objectCategory=person)(objectClass=user))(sAMAccountName="  + commonName + "))" ;
            deSearch.SearchScope = System.DirectoryServices.SearchScope.Subtree;
            try
            {
                SearchResult result = deSearch.FindOne();
                de = new  DirectoryEntry(result.Path);
                return  de;
            }
            catch  (Exception ex)
            {
                return  null ;
            }
        }

GetDirectoryObject()的方法体是:
?
1
2
3
4
5
6
7
8
9
10
11
12
private  DirectoryEntry GetDirectoryObject()
        {
            DirectoryEntry entry = null ;
            try
            {
                entry = new  DirectoryEntry( "LDAP://a.com" , "zhangsan" , "123456" , AuthenticationTypes.Secure);
            }
            catch  (Exception ex)
            {
            }
            return  entry;
        }

zhangsan 这个用户属于管理员用户组:
最后 调用以上方法更改属性时
DirectoryEntry obj = GetDirectoryEntry("oatest01");
SetProperty(obj, "physicalDeliveryOfficeName", "x");
提示“登录失败: 未知的用户名或错误密码。”
可是我用上述的用户名和密码 新增帐号 和查询都没有此提示?不知是哪儿的问题。
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值