HOWTO: Enumerate IIS website and ftpsite configuration (VBScript using ADSI)


I recently got a request to make a script to illustrate how to enumerate useful values from both Web and FTP sites serviced by IIS, so I decided to make some additions to the original script tool located here to allow it to easily enumerate both Web and FTP sites.


The modifications basically illustrate how both the Web and FTP services have consistent programming models and mechanisms to read/change configuration values. I basically only abstracted:



  • Metabase configuration node from /W3SVC (Web) to /MSFTPSVC (FTP)
  • ADSI Class name from IIsWebServer (Web) to IIsFtpServer (FTP)
  • Account for SecureBindings which exist for HTTPS (Web) but not for FTP

And the exact same script now displays both FTP and Web site status. The new syntax is still pretty straight forward – I just added one new parameter to distinguish between querying FTP vs Web sites.



  • EnumSites.vbs – enumerates status for Websites on this server
  • EnumSites.vbs server1 – enumerates status for Websites on server1
  • EnumSites.vbs localhost FTP – enumerates status for Ftpsites on this server

Enjoy,


//David

OPTION EXPLICIT

DIM strServer, strServerType, strServerMetaType
DIM objService

strServer = “localhost”
strServerType = “Web”
strServerMetaType = “W3SVC”

IF WScript.Arguments.Length >= 1 THEN
strServer = WScript.Arguments( 0 )
END IF

IF WScript.Arguments.Length = 2 THEN
strServerType = WScript.Arguments( 1 )

IF UCASE( strServerType ) = “FTP” THEN
strServerType = “Ftp”
strServerMetaType = “MSFTPSVC”
ELSE
strServerType = “Web”
strServerMetaType = “W3SVC”
END IF
END IF

