Previous Section Table of Contents Next Section

Administering IIS

Suppose you want to make it easy for junior administrators to create new virtual directories under IIS. You need a tool that will create the virtual directory, and automatically assign the designated Web developer as the owner of the new directory. This would be a great tool in a Web development shop, and can save a lot of mouse clicking. Suppose you also want to make sure that only members of a special Web Operators group on the Web server can use the page.

NOTE

This code is adapted in part from the IIS Admin Web site included with IIS 4.0 and 5.0. That site and its source are great examples of how to use the IIS administration object, which is utilized within this script.


Designing the Page

As usual, I start with FrontPage to make the basic HTML. In this case, it's pretty simple, and it's shown in Listing 24.4.

Listing 24.4. IIS.htm. Static HTML for the IIS administration page.

<HTML>

<BODY>

<CENTER>

 <FORM ACTION="iis.asp" METHOD="POST">

  <INPUT type="text" name="VirtualDir">

  <SELECT size=1 name="Developer">

   <OPTION VALUE="test">TEST</OPTION>

  </SELECT>

  <INPUT type="checkbox" name="AllowScript">

  <INPUT type="submit" value="Submit" name="Submit">

 </FORM>

</CENTER>

</BODY>

</HTML>

Not much to it. The only placeholder information is the TEST option in the drop-down list box; I'll want to populate the list with the members of the Web Developers group.

For a script this complex, I also want to lay out the tasks that I need to accomplish.

  • Create an IIS virtual directory.

  • Set properties on a virtual directory.

  • Create a physical file folder.

  • Set permissions on a physical file folder.

  • Check to make sure the user logged on.

  • Check to make sure the user is in the Web Operators group.

  • Get a membership list from a local computer group.

You should know how to do all but the first two. Excuse me? You don't know how to set permissions on a folder from within a script? Sure, you do-you just have to be creative. You've probably used, or at least heard of, Cacls.exe, Microsoft's command-line utility for setting NTFS permissions. I'll just use that within my script. Yes, I could use WMI, but working with permissions from within WMI is insanely complicated. I'm not after an "elegant" script, I'm out to get a job done as quickly as possible. Therefore, Cacls.exe it is.

TIP

When you don't know how to do something in script, be creative! If you have free time later-and who does?-you can always use a "prettier" method, but when there's work to be done, just do it in whatever way you know how. If it works, it isn't wrong.


Writing Functions and Subroutines

I've identified several tasks that can be broken up into functions or subroutines. These include creating the IIS virtual directory, creating the physical folder on the hard drive, and a couple of others. Listing 24.5 has the list of functions and subs.

Listing 24.5. IISFandS.vbs. These functions and subs will be called from the main script.

Function IISDirExists(sVirtualDir)



 On Error Resume Next

 Dim bExists



 'create an IIS admin object

 'assumes Default Web Site

 Set oIISAdmin = GetObject("IIS://localhost/W3SVC/1/Root/"

  & sVirtualDir)



 'if there's no error, the dir exists

 'display message and end

 If Err.Number = 0 Then

  bExists = True

 Else

  bExists = False

 End If



 'release IIS admin object

 Set oIISAdmin = Nothing



 IISDirExists = bExists



End Function



Function CreateFolder(sVirtualDir)



 'get another admin object first

 Set oIISAdmin = GetObject("IIS://localhost/W3SVC/1/Root")

 sVDirPath  = oIISAdmin.Path & "\" & sVirtualDir



 'get a filesystemobject

 Set oFSO = Server.CreateObject("Scripting.FileSystemObject")



 'create the folder on disk if it

 'doesn't exist already

 If Not oFSO.FolderExists(sVDirPath) Then

    oFSO.CreateFolder sVDirPath

 End If



 'release the filesystemobject

 Set oFSO = Nothing



 'return the path to the folder

 CreateFolder = sVDirPath



End Sub



Sub CreateIISVDir(sVirtualDir, bAllowScript, sVDirPath, _

 bInProcess)



 Set oVirtualDir = oIISAdmin.Create("IISWebVirtualDir",

   sVirtualDir)

 oVirtualDir.AccessScript = bAllowScript

 oVirtualDir.Path = sVDirPath

 oVirtualDir.SetInfo

 oVirtualDir.AppCreate bInprocess



