使用ADSI创建虚拟目录
你曾经相通过VBS添加一个虚拟目录吗?(我想过~)自动建立ISAPI服务器扩展?或者建立一整个站点,
包括权限?你可以用ADSI做这些和更多的事情.
ADSI (Active Directory Services Interface)是一种应用程序数据接口.微软的操作系统支持ADS
I的有Windows NT 4.0 Server, Exchange, IIS, 和Site Server.在WIN2K中ADSI将会成为操作系统
的接口并且可能取代注册表.ADSI的关键并不在于底层的数据存储,而在于它自已的接口层.用一个
接口,只要学习一次,你就可以配置所有的服务器程序.(是不是很爽啊,呵呵!)不像API,你可以使用
所有的语言或环境来通过COM访问ADSI.(这是后话!)
警告:
在运行本文章的例子之前,请先备份IIS4.0:
打开MMC
(以下略去备份过程)
面向对象的数据库
ADSI对所有的数据都当作对象来看待.用ADSI你可以熟练地操作所有的数据而不用去学一种数据库
查询语言如SQL.相对于一个关系型的数据库,建立一个面向对象的数据库要简单和快速一些.在一个
关系数据库中程序员不得不要知道一个对象是如何破坏和存储的;然而面向对象的数据存储,像ADSI
,不存在这些问题.程序员只要知道你想要访问的那个对象的名字.
为了去对比这两种数据库类型,设想你要一个员工的资料:个人信息,部门信息,和薪水信息.在一个
关系数据库中,这三个数据可能会被分别放在三个表中.而且对数据库的一个更改可能只会影响到其
中的一部分表,对数据库的修改程序员不得不通过一种数据库查询语言如SQL.很少用人去注意对象
是如何被存储的(除了数据库管理员).然而ADSI把所有的信息视为对象,对象之间的联系正是ADSI执
行的一部分,因此,这一部分就不再需要程序员处理了.一旦你学会了处理一种ADSI数据,你就学会了
处理所有的ADSI数据库.作为一个对比,你可能需要学习每一种关系数据库语言如果你要用不同的数
据库的话.(像FOXPRO)
数据结构
数据库结构是一个分级的模型.一个对象节点可以是另一个节点的父节点,兄弟结点,或者一个子节
点.每一个子节点继承父节点的属性.数据库有两个逻辑部分.第一个是定义数据和数据关联的计划.
第二个部分是数据的实际存储.定义一个员工对象是放在计划部分,个人信息放在数据部分.
获得一个对象的实例
不像COM,你不用去使用SERVER.CREATEOBJECT去获得一个ADSI对象的实例.你只需使用GETOBJECT方
法和一个指定服务器和联接位置的参数.例子一有两个GETOBJECT的例子.在第一种情况下,代码建立
了一个WINDOWS NT的ADSI实例.每二个例子取得了一个IIS的ADSI对象.
Example 1
For Windows NT
Set Object = GetObject("WinNT://15seconds" )
For LDAP
Set Object = GetObject("IIS://localhost/w3svc/1")
一些AD服务接口用一种特别的被称为X.500华贵名称的命名规则.IIS并没有用这种规则但是你必须
对X.500这一个命名规则因为你有可能还要操作其它的ADSI数据.你可以
从ftp://src.doc.ic.ac.uk/rfc/rfc1484.txt 得到相关资料.
数据取回
当我们在一个LDAP服务器上寻找信息时,我们必须知道是否信息在实例中或者在规划部分.举一个例
子来说,一个对象名称可以包含在一个对象实例中但是一个对象属性的列表将会存储在一个计划部
分.员工名称,雇佣日期,和部门被存储在员工对象中.计划部分存储了员工属性的定义像数据类型.
例二说明了一个对象实例和对象计划的定义.
Example 2
Employee Instance
Name: Bob Jones
Hire Date: 1/1/98
Department: Information Technology
Employee Object Instance
Attribute "Name", single value, data-type "text", maxlength 50"
Attribute "Hire Date", single value, data-type "date"
Attribute "Department", single value, data-type "text"
对SQL程序员来说,对象定义和一个表的定义是相似的.对象实例就像是一个表中的特定的一行.SQL
和ADSI的区别就在于数据是不是跨越了多个表,程序员是否需要管理数据之间的关系.在ADSI中,接
口是这些关系的负责人.
默认WEB站点的通有属性
第一个例子可以看到IIS4.0的默认WEB站点的属性.在例3中,代码会联接到本地机的默认WEB站点.
Example 3
<%
strMachineName = "localhost" ''domain name
strObjectPath = "W3SVC/1" ''object name
''construct object location in IIS
strPath = "IIS://" & strMachineName & "/" & strObjectPath
Set IISObject = GetObject (strPath) ''connect to IIS metabase
%>
Name = "<%= IISObject.Name %>"
Parent= "<%= IISObject.Parent %>"
SchemaLocation = "<%= IISObject.Schema %>"
Class = "<%= IISObject.Class %>"
Guid = "<%= IISObject.Guid %>"
ADSPath = "<%= IISObject.AdsPath %>"
输出显示是:
Name = "1"
Parent= "IIS://localhost/W3SVC"
SchemaLocation = "IIS://localhost/schema/IIsWebServer"
Class = "IIsWebServer"
Guid = "{8B645280-7BA4-11CF-B03D-00AA006E0975}"
ADSPath = "IIS://localhost/W3SVC/1"
注意:如果你要在一个ASP页面中运行本程序,请确定登陆的用户被授予了管理员的权限.
在最后一个例子的数据取回可以用于任何一个对象,包括计划对象.每一个对象不管他是一个实在的
对象还是一个计划对象都肯定有这些属性:名称,父,计划定们,CLASS,GUID,和ADS路径.
这些信息包括了通过分级结构访问数据的一些导航信息.NAME属性是一个对象的名称.一个parent属
性告诉了父对象的位置.schemalocation属性指的是计划对象的位置.class属性包括了对象的类型,
它包括了一个对象所有的属性并且被定们到schemalocation这个位置.GUID属性是一个对象的唯一
的识别码.ADSPath是你取回的这个对象的位置.
注:名为1的服务器代表默认的WEB站点
默认WEB站点的属性
既然我们已经知道了对象的位置和对象的类型,那就让我们来看一看默认WEB站点的属性.为了达到
这个目的,我们必须要取得默认WEB站点的计划(schema),找出相关的属性,并且看默认WEB站点的这
些属性的值.
Example 4
<%
strMachineName = "localhost"
strObjectPath = "W3SVC/1" ''find first web server listed in w3svc
strPath = "IIS://" & strMachineName & "/" & strObjectPath
Set IISObject = GetObject (strPath)
''find location of web server''s definition
Set ClassDefinition = GetObject(IISObject.Schema)
%>
<table border=1>
<tr><th>Default Web Server Property</th><th>Default Web Server Value</th></tr>
<tr><td>Name</td><td><%= IISObject.Name %></td></tr>
<tr><td>Parent</td><td><%= IISObject.Parent %></td></tr>
<tr><td>SchemaLocation</td><td><%= IISObject.Schema %></td></tr>
<tr><td>Class</td><td><%= IISObject.Class %></td></tr>
<tr><td>Guid</td><td><%= IISObject.Guid %></td></tr>
<tr><td>ADSPath</td><td><%= IISObject.AdsPath %></td></tr>
</table>
<table border=1>
<tr><th>Class Property</th><th>Class Value</th></tr>
<tr><td>Name</td><td><%= ClassDefinition.Name %></td></tr>
<tr><td>Parent</td><td><%= ClassDefinition.Parent %></td></tr>
<tr><td>SchemaLocation</td><td><%= ClassDefinition.Schema %></td></tr>
<tr><td>Class</td><td><%= ClassDefinition.Class %></td></tr>
<tr><td>Guid</td><td><%= ClassDefinition.Guid %></td></tr>
<tr><td>ADSPath</td><td><%= ClassDefinition.AdsPath %></td></tr>
</table>
<%
on error resume next
asMustHaves = ClassDefinition.MandatoryProperties
asMayHaves = ClassDefinition.OptionalProperties
i=1
%>
<table border=1>
<tr><th>Class Must Have Property</th>
<th>Default Web Site Current Value</th></tr>
<%
For Each Thing in asMustHaves
Response.Write "<tr><td>("& Cstr(i) & ") " &_
Thing & "</td><td>" &_
IISObject.Get(Thing) & "</td></tr>"
i = i + 1
Next
%>
</table>
<table border=1>
<tr><th>Class May Have Property</th>
<th>Default Web Site Current Value</th></tr>
<%
i=1
For Each Thing in asMayHaves
Response.Write "<tr><td>("& CStr(i) & ") " &_
Thing & "</td><td>" &_
IISObject.Get(Thing) & "</td></tr>"
i = i + 1
Next
%>
</table>
为了取得默认WEB站点的属性,你需要知道属性的名称,或者 isWebServer这一类的属性的列表.在例
4中,我们取得了所有的属性并且列出了他们的值.每个对象都可以有强制的和自已的属性.强制的属
性在每个对象建立时就产生了.
注意:如果IISWEBSERVER只列出了一些可选的属性,在参考IIS文档之前请不要建立一个新的WEB站
点的对象。ADSI对IIS的执行打破了这个规则。有一些必须的属性列在了可选的属性列表中。如果
你在建立一个WEB站点时没有对必要的属性进行设置,你的元数据库可能被破坏。
注意:ADSI不会在错误时停下了,它会继续前进。
建立一个虚拟目录
在例五中我们将在默认的WEB站点下建立一个虚拟目录。我们将先列出一个虚拟目录的所有属性然
后再建立一个虚拟目录。为了列出一个目录的所有属性,我借用了例3的一些代码,只不过将站点
改成了虚拟目录,你必须知道必须的属性:我们要建立怎样的WEB服务器,它的名字,它的物理路
径,一旦你建立了一个虚拟目录后你再将它们的属性一一设置。例五讲了怎样利用这些。
Example 5
<%
sComputer ="localhost"
sPhyDir = "c:\adsi"
sVirDir = "ADSITest"
''Get Default Web Site Object
set websvc = GetObject("IIS://" & sComputer & "/W3svc/1")
''Verify by printing out ServerComment
Response.Write "Comment = " & websvc.ServerComment & "
"
''Get root of Default Web Site
set vRoot = websvc.GetObject("IIsWebVirtualDir", "Root")
''Get Class Definition of virtual directory
Set ClassDefinition = GetObject(vRoot.Schema)
''Get list of mandatory properties
asMustHaves = ClassDefinition.MandatoryProperties
''Get list of optional properties
asMayHaves = ClassDefinition.OptionalProperties
i=1
%>
<table border=1>
<tr><th>Class Must Have Property</th>
<th>Root Virtual Directory Current Value</th></tr>
<%
on error resume next
For Each Thing in asMustHaves
Response.Write "<tr><td>("& Cstr(i) & ") " &_
Thing & "</td><td>" & vRoot.Get(Thing) &_
"</td></tr>"
i = i + 1
Next
%>
</table>
<table border=1>
<tr><th>Class May Have Property</th>
<th>Default Web Site Current Value</th></tr>
<%
i=1
For Each Thing in asMayHaves
Response.Write "<tr><td>("& CStr(i) & ") " &_
Thing & "</td><td>" & vRoot.Get(Thing) &_
"</td></tr>"
i = i + 1
Next
on error goto 0
''Create Virtual Directory
''Param 1 is class name
''Param 2 is the new object name
Set vDir = vRoot.Create("IIsWebVirtualDir",sVirDir)
''Only setting two properties
vDir.AccessRead = true
vDir.Path = sPhyDir
''Write information back to Metabase
vDir.SetInfo
%>
在这个例子中,为了建立一个对象的实例,父对象被用到了。建立对像的实例用的是对象的class
名称。而这个对象没有强制的属性,一些对象有强制的属性。如果你没有设置这些必要的属性,当
你使用object.setinfo时就会出错。
为了检验这个虚拟目录是否已经建立了,你可以打开IIS看一下。另一个方法是再运行一遍程序,
如果上次已经建立了,你这次就会得到错误结果。(推荐前一种,SUNWEN)
别一个ADSI的特征是在OBJECT。SETINFO被运行之前,所有的属性设置都不会生效。这使你的站点
不会受一些非正规的影响(如果一个人正在请求这个站点的话,就会出现错误)。这比一个关系型
的数据库更加简单。ADSI会自动完成所有相关的数据的设置,你就可以不用使用N次的INSERT语句
(嘻嘻,老外和SUNWEN一样幽默!)。更新也一样。你只需一次则可。
加入一个默认的文档
在这个例子中,我们将把"index.htm"这个文件加入到默认文档的列表中。为了实现这一目标,我
们要从数据源中得到这个虚拟目录,改变与默认文档相关的属性,然后把信息写回去。
Example 6
<%
sComputer ="localhost"
sPhyDir = "c:\dina\adsi"
sVirDir = "ADSITest"
''Get Default Web Site Object
set websvc = GetObject("IIS://" & sComputer & "/W3svc/1")
''Verify by printing out ServerComment
Response.Write "Comment = " & websvc.ServerComment & "
"
''Get root of Default Web Site
set vRoot = websvc.GetObject("IIsWebVirtualDir", "Root")
''Create Virtual Directory
Set vDir = vRoot.Create("IIsWebVirtualDir",sVirDir)
''Get local copy of object
vDir.GetInfo
Response.Write "Old Default Docs = " & vDir.DefaultDoc & "<BR>"
''Only setting two properties
vDir.DefaultDoc = vDir.DefaultDoc & ",index.htm"
''Write information back to Metabase
vDir.SetInfo
''Get Object Again
vDir.GetInfo
Response.Write "New Default Docs = " & vDir.DefaultDoc
%>
在这个例子中,我们是用了objec.getinfo这个语句把信息取回的。它一次性把所有的信息都取回
了。然后我们用setinfo这个语句把信息重新设置了回去。
删除一个虚拟目录
在这个例子中,你将学习到如何删除一个虚拟目录。当建立一个对象时,你必须有它的父对象。这
个真理也同样适用于删除。例七表明了如何做。
Example 7
<%
on error resume next
sComputer ="localhost"
sPhyDir = "c:\dina\adsi"
sVirDir = "ADSITest"
''Get Default Web Site Object
set websvc = GetObject("IIS://" & sComputer & "/W3svc/1")
''Verify by printing out ServerComment
Response.Write "Comment = " & websvc.ServerComment & "
"
''Get root of Default Web Site
set vRoot = websvc.GetObject("IIsWebVirtualDir", "Root")
''Delete Virtual Directory
Set vDir = vRoot.Delete("IIsWebVirtualDir",sVirDir)
%>