WScript.Echo “Enumerating ” & strServerType & “sites on ” & strServer & VbCrLf
SET objService = GetObject( “IIS://” & strServer & “/” & strServerMetaType )
EnumServersites objService

SUB EnumServersites( objService )
DIM objServer, strBindings

FOR EACH objServer IN objService
IF objServer.Class = “IIs” & strServerType & “Server” THEN
WScript.Echo _
“Site ID = ” & objServer.Name & VbCrLf & _
“Comment = “”” & objServer.ServerComment & “”” ” & VbCrLf & _
“State = ” & State2Desc( objServer.ServerState ) & VbCrLf & _
“LogDir = ” & objServer.LogFileDirectory & _
“”

‘ Enumerate the HTTP bindings (ServerBindings) and
‘ SSL bindings (SecureBindings) for HTTPS only
strBindings = EnumBindings( objServer.ServerBindings )

IF strServerType = “Web” THEN
strBindings = strBindings & _
EnumBindings( objServer.SecureBindings )
END IF

IF NOT strBindings = “” THEN
WScript.Echo “IP Address” & VbTab & _
“Port” & VbTab & _
“Host” & VbCrLf & _
strBindings
END IF
END IF
NEXT

END SUB

FUNCTION EnumBindings( objBindingList )
DIM i, strIP, strPort, strHost
DIM reBinding, reMatch, reMatches
SET reBinding = NEW RegExp
reBinding.Pattern = “([^:]*):([^:]*):(.*)”

FOR i = LBOUND( objBindingList ) TO UBOUND( objBindingList )
‘ objBindingList( i ) is a string looking like IP:Port:Host
SET reMatches = reBinding.Execute( objBindingList( i ) )
FOR EACH reMatch in reMatches
strIP = reMatch.SubMatches( 0 )
strPort = reMatch.SubMatches( 1 )
strHost = reMatch.SubMatches( 2 )

‘ Do some pretty processing
IF strIP = “” THEN strIP = “All Unassigned”
IF strHost = “” THEN strHost = “*”
IF LEN( strIP ) < 8 THEN strIP = strIP & VbTab

EnumBindings = EnumBindings & _
strIP & VbTab & _
strPort & VbTab & _
strHost & VbTab & _
“”
NEXT

EnumBindings = EnumBindings & VbCrLf
NEXT

END FUNCTION

FUNCTION State2Desc( nState )
SELECT CASE nState
CASE 1
State2Desc = “Starting (MD_SERVER_STATE_STARTING)”
CASE 2
State2Desc = “Started (MD_SERVER_STATE_STARTED)”
CASE 3
State2Desc = “Stopping (MD_SERVER_STATE_STOPPING)”
CASE 4
State2Desc = “Stopped (MD_SERVER_STATE_STOPPED)”
CASE 5
State2Desc = “Pausing (MD_SERVER_STATE_PAUSING)”
CASE 6
State2Desc = “Paused (MD_SERVER_STATE_PAUSED)”
CASE 7
State2Desc = “Continuing (MD_SERVER_STATE_CONTINUING)”
CASE ELSE
State2Desc = “Unknown state”
END SELECT

END FUNCTION

Comments (27)

  1. Arasaka says:

    David,

    This is outstanding!

    I would love to a use a few parts of your code, but I am not sure where to cut it out so it will still work.

    What I am looking to do is pull the strServer from AD OUs, the parts that of your code that would be a real help are the "Site ID = " and the  "LogDir  = " I wish to use these field as variables in a copy to move the logs out the dir on the server to some other place and use the Site ID as a variable to append to sub folders, which are made off the system name. I am set one everything but how to put the parts of your code into middle of the script as to pull those bits of info.

    I would also like try to run FTP and Web together as one script but two would work.

    Any help you could throw my way would be great.

    Thank you,

    David Brown

  2. David.Wang says:

    David – I suggest the following steps, which basically copies all script code and making three modifications – one addition and two bulk deletion of unneeded code.

    1. copy all of the code in the script as-is. You can remove the IF-blocks containing “WScript.Arguments.Length” if you want.

    2. Wrap two new FOR-loops around the following part of the script, one walking through the list of strServer from AD OUs, and the other for appropriate strServerMetaType values for FTP or Web:

    SET objService = GetObject( “IIS://” & strServer & “/” & strServerMetaType )
    EnumServersites objService

    3. Substitute all code inside the following IF-block in the code to use objServer.Name as ID and objServer.LogFileDirectory to append to sub folders and copy/move log files.

    IF objServer.Class = “IIs” & strServerType & “Server” THEN
       ‘Substitute all code inside this nested IF-block…
    END IF

    //David

  3. Dave says:

    David,

    Thank you for the reply.

    I will try to follow your steps, I am not very skilled at scripting so I hope this work out and fill needs I am trying to fill.

  4. Dave Brown says:

    What would need to be changed to find the SMTP log locations?

    * Metabase configuration node from /W3SVC (Web) to /MSFTPSVC

    * ADSI Class name from IIsWebServer (Web) to IIsFtpServer (FTP)

    Thanks for any help, I am almost done with What I am trying to do.  You site has been a great help.

  5. Dave Brown says:

    Does anyone see anything out of place in this chunk of code?

    Thanks

    ‘***

    dim IISObj, IISSite

    ‘ WScript.echo ("Log file directories…" & strComputer )

    ‘ WScript.echo

    set IISObj = GetObject("IIS://"& strComputer &"/W3Svc")

    for each IISSite in IISObj

    if (IISSite.Class = "IIsWebServer") then

     WScript.echo IISSite.LogFileDirectory & "W3SVC" & IISSite.Name

     

    Set IISObj = GetObject("IIS://"& strComputer &"/MSFTPSVC")

    for each IISSite in IISObj

    if (IISSite.Class = "IIsFtpServer") Then

      WScript.echo IISSite.LogFileDirectory & "MSFTPSVC" & IISSite.Name

     

     

     strLocation = IISSite.LogFileDirectory

     DelLocation = IISSite.LogFileDirectory & "W3SVC" & IISSite.Name

    ‘ Wscript.echo strlocation

    ‘ Wscript.echo DelLocation

     

    End If

    ‘***

  6. Stevie says:

    Hi David,

    Your page came up when I did a search on how to use script to migrate an IIS site.

    Basically, what I need is to:

    gather all settings for a particular site, including things like host headers used

    write these settings to a newly-created site on the same server

    I don’t want to ask someone else to do this for me – unless you’ve already written something which does it! – but would appreciate any pointers you can give on references for the methods that might be of interest.

    Many thanks

  7. Stevie says:

    Re the above, please disregard – I’ve noticed that my Windows Administrator’s Automation Toolkit has a chapter devoted to this… I simply haven’t had time to look at it since I acquired it – until today!

    Thanks again,

  8. Alan Kaplan says:

    I need to audit web servers in my domain, and would like to be able to connect to each server, and enumerate the virtual directories — ultimately leading to a link to each web site hosted by the server.  Can this code be modified to get that information?

    Thanks.

  9. David Wang says:

    Question: I need to audit web servers in my domain, and would like to be able to connect to each server,

  10. David.Wang says:

    Alan – If you just want to enumerate virtual directories, you can script the built-in ADSUTIL.VBS script to do this. I wrote the following quick batch script as illustration.

    http://blogs.msdn.com/david.wang/archive/2007/12/19/howto-list-all-virtual-directories-and-paths-of-a-list-of-servers.aspx

    //David

  11. Question: I need to audit web servers in my domain, and would like to be able to connect to each server

  12. Brody says:

    Has anybody modified this script, or could any one modify this script to write to a database or text file rather than a pop-up window. I am query 100s of servers, and I am not quite sure how to modify it accordingly. Actually I just need secure bindings and nothing else.

    Could anyone help me out? You can email me at bkilpatr@stewart.com if you like, or just post here.

  13. David.Wang says:

    Noticias externas – As documented in the blog entry, the first commandline parameter to the tool is the name of the remote server

    //David

  14. David.Wang says:

    Brody – No modifications needed. Launch this script with CSCRIPT.EXE

    Default scripting host in Windows is WSCRIPT.EXE, which uses a popup window for output.

    One can easily redirect output to a text file, and entering data into a database is likewise easy from the commandline. Those are tasks best done by the reader.

    //David

  15. Frits says:

    Does it work both on IIS 5.0 and 6.0 ??

  16. David.Wang says:

    Frits – why don’t you try it and be positively surprised? 🙂

    //David

  17. Chet Bliss says:

    David,

    I love your script. I really to output this info to text file instead of the screen. I saw that you said cscript would do the job but I can’t get it working. Would it be possible for you to create a small script outputing one of the variables to a file. I could then figure out the rest.

    Thank you in advance.

    Chet

  18. David.Wang says:

    Chet Bliss – CSCRIPT Script.VBS > Filename.txt

    //David

  19. Chet Bliss says:

    David,

    Thank you for the response. My team is enumerating web site on thousands of servers and I can not guarantee that IIS would be installed on every team members computer. I am trying to use SWbemServices with your script and can not get it to work.

    Thanks

    Chet

  20. Felix says:

    Been looking all day for something like this. Just what I needed, thanks.

    -Felix

  21. Harshini says:

    Davind, great piece of code! Thank you; very useful.

    Now…

    I need to find the physical path to any given Web site on a given machine that has IIS 5, 6 or 7 on it.

    So, using the site ID seems to be the way to go… But what property do I check for? Sorry, am not very well versed in finding IIS metadata and am unsure where to look… I can see that Server.MapPath is used in some cases in ASP… but I need to use vbscript.

    Thanks in advance!

    Harshini

  22. David.Wang says:

    Harshini – I suggest looking at how this script works.

    http://blogs.msdn.com/david.wang/archive/2007/12/19/howto-list-all-virtual-directories-and-paths-of-a-list-of-servers.aspx

    By default, legacy ADSI/WMI providers compatible with IIS5/6 are NOT installed with IIS7, so there is no way to do what you want with default IIS installations.

    ASP actually uses VBScript as a language by default, so your requirement is actually inconclusive. Choice of language is actually tangential to solving the issue.

    ASP/ASP.Net Server.MapPath calls HSE_REQ_MAP_URL_TO_PATH underneath the covers, which does a lookup sorta like what the script I want you to look at.

    //David

  23. Jeff says:

    Would be great to find a type library for these objects somewhere.

    I’m not a very variant kind of guy.  =)

    The Active DS IIS Extension Dll appears to be incomplete.

  24. Chris says:

    Wonderful script!

    However, another recommendation I would make is to replace that nasty case statement with a scripting dictionary.  It cleans up a lot of your code.  Here's what I did:

    Dim sdState : Set sdState = CreateObject("Scripting.Dictionary")

    sdState.Add 1, "Starting (MD_SERVER_STATE_STARTING)"

    sdState.Add 2, "Started  (MD_SERVER_STATE_STARTED)"

    sdState.Add 3, "Stopping (MD_SERVER_STATE_STOPPING)"

    sdState.Add 4, "Stopped  (MD_SERVER_STATE_STOPPED)"

    sdState.Add 5, "Pausing  (MD_SERVER_STATE_PAUSING)"

    sdState.Add 6, "Paused   (MD_SERVER_STATE_PAUSED)"

    sdState.Add 7, "Continuing (MD_SERVER_STATE_CONTINUING)"

    It's called with:

    sdState.Item(intState)

  25. EBrant says:

    Hello

    I am not a scripter so please bear with me, I want to get the "Subject Name" and "Issuer" of the SSL certificate. I presume I need a line similar to the following

    Comment = """ & objServer.ServerComment

    but the ServerComment part would be some thing like SubjectName or Issuer ?

    I would be very grateful if you can assit me on this please

    Thanks

    Ernie

    ErnestBrant@Hotmail.co.uk

  26. EBrant says:

    Hello

    I am not a scripter so please bear with me, I want to get the "Subject Name" and "Issuer" of the SSL certificate. I presume I need a line similar to the following

    Comment = """ & objServer.ServerComment

    but the ServerComment part would be some thing like SubjectName or Issuer ?

    I would be very grateful if you can assit me on this please

    Thanks

    Ernie

    ErnestBrant@Hotmail.co.uk

  27. Lenard says:

    Hi David, how do I collect the base installation directory of the website,

    Leonard

    Leonard.lunardi@trescon.com.br