End Sub



Sub CheckAuth()



 If Request.ServerVariables("LOGON_USER") = "" Then

  Response.Status = "401 Authorization Required"

  Response.End

 End If



End Sub

These probably deserve some explanation. I'll start with IISDirExists(), which checks to see if a virtual directory with a specified name already exists in IIS' Default Web Site.


Function IISDirExists(sVirtualDir)



 On Error Resume Next

 Dim bExists



 'create an IIS admin object

 'assumes Default Web Site

 Set oIISAdmin = GetObject("IIS://localhost/W3SVC/1/Root/"

  & sVirtualDir)



 'if there's no error, the dir exists

 'display message and end

 If Err.Number = 0 Then

  bExists = True

 Else

  bExists = False

 End If



 'release IIS admin object

 Set oIISAdmin = Nothing



 IISDirExists = bExists



End Function

This function uses the IIS Administration object. Notice that it works a lot like ADSI: You connect to it using the IIS: provider, specify the server name ("localhost"), the service ("W3SVC"), the instance ("1" is the Default Web Site), and then specify "Root" to connect to the root level. Finally, I tacked on the name of the virtual directory I'm checking on. This call to GetObject fails if the virtual directory doesn't exist, so I issue On Error Resume Next to start with. If the call does fail, I catch it with the If Err.Number = 0 statement. Here's how it works.

  • If there's no error, the directory exists, and I set bExists to True.

  • If there's an error, the directory doesn't exist, so I set bExists to False.

Finally, I release the Administration object and return my result.

The next function creates a new physical file folder. It accepts the name of the virtual directory, though, and uses an IIS admin object to figure out the correct physical file path. This ensures that the new folder will be created under the Default Web Site's physical root folder (usually C:\Inetpub\Wwwroot).


Function CreateFolder(sVirtualDir)



 'get another admin object first

 Set oIISAdmin = GetObject("IIS://localhost/W3SVC/1/Root")

 sVDirPath  = oIISAdmin.Path & "\" & sVirtualDir



 'get a filesystemobject

 Set oFSO = Server.CreateObject("Scripting.FileSystemObject")



 'create the folder on disk if it

 'doesn't exist already

 If Not oFSO.FolderExists(sVDirPath) Then

    oFSO.CreateFolder sVDirPath

 End If



 'release the filesystemobject

 Set oFSO = Nothing



 'return the path to the folder

 CreateFolder = sVDirPath



End Sub

At the completion of this function, I return the full path of the new folder. I'll use that information again in the next routine, which is a sub. This routine creates the IIS virtual directory and sets its scripting permissions property, its physical path, and its status as an in-process IIS application.


Sub CreateIISVDir(sVirtualDir, bAllowScript, sVDirPath, _



 bInProcess)



 Set oVirtualDir = oIISAdmin.Create("IISWebVirtualDir",

   sVirtualDir)

 oVirtualDir.AccessScript = bAllowScript

 oVirtualDir.Path = sVDirPath

 oVirtualDir.SetInfo

 oVirtualDir.AppCreate bInprocess



End Sub

I need one more sub. This one just checks to make sure the current user authenticated and has a user name; if he doesn't, I set Response.Status equal to the "Authorization Required" error message and end the script.


Sub CheckAuth()



 If Request.ServerVariables("LOGON_USER") = "" Then

  Response.Status = "401 Authorization Required"

  Response.End

 End If



End Sub

That's the bulk of the script's heavy lifting. There are a couple of other tasks I'll write in the main script, mainly because they require a lot of input parameters and aren't worth writing as a separate function or sub.

Writing the Main Script

Time to add the main script. I still need to populate that drop-down list with members of the Web Developers group, run CACLS, and make sure the current user belongs to the Web Operators group.

graphics/arrow.gif IIS Administration

Listing 24.6 shows the full, complete Web page code.

Listing 24.6. IIS.asp. You'll need to make some changes to get this working in your environment.

<%



Function IISDirExists(sVirtualDir)



 On Error Resume Next

 Dim bExists



 'create an IIS admin object

 'assumes Default Web Site

 Set oIISAdmin = GetObject("IIS://localhost/W3SVC/1/Root/"

  & sVirtualDir)



 'if there's no error, then the dir exists

 'display message and end

 If Err.Number = 0 Then

  bExists = True

 Else

  bExists = False

 End If



 'release IIS admin object

 Set oIISAdmin = Nothing



 IISDirExists = bExists



