①问:LDAP这里代表什么意思?
Set objUser = objOU.Create ("User", "cn=MyerKen")
②问:user代表什么?是创建名字叫user的用户吗?还是代表要创建一个用户,而MyerKen才是用户名称?
objUser.Put "sAMAccountName", "myerken"
③ 问:sAMAccountName这个在这里代表什么?
objUser.Setinfo
C:publicdocumentsadsiadsi_spec.doc
目录服务命名空间也是使用基于目录定位的唯一名称来标识对象,这个位置必须是可以查询的。比如在遵循 X.500 目录中, 一个既定的对象使用的名称应该类似于这样:
CN=John,OU=Marketing,O=Fabrikam
不同的目录服务为它们所包含的对象使用不同的格式,那么如何处理这种情况就变得很富有挑战性,尤其对于开发者来说, 要考虑让代码适用于所有环境。
Active Directory Service Interfaces (ADSI) 应运而生,它的一个目标就是提供一个命名的架构,以便不同的目录服务提供者都能够访问它。
ADSI 定义一个命名规范,能够在多种目录结构的复杂环境中唯一的标识命名。这些名称称为 ADsPath 字串 ADsPath 字串遵循如下格式:
"ADs://" "LDAP://" "WinNT://"
附加的 ADsPath 格式被不同的 ADSI 提供者定义 (比如 Internet Information Services ADSI 提供者,支持 "IIS://" ADsPaths).那么Microsoft LDAP Provider ADsPath 定义如下:
LDAP://HostName[:PortNumber][/DistinguishedName]
注意:被[ ] 包括的是可选的参数
HostName
可以是一个计算机名称,一个 IP 地址或者一个域名,当然也可以指定一个服务器的名字。大多数 LDAP provider 都遵循这一模式。
PortNumber
指定用于连接的端口。如果没有指定,LDAP 将使用默认端口号 389 (使用 SSL )或者 636 (不使用用 SSL )
(详见 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/ldap_adspath.asp )
DistinguishedName
指定作用对象的 distinguished name ,这个名称必须是唯一的。
Distinguished Name 定义如下:
LDAP API 通过 distinguished name (DN) 访问一个 LDAP 对象。DN 是一个相对 distinguished names (RDN) 的序列,构成序列的各个字串之间通过逗号间隔。RDN 是一个以这样格式关联的属性值 attribute=value; 一般使用 UTF-8 编码,下面的列表中定义了各 RDN 属性类型。
DC | domainComponent |
CN | commonName |
OU | organizationalUnitName |
O | organizationName |
STREET | streetAddress |
L | localityName |
ST | stateOrProvinceName |
C | countryName |
UID | userid |
下面是一个 distinguished names 的例子:
如果是在windows active directory中,那么通常按照从上至下的层级结构,这个名称按照从后往前的顺序书
写,比如在一个域中 shenzhen.china.com 存在一个ou:department ,其下有个ou: purchase ,再下面
有一个用户或者组 gnaw0725 & SMgroup ,写法应该如下:
唯一标识用户 gnaw0725 cn=gnaw0725,ou=purchase,ou=department,dc=shenzhen,dc=china,dc=com
唯一标识组 SMgroup cn=SMgroup,ou=purchase,ou=department,dc=shenzhen,dc=china,dc=com
可以看到一般最后用cn来标识对象。
(详见: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/distinguished_names.asp )
(gnaw0725注:如果您在运行脚本的时候提示类似于这样的错误,
"D:ADBackupcreateuser.vbs(1, 1) (null): �o法指出的�e�`" |
那么请注意LDAP Provider是否小写了,这里一定要大写。)
②问:user代表什么?是创建名字叫user的用户吗?还是代表要创建一个用户,而MyerKen才是用户名称?
答:的确,这里的user表示需要创建的对象类型是user,而user的名称是MyerKen。
按照create method 定义如下:
IADsContainer::Create method 接受创建一个目录对象的请求,这个对象必须指定架构类型和既定名称。然后通过调用 IADs::SetInfo 将这个对象固定下来(关于为什么要执行 IADs::SetInfo 在后面描述),您就可以这个对象的属性了。
HRESULT Create( BSTR bstrClass, BSTR bstrRelativeName, IDispatch** ppNewObject);
-
bstrClass
- [in] Name of the schema class object to be created. The name is that returned from the IADs::get_Schema property method. bstrRelativeName
- [in] Relative name of the object as it is known in the underlying directory and identical to the one retrieved through the IADs::get_Name property method. ppNewObject
- [out] Indirect pointer to the IDispatch interface on the newly created object.
This method supports the standard return values, including S_OK for a successful operation. For more information about error codes, see ADSI Error Codes.
类似,Getobject method 定义如下:
The IADsContainer::GetObject method 为连接容器中的目录对象获取接口
HRESULT GetObject( BSTR bstrClass, BSTR bstrRelativeName, IDispatch** ppNamedObject);
-
bstrClass
- [in] A BSTR that specifies the name of the object class as of the object to retrieve. If this parameter is NULL, the provider returns the first item found in the container. bstrRelativeName
- [in] A BSTR that specifies the relative distinguished name of the object to retrieve. ppNamedObject
- [out] Pointer to a pointer to the IDispatch interface on the specified object.
This method supports standard return values, including S_OK for a successful operation. For more information about error codes, see ADSI Error Codes.
类似,setinfo method定义如下:
The IADs::SetInfo method 将缓存中 ADSI 对象的属性值写入目录数据库
HRESULT SetInfo();
This method has no parameters.
This method supports the standard return values, including S_OK for a successful operation. For more information, see ADSI Error Codes.
强调 IADs::Put 和 IADs::SetInfo methods 之间的不同是非常重要的。 前者设定缓存中的属性值,而或者将这个变化写入目录数据库。 因此,在没有调用 IADs::SetInfo 写入前,如果执行了 IADs::GetInfo (或者 IADs::GetInfoEx) ,任何被 IADs::Put 改变的属性值都会丢失。
由于最终的结果将要通过网络传输数据,出于安全、效率、带宽的考虑,不可能让使用者一直连接到数据库,那么出于设计的考虑,系统将每次修改的数据先存放在本地缓存,最后由 IADs::SetInfo 将所有变更数据提交给服务器上的数据库,这样做极大的降低了客户端连接服务器数据库的次数,提高了效率。在平时程序设计中您也应该遵循这个规则,尽可能在最后提交所有或者大多数的变更,把缓存的数据一次性写入。
这个原则仅适用于和 IADs::Put method 相关联的 IADs::SetInfo ,这和 IADs::PutEx method 是不同的。
③问:sAMAccountName这个在这里代表什么?
The IADs::Put method 设置位于ADSI属性缓存中的一个属性值。(为什么说是在缓存中,前面IADS::SetInfo已经提到)
HRESULT Put( BSTR bstrName, VARIANT vProp);
参数bstrName
- [in] Contains a BSTR that specifies the property name. vProp
- [in] Contains a VARIANT that specifies the new values of the property.
返回值
For more information, and other return values, see ADSI Error Codes.
1、调用 IADsContainer.Create 按照指定的位置(cn)在本地缓存中创建用户
2、使用 IADs.Put method 将 sAMAccountName 属性值设定为将要创建用户的用户名
3、调用 IADs.SetInfo 将新的用户提交到服务器数据库
4、接着修改用户的其他属性,比如 userAccountControl。这个约束将也会应用到其他 ADSI 属性,比如 IADsUser.AccountDisabled, 或者ADSI methods ,比如 IADsUser.SetPassword
5、调用 IADs.SetInfo 再次将修改提交到服务器数据库
Const ADS_UF_SCRIPT = &H1Const ADS_UF_ACCOUNTDISABLE = &H2Const ADS_UF_HOMEDIR_REQUIRED = &H8Const ADS_UF_LOCKOUT = &H10Const ADS_UF_PASSWD_NOTREQD = &H20Const ADS_UF_PASSWD_CANT_CHANGE = &H40Const ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = &H80Const ADS_UF_TEMP_DUPLICATE_ACCOUNT = &H100Const ADS_UF_NORMAL_ACCOUNT = &H200Const ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = &H800Const ADS_UF_WORKSTATION_TRUST_ACCOUNT = &H1000Const ADS_UF_SERVER_TRUST_ACCOUNT = &H2000Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000Const ADS_UF_MNS_LOGON_ACCOUNT = &H20000Const ADS_UF_SMARTCARD_REQUIRED = &H40000Const ADS_UF_TRUSTED_FOR_DELEGATION = &H80000Const ADS_UF_NOT_DELEGATED = &H100000Const ADS_UF_USE_DES_KEY_ONLY = &H200000Const ADS_UF_DONT_REQUIRE_PREAUTH = &H400000Const ADS_UF_PASSWORD_EXPIRED = &H800000Const ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = &H1000000Public Sub CreateUser(strName As String, strSAMAccountName As String, strInitialPassword As String)
为后面即将使用的变量定义类型,这是个编程的好习惯 Dim objRootDSE As IADs Dim objUsers As IADsContainer Dim objNewUser As IADsUser
忽略可能出现的错误,错误返回码自行处理 On Error Resume Next 绑定到 rootDSE 对象. Set objRootDSE = GetObject(LDAP://rootDSE)
为了便于debug和监控代码,每一句后都为可能出现的错误给出处理方法,即直接退出子程序。 If (Err.Number <> 0) Then Exit Sub End If 绑定到即将放置新建用户所处目录层次 Set objUsers = GetObject("LDAP://CN=Users," & objRootDSE.Get("defaultNamingContext")) If (Err.Number <> 0) Then Exit Sub End If 创建用户对象 Set objNewUser = objUsers.Create("user", "CN=" + strName) If (Err.Number <> 0) Then Exit Sub End If 设置用户 sAMAccountName 属性 objNewUser.Put "sAMAccountName", strSAMAccountName If (Err.Number <> 0) Then Exit Sub End If 提交新的用户 objNewUser.SetInfo If (Err.Number <> 0) Then Exit Sub End If 设置初始化密码。这个动作必须在 Setinfo 之后,因为用户账户必须已经存在于ad中。 objNewUser.SetPassword strInitialPassword If (Err.Number <> 0) Then Exit Sub End If 设置 pwdLastSet 属性为0,这样做的目的是强制用户下次登陆时更改密码。 objNewUser.Put "pwdLastSet", 0 If (Err.Number <> 0) Then Exit Sub End If 为了启用用户账户,从 userAccountControl 属性中移除 ADS_UF_ACCOUNTDISABLE 标志量。
同样也移除 ADS_UF_PASSWD_NOTREQD 和 ADS_UF_DONT_EXPIRE_PASSWD 标志量
userActCtrl = objNewUser.Get("userAccountControl") userActCtrl = userActCtrl And Not (ADS_UF_ACCOUNTDISABLE +
ADS_UF_PASSWD_NOTREQD + ADS_UF_DONT_EXPIRE_PASSWD)
使用 Put Methon 写入 userAccountControl 属性 objNewUser.Put "userAccountControl", userActCtrl If (Err.Number <> 0) Then Exit Sub End If 提交属性变更 objNewUser.SetInfoEnd Sub