One of the most valuable features in ADSI's IIS support is the ability to programmatically create, delete, and manage WWW, FTP, Simple Mail Transport Protocol (SMTP), and Network News Transfer Protocol (NNTP) sites.
Whereas most enterprises create a home directory for every account in the enterprise, tomorrow's users may also each have a virtual directory to share their information via the user -friendly Web interface that has become familiar to everyone. Without a programmatic method for performing such tasks , this could be an unbearable administrative burden on those charged with managing such environments.
The following sections explore the enumeration, creation, and manipulation of IIS sites for the WWW and FTP services.
Before you can begin manipulating a site, you must first learn what sites are defined for a particular server. To do this, use the enumeration function shown earlier in the chapter (in the section "Examining the Structure of the IIS Metabase Using Visual Basic") with a slight modification to the binding string, as shown in the following Visual Basic code:
Dim Parent As IADs Dim Child As IADs Dim ServerName As String Dim RetVal as String ServerName = " IIS_Server_Name " Set Parent = GetObject("IIS://" & ServerName & "/W3SVC") For Each Child In Parent If IsNumeric(Child.Name) then RetVal = Child.Name Debug.Print RetVal End If Next
After running this code segment, you quickly notice that the names of the sites on the machine do not appear using their friendly names as they do in the Internet Service Manager. Instead, you see Filters , Info , and then a series of integers. The integers represent the programmatic IDs for the sites on the server. Whereas machines may be able to easily cope with integers, human beings tend to prefer more friendly identifiers, forcing us to account for this in our code.
To show the results of the enumeration to the user, use the IIsWebServer ServerComments property to display the friendly name associated with the site as follows :
Dim Parent As IADs Dim Child As IADs Dim ServerName As String ServerName = " IIS_Server_Name " Set Parent = GetObject("IIS://" & ServerName & "/W3SVC") For Each Child In Parent If IsNumeric(Child.Name) then Debug.Print "ProgrammaticID: " & Child.Name & vbTab & "Friendly Name: " & Child.ServerComment End If Next
Note
The friendly name cannot be used to identify the object programmatically ”it is merely a property, as the user profile path is for a user object. In fact, you can create two sites with exactly the same friendly name.
Use the following Visual Basic code to display the integer value and the value of each associated ServerComment property value for each site defined in the Metabase:
Dim Parent As IADs Dim Child As IADs Dim ServerName As String ServerName = "IIS_Server_Name" Set Parent = GetObject("IIS://" & ServerName & "/MSFTPSVC") For Each Child In Parent If IsNumeric(Child.Name) Then Debug.Print Child.Name & vbTab & " - " & vbTab & Child.ServerComment End If Next
Tip
Notice that the code for the Web and FTP services is nearly identical, with the exception being the name of the container specified by the binding string. Simply changing the container will perform similar functionality for each of the IIS services (W3SVC, MSFTPSVC, NNTPSVC, and SmtpSvc).
If you want to apply the code in this section to the SMTP or NNTP services, begin by changing the binding string to reflect the proper IIS service.
Sites are generally known by name and not by index number, leaving the user in a difficult situation when trying to manipulate a site. To alleviate this issue, use the following Visual Basic code to return the index value for a site given an existing ServerComment :
Dim Sites As IADs Dim Site As IADs Dim SearchTerm As String Dim Counter As Integer Dim IndexValue As Long Dim ServerName as String SearchTerm = "Site_Description_String" ServerName = "IIS_Server_Name" Counter = 0 Set Sites = GetObject("IIS:\" & ServerName & "\w3svc") For Each Site In Sites If IsNumeric(Site.Name) Then If LCase(Site.ServerComment) = LCase(SearchTerm) Then Counter = Counter + 1 IndexValue = Site.Name End If End If Next Select Case Counter Case 0 Debug.Print "The referenced site could not be found. Please enter a new search term." Case 1 Debug.Print "The index value for site '" & SearchTerm & "' is " & IndexValue Case Is > 1 Debug.Print "More than one site uses the value '" & SearchTerm & "' for the &" _ ; "ServerComments property. Assure all values are unique before continuing." End Select
Another advantage to programmatic IIS administration is the ability to have developers create a site installation script that quickly and easily creates the site, sets all required security and configuration settings, and even starts the new site. This can be especially useful when implementing a new site across multiple nodes in a front-end Web server cluster, or when developers want to ease the burden placed on the administrative staff when bringing up new sites.
It all starts with the creation of a new site. In the previous section, you learned that sites are not defined by friendly names (as they are in the Internet Service Manager), but rather by an index number.
Consider the following Visual Basic code, which allows you to create a new site (virtual Web server) in IIS:
On Error Resume Next Dim Parent As IADsContainer Dim Child As IADs Dim NewSite As IADs Dim NewRoot As IADs Dim ServerName As String Dim Index As Long Dim SiteName As String Dim SitePath As String SiteName = "Friendly_Site_Name" ServerName = "IIS_Server_Name" SitePath = "Site_Path" Set Parent = GetObject("IIS://" & ServerName & "/W3SVC") For Each Child In Parent If IsNumeric(Child.Name) Then If Index < Child.Name Then Index = Child.Name End If End If Next Index = Index + 1 Set NewSite = Parent.Create("IIsWebServer", Index) NewSite.ServerComment = SiteName NewSite.SetInfo Set NewRoot = NewSite.Create("IIsWebVirtualDir", "Root") NewRoot.Path = SitePath NewRoot.SetInfo
Using the preceding code example, you can create a site and root virtual directory pointing to a specific directory.
Tip
Although this works well for basic configurations, you typically want to install more than one site per IP address. This is best accomplished using host headers or an alternate TCP port. To add a new host header or alternate TCP port, you must manipulate the ServerBindings property of the bound site.
Property manipulation is covered in detail for each of the IIS Web and FTP services in Chapter 9 "Programmatic Management of Web Site Properties," and Chapter 10 "Programmatic Management of FTP Site Properties," respectively.
In the following Visual Basic code example, you can specify an alternate IP address and TCP port by removing the comment designator (apostrophe) and assigning a valid and unique IP address and TCP port pairing for the site.
To allow the site to be bound to any unassigned IP address, simply set the IP address to an empty string.
Dim Parent As IADsContainer Dim Child As IADs Dim NewSite As IADs Dim NewRoot As IADs Dim ServerName As String Dim Index As Long Dim SiteName As String Dim SitePath As String Dim SiteIPAddress as String Dim SiteTCPPort As Long SiteName = "Friendly_Site_Name" ServerName = "IIS_Server_Name" SitePath = "Site_Path" SiteIPAddress = " SiteTCPPort = "21" 'SiteIPAddress = "xxx.xxx.xxx.xxx" 'SiteTCPPort = "TCP_Port_for_Server" Set Parent = GetObject("IIS://" & ServerName & "/MSFTPSVC") For Each Child In Parent If IsNumeric(Child.Name) Then If Index < Child.Name Then Index = Child.Name End If End If Next Index = Index + 1 Set NewSite = Parent.Create("IIsFTPServer", Index) NewSite.ServerComment = SiteName NewSite.ServerBindings = Array(SiteIPAddress & ":" & SiteTCPPort & ":") NewSite.SetInfo Set NewRoot = NewSite.Create("IIsFTPVirtualDir", "Root") NewRoot.Path = SitePath NewRoot.SetInfo
When deleting a site, you do not want to make a mistake as to which one you really meant to delete. In a non-clustered production environment, deleting the wrong site could be a real career-limiting move.
One of the most frustrating parts of programmatic IIS administration is dealing with the index number rather than the friendly name of the site. Although you can create multiple sites with identical names in the Internet Service Manager, this truly defies logic and good administrative practice. Even if you decide to take such an approach, remember that besides looking at content, there is no way to determine one site from another.
Assuming you have unique ServerComment properties for each site on the server, you can combine the site enumeration function (described earlier in the section "Viewing the List of Current Server-Defined MIME Type Mappings Using Visual Basic") with a conditional that tests the ServerComment property for a known string. This allows you to use the ServerComment field as an identifier for managing the site.
You can use the following Visual Basic code to pass in this friendly name, find out the corresponding index number of the site, and delete the site from the Metabase:
Dim Sites As IADs Dim Site As IADs Dim SearchTerm As String Dim Counter As Integer Dim IndexValue As Long Dim ServerName as String SearchTerm = "Site_Description_String" ServerName = "IIS_Server_Name" Counter = 0 Set Sites = GetObject("IIS:\" & ServerName & "\w3svc") For Each Site In Sites If IsNumeric(Site.Name) Then If LCase(Site.ServerComment) = LCase(SearchTerm) Then Counter = Counter + 1 IndexValue = Site.Name End If End If Next Select Case Counter Case 0 Debug.Print "The referenced site could not be found. Please enter a new search term." Case 1 Call Sites.Delete("IIsWebServer", IndexValue) Set Sites = Nothing Debug.Print "Site '" & SearchTerm & "' was deleted successfully." Case Is > 1 Debug.Print "More than one site uses the value '" & SearchTerm & "' for the " _ ; "ServerComments property. Assure all values are unique before continuing." End Select
This code verifies the uniqueness of the ServerComment property value before performing the deletion. This eliminates any ambiguity and keeps you from having to update your resume if you happen to miss correcting a non-unique ServerComment property assignment in a production environment.
Warning
If you choose to use the ServerComment field as an identifier for sites, be sure to verify that all sites on the server maintain unique values for the ServerComment field.
By simply changing the binding string, you can programmatically delete an FTP site. Use the following Visual Basic code to perform this task:
Dim Sites As IADs Dim Site As IADs Dim SearchTerm As String Dim Counter As Integer Dim IndexValue As Long Dim ServerName As String SearchTerm = "Site_Description_String" ServerName = "IIS_Server_Name" Counter = 0 Set Sites = GetObject("IIS:\" & ServerName & "\MSFTPSVC") For Each Site In Sites If IsNumeric(Site.Name) Then If LCase(Site.ServerComment) = LCase(SearchTerm) Then Counter = Counter + 1 IndexValue = Site.Name End If End If Next Select Case Counter Case 0 Debug.Print "The referenced site could not be found. Please enter a new search term." Case 1 Call Sites.Delete("IIsFTPServer", IndexValue) Set Sites = Nothing Debug.Print "Site '" & SearchTerm & "' was deleted successfully." Case Is > 1 Debug.Print "More than one site uses the value '" & SearchTerm & "' for the " & ServerComments &_ " property. Assure all values are unique before continuing." End Select
When creating a new site, you must create a root virtual directory to assign to the site's Path property. If this step is ignored, the site will be unmanageable in the MMC or through programmatic methods until the Path property is set to a valid path.
In addition to the root virtual directory, a site can also contain virtual directories that can be accessed by the client at http://sitename/virtual_directory . These directories can exist anywhere in the file system and need not be a child path of the root virtual directory path. Unlike virtual sites, virtual directories use a friendly name for their programmatic identifier in the binding string.
Use the following Visual Basic code to create a new virtual directory under the default Web site:
Dim Parent as IADs Dim NewVDir As IADs Dim ServerName As String Dim VDirPath As String Dim VDirName As String Dim Index As Long ServerName = "IIS_Server_Name" VDirPath = "Path_for_New_Virtual_Directory" VDirName = "Name_For_Virtual_Directory" Index = Site_Index_Integer Set Parent = GetObject("IIS://" & ServerName & "/W3SVC/" & Index & "/ROOT") Set NewVDir = Parent.Create("IIsWebVirtualDir", VDirName) NewVDir.SetInfo NewVDir.Path = VDirPath NewVDir.SetInfo
Using the following Visual Basic code, you can quickly and easily implement a new virtual directory to organize your FTP site in a more logical fashion:
Dim Parent As IADs Dim NewVDir As IADs Dim ServerName As String Dim VDirPath As String Dim VDirName As String Dim Index As Long ServerName = "IIS_Server_Name" VDirPath = "Path_for_New_Virtual_Directory" VDirName = "Name_For_Virtual_Directory" Index = Site_Index_Integer Set Parent = GetObject("IIS://" & ServerName & "/MSFTPSVC/" & Index & "/ROOT") Set NewVDir = Parent.Create("IIsFTPVirtualDir", VDirName) NewVDir.SetInfo NewVDir.Path = VDirPath NewVDir.SetInfo
There may be occasions when you require a technique to perform the deletion of an existing virtual directory. To accomplish this task, simply use the IADsContainer Delete method to remove the entry in the Metabase for the virtual directory.
Consider the following Visual Basic code to remove an existing virtual directory:
Dim Parent As IADsContainer Dim ServerName As String Dim VDirName As String Dim Index As Long ServerName = "IIS_Server_Name" VDirName = "Name_For_Virtual_Directory Index = Site_Index_Value Set Parent = GetObject("IIS://" & ServerName & "/W3SVC/" & Index & "/ROOT") Call Parent.Delete("IIsWebVirtualDir", VDirName) Set Parent = Nothing
With a simple change to the binding string, existing virtual directories on FTP sites can be removed.
Use the following Visual Basic code as a guide for removing an existing virtual directory from an FTP site:
Dim Parent As IADsContainer Dim ServerName As String Dim VDirName As String Dim Index As Long ServerName = "IIS_Server_Name" VDirName = "Name_For_Virtual_Directory Index = Site_Index_Value Set Parent = GetObject("IIS://" & ServerName & "/MSFTPSVC/" & Index & "/ROOT") Call Parent.Delete("IIsFTPVirtualDir", VDirName)
Unlike a virtual directory entry, folders and files in the file system will not automatically synchronize with the Metabase. To bind to a directory that exists in the file system underneath a Web site's virtual directory, you must first create an entry in the Metabase. Although this may seem like a terrific amount of effort, keep in mind that the IIS Metabase hierarchy supports inheritance. This allows you to define a set of properties at a higher level (such as a virtual directory or file system directory) and have the property trickle down to all child nodes in the tree. Consequently, you must define an entry in the Metabase only for each departure from the inherited property values.
Most directory service designers try to derive designs that minimize the need to block inheritance as much as possible. Armed with this knowledge, you should try to persuade the Web developers in your organization to design the physical directory structure using a flat structure where possible to reduce the need to change inherited properties for each directory on the site. By creating an entry in the Metabase for each directory or file requiring a unique permission or property assignment, you can bind and manage the properties for the resource.
Although the Internet Service Manager shows Web file and folder entries and allows manipulation of the properties for all of these entities, an entry is not made into the Metabase unless there is a change in the inherited configuration for the entity.
To see what is actually being stored in the Metabase, use the following Visual Basic code to enumerate the entities under a virtual directory:
Dim VirtualDirectory As IADs Dim ServerName As String Dim Index As Long ServerName = "IIS_Server_Name" Index = Site_Index_Value Set VirtualDirectory = GetObject("IIS://" & ServerName & "/W3SVC/" & Index & "/ROOT") For Each Item In VirtualDirectory Debug.Print Item.Name Next
Note
This code will display all the entries in the default Web site's root virtual directory. If you compare the results found in the ISM and those in the immediate window, you quickly see the disparity. If you were to attempt to bind to default.asp and it did not have an entry in the Metabase, the operation would fail. To account for this, you must place entries in the Metabase for file system objects that should maintain different properties from those inherited from the parent object.
By enumerating the contents of the parent container, you now see that there is an entry for the file system directory specified.
Use the following Visual Basic code to define a change in the inherited properties for a Web directory:
Dim VirtualDirectory As IADs Dim WebDir As IADs Dim ServerName As String Dim FileName As String Dim Index As Long Dim VirtualDirectoryName As String ServerName = "IIS_Server_Name" DirName = "Directory_Name_To_Enter" Index = Site_Index Set VirtualDirectory = GetObject("IIS://" & ServerName & "/W3SVC/" & Index & "/ROOT") Set WebDir = VirtualDirectory.Create("IIsWebDirectory", DirName) WebDir.SetInfo
In addition to specifying unique properties for an entire virtual directory or Web directory, there may also be times when you desire the ability to set a unique property at the file level.
Use the following Visual Basic code to add a new entry in the Metabase for an individual Web file in the file system:
Dim VirtualDirectory As IADs Dim WebFile As IADs Dim ServerName As String Dim FileName As String Dim Index As Long Dim VirtualDirectoryName As String ServerName = "IIS_Server_Name" FileName = "File_Name_To_Enter" Index = Site_Index Set VirtualDirectory = GetObject("IIS://" & ServerName & "/W3SVC/" & Index & "/ROOT") Set WebFile = VirtualDirectory.Create("IIsWebFile", FileName) WebFile.SetInfo
Note
If you were to enumerate the virtual directory contents after adding entries for individual directories or files, you would see that an entry was made for the file you just referenced. This enables you to bind and manipulate the file just as any other object in the namespace.
Top |