End Function



Function CreateFolder(sVirtualDir)



 'get another admin object first

 Set oIISAdmin = GetObject("IIS://localhost/W3SVC/1/Root")

 sVDirPath  = oIISAdmin.Path & "\" & sVirtualDir



 'get a filesystemobject

 Set oFSO = Server.CreateObject("Scripting.FileSystemObject")



 'create the folder on disk if it

 'doesn't exist already

 If Not oFSO.FolderExists(sVDirPath) Then

    oFSO.CreateFolder sVDirPath

 End If



 'release the filesystemobject

 Set oFSO = Nothing



 'return the path to the folder

 CreateFolder = sVDirPath



End Sub



Sub CreateIISVDir(sVirtualDir, bAllowScript, sVDirPath, _

 bInProcess)



 Set oVirtualDir = oIISAdmin.Create("IISWebVirtualDir",

   sVirtualDir)

 oVirtualDir.AccessScript = bAllowScript

 oVirtualDir.Path = sVDirPath

 oVirtualDir.SetInfo

 oVirtualDir.AppCreate bInprocess



End Sub



Sub CheckAuth()



 If Request.ServerVariables("LOGON_USER") = "" Then

  Response.Status = "401 Authorization Required"

  Response.End

 End If



End Sub



'Ensure authentication occurs

CheckAuth



'handle submitted form

If Request("Submit") <> "" Then



 Dim sVirtualDir, bInprocess

 Dim oIISAdmin, sVDirPath

 Dim oFSO, sDeveloper

 Dim oVirtualDir, bAllowScript

 Dim sServer, oWSH

 Dim oReturnCode, sCmdLine



 'get submitted information

 sVirtualDir = Request.Form("VirtualDir")

 sDeveloper = Request.Form("Developer")



 If Request.Form("AllowScript") = "on" Then

  bAllowScript = "True"

 Else

  bAllowScript = "False"

 End If



 'see if virt dir exists already

 If IISDirExists(sVirtualDir) = True Then

  Response.Write "That directory exists."

  Response.End

 End If



 'Create the directory in the file system

 sVDirPath = CreateFolder(sVirtualDir)



 'Create the folder in IIS

 CreateIISVDir(sVirtualDir, bAllowScript, sVDirPath, bInProcess)



 'build a command line for CACLS

 sCmdLine = "cmd /c echo y| CACLS "

 sCmdLine = sCmdLine & sVDirPath

 sCmdLine = sCmdLine & " /g "

   & sDeveloper & ":C"



 'create a WSH shell object

 Set oWSH = Server.CreateObject("WScript.Shell")



 'execute CACLS

 oReturnCode = oWSH.Run (sCmdLine , 0, True)



 'release the shell object

 Set oWSH = Nothing



 'report

 Response.Write("Done.")

 Response.End



End If





%>

<HTML>

<BODY>

<%

Dim sUserADSI, oMachine

Dim oMember, oGroup

Dim sADSI, bLoggedOn

Dim sMember



'get current user

sUserADSI = "WinNT://BRAINCORE/" & _

 Request.ServerVariables("LOGON_USER")



'change backslashes to slashes for ADSI

sUserADSI = Replace(sUserADSI, "\", "/")



'get the group

Set oGroup = GetObject("WinNT://DON-TABLET/Web Operators,group")



'is the user a member?

For Each oMember in oGroup.Members

 If LCase(oMember.ADsPath) = LCase(sUserADSI) Then

  bLoggedOn = True

  Exit for

 End If

Next



Set oGroup = Nothing

If bLoggedOn = True Then

%><CENTER>

 <FORM ACTION="iis.asp" METHOD="POST">

  <INPUT type="text" name="VirtualDir">

  <SELECT size=1 name="Developer">

<%



'make a list of Web Developers members

Set oGroup = _

 GetObject("WinNT://don-tablet/Web Developers,group")



For Each oMember in oGroup.Members

 sMember = Replace(oMember.ADsPath, "/", "\")

 sMember = Mid(sMember, 9, Len(sMember))

 Response.Write "<OPTION VALUE=" & sMember & ">"

 Response.Write sMember

 Response.Write "</OPTION>"

Next

Set oGroup = Nothing

%>

  </SELECT>

  <INPUT type="checkbox" name="AllowScript">

  <INPUT type="submit" value="Submit" name="Submit">

 </FORM>

</CENTER>

<%

Else

%>Your user account:

 <% Response.Write sUserADSI %>

 does not have access to this page.

 <%

End If

%>

</BODY>

</HTML>

You need to make a number of changes to get this to work.

  • Change "don-tablet" to the name of the local Web server.

  • Change "BRAINCORE" to the name of the domain or workgroup that the Web server belongs to.

  • Make sure the "Web Operators" and "Web Developers" user groups all exist.

  • Make sure the Default Web Site exists in IIS.

graphics/arrow.gif IIS Administration-Explained

This page starts with the functions and subs I outlined earlier.


<%



Function IISDirExists(sVirtualDir)



 On Error Resume Next

 Dim bExists



 'create an IIS admin object

 'assumes Default Web Site

 Set oIISAdmin = GetObject("IIS://localhost/W3SVC/1/Root/"

  & sVirtualDir)



 'if there's no error, then the dir exists

 'display message and end

 If Err.Number = 0 Then

  bExists = True

 Else

  bExists = False

 End If



 'release IIS admin object

 Set oIISAdmin = Nothing



 IISDirExists = bExists



End Function



Function CreateFolder(sVirtualDir)



 'get another admin object first

 Set oIISAdmin = GetObject("IIS://localhost/W3SVC/1/Root")

 sVDirPath  = oIISAdmin.Path & "\" & sVirtualDir



 'get a filesystemobject

 Set oFSO = Server.CreateObject("Scripting.FileSystemObject")



 'create the folder on disk if it

 'doesn't exist already

 If Not oFSO.FolderExists(sVDirPath) Then

    oFSO.CreateFolder sVDirPath

 End If



 'release the filesystemobject

 Set oFSO = Nothing



 'return the path to the folder

 CreateFolder = sVDirPath



End Sub



Sub CreateIISVDir(sVirtualDir, bAllowScript, sVDirPath, _

 bInProcess)



 Set oVirtualDir = oIISAdmin.Create("IISWebVirtualDir",

   sVirtualDir)

 oVirtualDir.AccessScript = bAllowScript

 oVirtualDir.Path = sVDirPath

 oVirtualDir.SetInfo

 oVirtualDir.AppCreate bInprocess



End Sub



Sub CheckAuth()



 If Request.ServerVariables("LOGON_USER") = "" Then

  Response.Status = "401 Authorization Required"

  Response.End

 End If



End Sub

Next, I call the CheckAuth routine. This ensures that the user has authenticated; if he hasn't, the sub takes care of sending an appropriate error message and ending the script.


'Ensure authentication occurs

CheckAuth

Now, I need to see if the form has been submitted. For now, let's assume it has been, so the following code will evaluate to a True logical condition.


'handle submitted form

If Request("Submit") <> "" Then

I'll dimension some variables, and then pull information from the Request object into variables. Pulling the information into variables just makes it easier to work with, so I don't have to keep retyping Request("VirtualDir") and so forth.


Dim sVirtualDir, bInprocess

Dim oIISAdmin, sVDirPath

Dim oFSO, sDeveloper

Dim oVirtualDir, bAllowScript

Dim sServer, oWSH

Dim oReturnCode, sCmdLine



'get submitted information

sVirtualDir = Request.Form("VirtualDir")

sDeveloper = Request.Form("Developer")



If Request.Form("AllowScript") = "on" Then

 bAllowScript = "True"

Else

 bAllowScript = "False"

End If

Now, use the IISDirExists() function to see if the specified virtual directory already exists. If it does, write an error message and end the script.


'see if virt dir exists already

If IISDirExists(sVirtualDir) = True Then

 Response.Write "That directory exists."

 Response.End

End If

If you've made it this far, you know the directory doesn't already exist in IIS. Call the routine to create the folder in the file system. Note that this function actually checks to see if the folder exists, and only tries to create it if it doesn't exist.


'Create the directory in the file system

sVDirPath = CreateFolder(sVirtualDir)

Because the physical folder exists, the virtual directory can be created in IIS.


'Create the folder in IIS

CreateIISVDir(sVirtualDir, bAllowScript, sVDirPath, bInProcess)

Next, assemble a command-line string to execute CACLS. This makes the designated developer the owner of the physical folder, so that he or she can manipulate the files in the folder.


'build a command line for CACLS

sCmdLine = "cmd /c echo y| CACLS "

sCmdLine = sCmdLine & sVDirPath

sCmdLine = sCmdLine & " /g "

  & sDeveloper & ":C"

To launch the command line, you need a reference to the Windows Script Host's Shell object.


'create a WSH shell object

Set oWSH = Server.CreateObject("WScript.Shell")

Use the Shell object to execute CACLS.


'execute CACLS

oReturnCode = oWSH.Run (sCmdLine , 0, True)

Finish the script and write a completion message.


'release the shell object

Set oWSH = Nothing



'report

Response.Write("Done.")

Response.End



End If

Everything up to now only executes when the script is completed. If the script wasn't submitted, the following is executed.


%>

<HTML>

<BODY>

<%

Dim sUserADSI, oMachine

Dim oMember, oGroup

Dim sADSI, bLoggedOn

Dim sMember

That gets variable definitions out of the way. Because the first thing we need to do is make sure the user is a member of Web Operators, we need to get the user's logon name. The Request object provides a ServerVariables collection, which provides access to a number of useful data-including the name of the logged-on user. I'm prefixing that logon name with a string that will turn it into an ADSI path.


'get current user

sUserADSI = "WinNT://BRAINCORE/" & _

 Request.ServerVariables("LOGON_USER")

We're going to be feeding that path to ADSI, so we need to flip any backslashes into regular slashes. The LOGON_USER variable returns something to the effect of domain\user, but ADSI expects to see domain/user instead. The Replace() function accomplishes the switch in one step.


'change backslashes to slashes for ADSI

sUserADSI = Replace(sUserADSI, "\", "/")

I use ADSI to get a reference to the Web Operators group.


'get the group

Set oGroup = GetObject("WinNT://DON-TABLET/Web Operators,group")

Now, I iterate through each member of the group. For each one, I check to see if the member's ADSI path matches the one I built for the user. If it does match, I set a variable to True and exit the For Each…Next loop.


'is the user a member?

For Each oMember in oGroup.Members

 If LCase(oMember.ADsPath) = LCase(sUserADSI) Then

  bLoggedOn = True

  Exit for

 End If

Next

I can now release the ADSI group object. If bLoggedOn equals True, I know the user logged on as a member of the Web Operators group, and I can continue.


Set oGroup = Nothing

If bLoggedOn = True Then

The next few lines are straight from my original static Web page design.


%><CENTER>

 <FORM ACTION="iis.asp" METHOD="POST">

  <INPUT type="text" name="VirtualDir">

  <SELECT size=1 name="Developer">

It's time to fill in that drop-down list of Web Developer members. I use code similar to what I just used to check the Web Operators group: query ADSI for the group, and add each member as an <OPTION> to the drop-down list box.


<%



'make a list of Web Developers members

Set oGroup = GetObject("WinNT://don-tablet/Web Developers,group")



For Each oMember in oGroup.Members

 sMember = Replace(oMember.ADsPath, "/", "\")

 sMember = Mid(sMember, 9, Len(sMember))

 Response.Write "<OPTION VALUE=" & sMember & ">"

 Response.Write sMember

 Response.Write "</OPTION>"

Next

Set oGroup = Nothing

%>

Finishing the static HTML also finishes the code that executes if the user is a member of Web Operators.


  </SELECT>

  <INPUT type="checkbox" name="AllowScript">

  <INPUT type="submit" value="Submit" name="Submit">

 </FORM>

</CENTER>

<%

Now, I include an Else and the code to execute if the user isn't a member of Web Operators.


Else

%>Your user account:

 <% Response.Write sUserADSI %>

 does not have access to this page.

 <%

End If

%>

</BODY>

</HTML>

That's it! The script should execute perfectly, after you make the minor changes I mentioned earlier. This should also serve as a great example of working with IIS from script, and of how to design an administrative Web page.

    Previous Section Table of Contents Next Section