How to Manipulate (insert/replace/remove) LIST data type in IIS Configuration

After a long tour on newsgroups, I am starting my blog today.

For my first entry, I am going to discuss a frequent question about IIS programmatic administration – how to manipulate the LIST data type (i.e. ScriptMaps, HttpErrors, ServerBindings, etc). No, MIMEMap is not included in this because it is not a LIST (it is its own custom data type) – good topic for a future blog…

The astute reader should realize that ADSUTIL.VBS already allows you to set/delete these LIST properties. However, ADSUTIL.VBS has a fatal flaw for multi-valued properties like LIST – it only allows you to set/delete the entire LIST. It does not allow you to replace one LIST item with a new value. Even worse, the default implementation only allows nine commandline parameters. So, suppose you wanted to:

  • add a wildcard application mapping (with long filepath)
  • replace the 404 Custom Error URL while preserving all other Custom Error definitions
  • add/edit a Host header while preserving all others
  • recursively remove an application mapping from everywhere

THEY are all impossible do with an unmodified ADSUTIL.VBS. Therefore, I decided to write a little tool that illustrates how to:

  • Navigate and enumerate through the IIS configuration namespace (/RECURSE)
  • Locate LIST data types (like ScriptMaps, HttpErrors, ServerBindings, etc) (SYNTAX)
  • Enumerate and Manipulate LIST data type

In fact, the above tasks become very straight forward with this tool:

  • Add a wildcard application mapping for website ID 1
    <chglist.vbs> W3SVC/1/root/ScriptMaps “” “*,%ProgramFiles%\WildcardISAPI.dll,0” /INSERT /COMMIT
  • Change the 404 Custom Error for website ID 1
    <chglist.vbs> W3SVC/1/HttpErrors 404 404,*,URL,/CustomErrors/404.asp /COMMIT
  • Add a Host header for Website ID 2 while preserving all others
    <chglist.vbs> W3SVC/2/ServerBindings FIRST “” /INSERT /COMMIT
  • Recursively remove application mapping for “.ext” extension
    <chglist.vbs> W3SVC/ScriptMaps “.ext” “” /REMOVE /RECURSE /ALL /COMMIT

You can run the script with no commandline parameters for help, and operation should be self-explanatory.  The tool does not make any changes unless you add /COMMIT, so feel free to poke around the various options.  Feel free to post comments/suggestions as well as propose future topics.

[Updated 04/22/2006 – Added “ (double-backquote) syntax to put in double-quotes into a value. This allows manipulation of ScriptMaps, Application Extensions, etc pathnames with spaces.]

[Updated 05/11/2006 – Fixed bugs to make /recurse work correctly. Fixed bug when matching against “*” and /RegExp is not specified]



‘ Allows append/insert/remove of specific elements from an IIS “List” type node
‘ i.e. ScriptMap, HttpError, ServerBindings

‘ Origin :
‘ Version: December 1 2004

Option Explicit
On Error Resume Next


CRLF = CHR(13) & CHR(10)
Dim strHelp
strHelp = “Edit/Replace IIS metabase LIST properties” & CRLF &_
WScript.ScriptName & ” PropertyPath ExistValue NewValue [Options]” & CRLF &_
“Where:” & CRLF &_
” PropertyPath IIS metabase property path whose data type is LIST.” & CRLF &_
” i.e. W3SVC/ScriptMaps, W3SVC/HttpErrors” & CRLF &_
” ExistValue Value to case-insensitive literal match against existing” & CRLF &_
” LIST elements.” & CRLF &_
” FIRST – matches the first LIST element.” & CRLF &_
” LAST – matches the last LIST element.” & CRLF &_
” NewValue New value that replaces the matched the LIST element.” & CRLF &_
“Options:” & CRLF &_
” /INSERT Insert before LIST element matching .” & CRLF &_
” /REMOVE Remove LIST element matching .” & CRLF &_
” /ALL Operate on ALL matching . Default is first match.” & CRLF &_
” /REGEXP Use as RegExp to match. Default is literal.” & CRLF &_
” /RECURSE Recursively perform the operation underneath .” & CRLF &_
” /VERBOSE Give more status/output.” & CRLF &_
” /COMMIT Actually perform changes. Default only shows.” & CRLF &_

dim Debug
Debug = true
dim Verbose
Verbose = false
dim reMatch
reMatch = false

Dim strServer
Dim strNamespace
Dim strSchemaNamespace
Dim strNodeSyntax
Dim objNode

Dim nOperationType
Dim strNormalizedPath
Dim strPropertyPath
Dim strPropertyName
Dim strPropertyExistValue
Dim strPropertyNewValue

Dim i,j

‘ Start of script

strServer = “localhost”
strNamespace = “IIS://” & strServer
strSchemaNamespace = strNamespace & “/” & “Schema”

‘ Parse the commandline

If WScript.Arguments.Count < 3 Then
HandleError “Insufficient number of arguments.” & CRLF &_
strHelp &_
End If


For i = 0 To WScript.Arguments.Count – 1
Select Case UCase( WScript.Arguments( i ) )
Case “/INSERT”
nOperationType = nOperationType Or LIST_OPTION_INSERT
Case “/REMOVE”
nOperationType = nOperationType Or LIST_OPTION_REMOVE
Case “/ALL”
nOperationType = nOperationType Or LIST_OPTION_ALL
nOperationType = nOperationType Or LIST_OPTION_RECURSE
Case “/COMMIT”
Debug = false
Verbose = true
Case “/REGEXP”
reMatch = true
Case Else
If ( i = 0 ) Then

‘ Split out PropertyName and its ParentPath from PropertyPath

strNormalizedPath = NormalizePath( WScript.Arguments( 0 ) )
HandleError “Failed to normalize PropertyPath.”

j = InstrRev( strNormalizedPath, “/”, -1, 0 )

If ( j = 0 Or j = 1 ) Then
HandleError “Invalid PropertyPath.”
End If

strPropertyPath = NormalizePath( Mid( strNormalizedPath, 1, j – 1 ) )
HandleError “Failed to retrieve/normalize PropertyPath.”

strPropertyName = NormalizePath( Mid( strNormalizedPath, j + 1 ) )
HandleError “Failed to retrieve/normalize PropertyName.”
ElseIf ( i = 1 ) Then

‘ The existing match value

strPropertyExistValue = Replace( UCase( WScript.Arguments( 1 ) ), ““”, “””” )
ElseIf ( i = 2 ) Then

‘ The new replace value

strPropertyNewValue = Replace( WScript.Arguments( 2 ), ““”, “””” )
HandleError “Unknown parameter ” & WScript.Arguments( i ) & CRLF &_
strHelp &_
End If
End Select

LogVerbose “OpType = ” & nOperationType
LogVerbose “PropertyPath = ” & strPropertyPath
LogVerbose “PropertyName = ” & strPropertyName
LogVerbose “ExistValue = ” & strPropertyExistValue
LogVerbose “NewValue = ” & strPropertyNewValue

‘ Check the data type for the given property
‘ If it is not LIST, do not process any further

Set objNode = GetObject( strSchemaNamespace & “/” & strPropertyName )
HandleError “Cannot read schema for property ” & strPropertyName
strNodeSyntax = UCase( objNode.Syntax )

LogVerbose “Syntax = ” & strNodeSyntax
LogVerbose “”

Select Case strNodeSyntax
Case “LIST”

‘ Finally, we are ready to do some real work

Err.Number = HandleListOps( nOperationType, strPropertyPath, strPropertyName, strPropertyExistValue, strPropertyNewValue, ( nOperationType And LIST_OPTION_RECURSE ) <> 0 )
HandleError “”
Case Else
HandleError “Cannot handle ” & strPropertyPath & “/” & strPropertyName & ” with type ” & strNodeSyntax
End Select

‘ End of script

‘ Sub routines and functions

Sub HandleError( errorDescription )
If ( Err.Number <> 0 ) Then
If ( IsEmpty( errorDescription ) ) Then
LogEcho Err.Description
LogEcho errorDescription
End If

WScript.Quit Err.Number
End If
End Sub

Function NormalizePath( strInput )

‘ Replace all \ with /

strInput = Replace( strInput, “\”, “/”, 1, -1 )

‘ Replace all // with /

strInput = Replace( strInput, “//”, “/”, 1, -1 )
Loop While ( Instr( strInput, “//” ) <> 0 )

‘ Removing leading and trailing /

If ( Left( strInput, 1 ) = “/” ) Then
strInput = Right( strInput, Len( strInput ) – 1 )
End If

If ( Right( strInput, 1 ) = “/” ) Then
strInput = Left( strInput, Len( strInput ) – 1 )
End If

NormalizePath = strInput
End Function

Function HandleListOps( OpType, strPropertyPath, strPropertyName, strPropertyExistValue, strPropertyNewValue, bRecurse )
On Error Resume Next
Dim objNode, objNodeAttribute
Dim objList
Dim objElement
Dim objNewArray
Dim PerformedOperation
Dim Operation
Dim re
Dim reMatched
Dim i, j

Set objNode = GetObject( strNamespace & “/” & strPropertyPath )
objList = objNode.Get( strPropertyName )

If ( Err.Number <> 0 Or IsEmpty( objList ) ) Then
LogEcho “Failed to retrieve ” & strPropertyPath & “/” & strPropertyName
HandleListOps = Err.Number
Exit Function
End If

Set objNodeAttribute = objNode.GetPropertyAttribObj(strPropertyName)
HandleError “Failed to retrieve Attributes for ” & strPropertyPath & “/” & strPropertyName

If ( objNodeAttribute.IsInherit = true ) Then
LogEcho strPropertyPath & “/” & strPropertyName & ” (Inherited)”

If ( bRecurse = true ) Then
LogEcho( “Ignoring inherited property for Recursive Modification” )
Exit Function
End If
LogEcho strPropertyPath & “/” & strPropertyName
End If

‘ j is the count of elements in objNewArray
‘ So that we can resize it to the right size in the end

j = 0

‘ Size objNewArray to maximum possible size up-front, later shrink it

Redim objNewArray( UBound( objList ) + UBound( objList ) + 1 )

‘ PerformedOperation indicates whether something has matched and already
‘ operated upon, in this session. Start with ‘not yet’ = 0

PerformedOperation = 0

‘ Setup the RegExp match based on the existing value to search for

Set re = new RegExp
re.Pattern = strPropertyExistValue
re.IgnoreCase = true
re.Global = true

‘ Do this test outside of IF conditional because on error resume next
‘ turns off failures due to incorrect Pattern

reMatched = re.Test( objElement )
If ( Err.Number <> 0 Or reMatch = false ) Then
reMatched = false
End If

LogVerbose “Original:”

For i = LBound( objList ) To UBound( objList )
objElement = objList( i )
‘LogVerbose i & “(” & j & “)” & “: ” & objElement

If ( ( ( ( strPropertyExistValue = LIST_OP_FIRST ) And ( i = LBound( objList ) ) ) Or _
( ( strPropertyExistValue = LIST_OP_LAST ) And ( i = UBound( objList ) ) ) Or _
( ( reMatch = false ) And ( Instr( UCase( objElement ), strPropertyExistValue ) > 0 ) ) Or _
( reMatched = true ) _
) _
And _
( ( ( OpType And LIST_OPTION_ALL ) <> 0 ) Or ( PerformedOperation = 0 ) ) _
) Then
Operation = “Replace ”

If ( ( OpType And LIST_OPTION_REMOVE ) <> 0 ) Then
‘Don’t copy this element for deletion
Operation = “Remove ”
objNewArray( j ) = strPropertyNewValue
j = j + 1

If ( ( OpType And LIST_OPTION_INSERT ) <> 0 ) Then
Operation = “Insert ”
objNewArray( j ) = objElement
j = j + 1
End If
End If

PerformedOperation = 1
Operation = “”
objNewArray( j ) = objElement
j = j + 1
End If

LogVerbose Operation & objElement

‘ Resize the final array to the correct size prior to SetInfo

ReDim Preserve objNewArray( j – 1 )

LogVerbose “New:”

For i = LBound( objNewArray ) To UBound( objNewArray )
LogDebug i & “: ” & objNewArray( i )

If ( Debug = false ) Then
If ( PerformedOperation = 1 ) Then
objNode.Put strPropertyName, objNewArray
HandleError “Failed to SetInfo ” & strPropertyPath & “/” & strPropertyName
LogEcho “SUCCESS: Updated ” & strPropertyPath & “/” & strPropertyName
LogEcho “SUCCESS: Nothing to update”
End If
If ( PerformedOperation = 1 ) Then
LogEcho “DEBUG: Matched. Did not SetInfo”
LogEcho “SUCCESS: No Match. Did not SetInfo”
End If
End If

If ( bRecurse = true ) Then
For Each objElement In objNode
LogEcho “”
HandleListOps = HandleListOps( OpType, NormalizePath( Mid( objElement.AdsPath, Len( strNamespace ) + 1 ) ), strPropertyName, strPropertyExistValue, strPropertyNewValue, bRecurse )
End If

HandleListOps = 0
End Function

Sub LogEcho( str )
WScript.Echo str
End Sub

Sub LogDebug( str )
If ( Debug = true ) Then
LogEcho str
End If
End Sub

Sub LogVerbose( str )
If ( Verbose = true ) Then
LogEcho str
End If
End Sub

Comments (118)

  1. Rick Stivers says:

    I guess I could then run this from within using System.Diagnostics.Process.Start to open a cmd prompt and pass in the arguments. I set custom errors based on the web site being created, and it was a pain editing the metabase.xml file. I’ll let you know how it goes. Thanks for the very nice script!

  2. says:

    this is not working for me

    adding a Wildcard Application map on

    II 6.0 on Windows 2003..

    It just adds a blank space under the

    regular application mappings..

    Using adsutil.vbs does add it correctly

    but it deletes (under the wildcard application maps) but delets all the other mappings

    in the application section..

  3. David.Wang says:

    Can you give the exact command that you used.

    It worked fine for me to insert an ISAPI wildcard application mapping at any point that I wanted.


  4. David Wang says:

    A powerful but often under-utilized and misunderstood feature of IIS is its programmatic configuration…

  5. David Wang says:

    A powerful but often under-utilized and misunderstood feature of IIS is its programmatic configuration…

  6. Thanks David! I used this code to hunt down a bug of my own today 🙂

  7. mattgo says:

    Thanks for the script – tweaking just one of the list elements has been tripping me up for weeks! Too bad your script relies on local execution on the server… I’ve got 200+ to wire up – guess I’ve got a little work to do now 🙂

  8. David Wang says:

    There is a variable at the top of the script, strServer, which can be easily adjusted to any other server name or parameterized from the commandline.


  9. Tim says:

    I am wanting to add a hostheader to a particular site (ie: on port 80). How is this done through this script?

  10. David Wang says:

    Tim – Assuming the site ID is 1…

    <tool name.vbs> W3SVC/1/ServerBindings : "" /INSERT

    Which basically means:

    1. Inside of the LIST element named W3SVC/1/ServerBindings

    2. Search for a LIST element with ":" in it

    3. /INSERT ahead of that element another element whose value is ""

    In other words, that’s exactly the mechanics of "adding a hostheader" element to a particular site’s ServerBinding.


  11. Shaun says:

    How come when I change a custom error page (401,1) to a URL

    <tool name.vbs> W3SVC/3/HttpErrors 401,1 401,1,URL,/errors/401-1.html

    It works great but when I go into IIS and change the same error page to the default or another file and re-run the VBS script to change another error page it still reports that 401,1 is set to /errors/401-1.html and not to what I changed it to in IIS?

    Is there a cache problem maybe?

  12. Shaun says:

    How come when I change a custom error page (401,1) to a URL

    <tool name.vbs> W3SVC/3/HttpErrors 401,1 401,1,URL,/errors/401-1.html

    It works great but when I go into IIS and change the same error page to the default or another file and re-run the VBS script to change another error page it still reports that 401,1 is set to /errors/401-1.html and not to what I changed it to in IIS?

    Is there a cache problem maybe?

  13. David Wang says:

    Shaun – You need to give /COMMIT on the commandline to have it actually change configuration (by default it just shows you what it is going to do – so that you can verify the right search/replace happens *before* you do something).

    So, if you use the above syntax, no matter what you changed the error page to in IIS, the tool will display /errors/401-1.html because that’s what it is *going* to change it to.

    If you want to list what is in the property, either use ADSUTIL.VBS to retrieve the property directly, or use the tool’s /INSERT syntax to insert an entry, which then gives you an idea what the original list looks like with the new entry inserted – but that’s not a LISTing of what actually exists.


  14. Sandeep says:

    I am trying to remove a particular entry from scriptmaps of a website. It is a wildcard entry. But it is removing all entries from the scriptmap.

    How can I make this happen. The command I am using is:

    cscript <sample code>.vbs w3svc/3/root/scriptmap "*, E:CFusionMXruntimelibwsconfig1jrun_iis6_wildcard.dll,3" "" /remove /commit

  15. David.Wang says:

    Sandeep – hmm, weird. The "*" seems to be tricking VBScript somehow, but I’m not certain why.

    Since that parameter is an inclusive match, you can simply work around the behavior by not specifying "*," because the rest will simply match and the right entry gets removed.

    I’ll debug and figure out what is going on with "*" and post the update here…


  16. Lenny says:

    Well I like the script as it saved me a lot of effort. I worked out the mime map thing and it followed the same principal of getting the existing array and redim presever with an increment on the current count.

    Only thing is that even from the command prompt it tells me that

    c:ADSIArrayListTool W3SVC/Root/RacketShop/HttpErrors 404 404,2,FILEc:WINDOWSiisHelpcommon404lw.htm /COMMIT

    has been successfull but Metabase Explorer and IIS Manager show that no change has occured. I’ll peservere though as I’m close…


  17. Lenny says:

    Note for the posting above –

    although I typed it wrong here the syntax does actually include the /n or /1 for the website path and there is a comma between FILE and the path.

    I have edit while running enabled in the metabase and the script does add a value to the custom errors list. Although the old one still is there and the new one shows up in metabase explorer but not on the custom errors tab for the Racket shop vdir.

    Interesting, I’ll try removing an entry before adding one etc and see how it goes…

  18. David Wang says:


    What is a 999 error and how can I troubleshoot it? It’s not an error code that IIS will allow…

  19. Your site is very informational for me. Nice work.

  20. ale5000 says:

    Nice work but

    – "/remove" There are two equal elements but it remove only one.

    – "/insert" It shouldn’t add a new element if it is already present.

  21. David.Wang says:

    ale5000 –

    1. As documented in help:

       /ALL         Operate on ALL matching <ExistValue>. Default is first match.

    So,  /remove /all  will remove all matching elements. Default is first match

    2. LIST data type does not have uniqueness constraint in IIS, so I am not introducing it. For example, it is ok to configure multiple identical *-scriptmaps.


  22. loralynne says:


    Iʻm trying to add an application extension, but the path to the dll Iʻm adding has spaces in it so it needs quotes around the path.  I canʻt seem to get the quotes in there using this script.  Can someone help me out with this please?



  23. David.Wang says:

    loralynne – There is already a tool to manipulate Application Extensions. iisext.vbs

    It is actually impossible to pass double-quotes into a script hosted by Windows Scripting Host (like VBScript or JScript), so what you are asking for is not possible by default. I explain why in the referenced blog entry.

    Now, one can always come up with a custom-encoding for double-quotes to work around this issue, but that was not in my sample. I just added a syntax for it – double-backquote = double-quote


  24. loralynne says:

    Thanks, David!  Works great.

    Yeah, I use iisext.vbs to add a Web Service Extension.  Iʻm using your script to add to the ScriptMaps property.

  25. David Wang says:

    It never ceases to amaze me how easily users will download and install arbitrary binaries from arbitrary…

  26. surendraz says:

    Hi David,

       I have  a script that does something like this –

    Find all the xml nodes where HTTPERRORS is defined in Metabase.xml

            Now, traverse through all the nodes and then update the list to the new set of HTTPERRORS list.

    Script looks like this –  

         Set iisPath = GetObject("IIS://" & strServerName)

         aryPathList = iisPath.GetDataPaths("HttpErrors",0)

         For Each strPath in aryPathList

              Set iisPath = GetObject(strPath)

              aryCustomErrors = iisPath.GetEx("HttpErrors")

              — UPDATE THE LIST

              iisPath.PutEx  ADS_PROPERTY_UPDATE,"HttpErrors",aryMasterArray



    This seem to work fine, but I just discovered that for some folders under v-roots has HTTPERRORS defined as a custom element, where this script bails out.

    HTTPERRORS as a custom element looks like this —

    <IIsConfigObject Location ="/LM/W3SVC/1/ROOT/SampleVRoot/Folder1"










    Do you have any suggestions on handling this case? I can be more specific and precise on the script if you would like to know the exact script…


  27. surendraz says:

    Hi David,

           May be I should rephrase the question in this way – Can I update Custom properties via ADSI? If not, are there any other easy ways to achieve this?


  28. Confused Admin says:

    Hi David,

    First off, thanks for your help on the IIS Newsgroups;

    I think I am now very close to what I want by using your script.

    I am still having some problems though when trying to do a recursive replacement of a particluar application mapping. This is my script;

    cscript <script_name> W3SVC/ScriptMaps ".app" ".app,X:pathtoapp.dll,5" /ALL /RECURSE /COMMIT

    If I remove the "/COMMIT" switch and put in a "/VERBOSE" one, I can see that the script is matching all the existing application mappings for ".app" throughout the metabase. The problem is when I put the "/COMMIT" switch back in the script exits the first time it doesn’t get a match instead of continuing through the metabase. Is this behaviour by design, is it a bug, or have I just gotten the syntax wrong (probable)? Thanks again.

  29. David.Wang says:

    Confused Admin – Ah, you found two bugs which I have fixed and reposted.

    Bug 1 – VBScript uses "Exit Function" to return from a function, not "Return". It silently ignored my syntax error of using "Return", a part of my error-checking, which played havoc on the remainder of the code since it then allowed: "If (Undefined AND true )" to return true, which caused the code to attempt to match and modify a property that it should not… which fails and since I expect it to succeed, the code fails fast and quits.

    It would have been nice for VBScript to tell me "syntax error" up-front because then I would have figured out "Exit Function" earlier…

    Bug 2 – When recursively editing a value, you should not edit inherited values.

    This should now address your issues.


  30. David.Wang says:

    Sandeep – Ok, I finally figured out what is going awry with your use of "*" on the commandline. The "*" was being used in a RegExp Test and failing (since "*" needs a qualifier), but due to "on error resume next", it still evaluated to "true" and thus mistakenly matching against entries.

    This is now fixed.


  31. David.Wang says:

    surendraz – Unfortunately, custom nodes are exactly that, "custom", so it does not conform to any schema and hence cannot be manipulated via ADSI/WMI.

    IIS should not be generating any custom nodes, so its presence means that you have run code which incorrectly modified properties using ABO (which is the only way to generate such nodes since it is not bound by schema).

    Now, IIS still functions because it uses ABO to read properties. Such incorrect properties are only problems for scripts that use ADSI/WMI to configure IIS and are unfortunately by-design.

    You want to deal with this problem by removing/fixing code who generates custom nodes in the IIS metabase.


  32. Confused Admin says:

    Hi David,

    Thanks very much for your help again, I really appreciate it. I’m using your updated script and I think there still might be an issue with the script exiting early. This time it is not exiting because it failed to find a match, but rather because it finds an inherited property. Should the script exit when it finds an inherited property, or should it just skip it and move onto the next one?

  33. David.Wang says:

    Confused Admin – I think something else specific to your machine is happening – maybe you have a property that is not type’d correctly from some 3rd party application.

    On /recurse, the tool skips the inherited property and moves on to the next one.


  34. Confused Admin says:

    Hi David,

    Actually I think you’re correct David, the issue I’m having is different than I first thought. I don’t think it is to do with the inherited values now, and it seems to be due to property depth in the metabsae. This is the syntax I’m using to try and recursively remove any .app application mapping that is not inherited throughout the entire metabase;

    cscript <script_name> W3SVC/ScriptMaps ".app" "" /REMOVE / ALL /RECURSE /COMMIT

    This seems to only work until the script reaches Root. For example the recursive search  for these paths work;



    But the script seems to exit when it gets to here;


    If I run the script with the full path to where any custom application mappings are actually going to reside the script works fine, such as;

    cscript <script_name> W3SVC/1/Root/ScriptMaps ".app" "" /REMOVE / ALL /RECURSE /COMMIT

    Maybe I am missing something, but I have now tested this on two IIS 5.1 machines and one IIS 6 server with consistent results. Is Root treated differently perhaps?

  35. David.Wang says:

    Confused Admin – can you turn on /VERBOSE and /DEBUG so that we narrow down where the failure is coming from your commandline.

    Root is not treated differently; on my IIS 5.1 and IIS 6 machines the recursion worked just fine, including at W3SVC/1/Root/ScriptMaps.

    There is something consistently peculiar on your machines.


  36. Confused Admin says:

    Sorry for all the trouble David. I created a test application mapping for a ".app" extension in W3SVC/7989556/Root/ScriptMaps using the IIS Admin MMC, and this is what I get when I run your script (named update_metabase.vbs in this case);

    C:InetpubAdminScripts>update_metabase.vbs W3SVC/ScriptMaps ".app" ""  /REMOVE /RECURSE /ALL /VERBOSE

    OpType       = 14

    PropertyPath = W3SVC

    PropertyName = ScriptMaps

    ExistValue   = .APP

    NewValue     =

    Syntax       = LIST













    0: .asa,C:WINDOWSsystem32inetsrvasp.dll,5,GET,HEAD,POST,TRACE

    1: .asp,C:WINDOWSsystem32inetsrvasp.dll,5,GET,HEAD,POST,TRACE

    2: .cdx,C:WINDOWSsystem32inetsrvasp.dll,5,GET,HEAD,POST,TRACE

    3: .cer,C:WINDOWSsystem32inetsrvasp.dll,5,GET,HEAD,POST,TRACE

    4: .idc,C:WINDOWSsystem32inetsrvhttpodbc.dll,5,GET,POST

    5: .php,S:PHP4sapiisapi_fcgi.dll,5

    6: .shtm,C:WINDOWSsystem32inetsrvssinc.dll,5,GET,POST

    7: .shtml,C:WINDOWSsystem32inetsrvssinc.dll,5,GET,POST

    8: .stm,C:WINDOWSsystem32inetsrvssinc.dll,5,GET,POST

    SUCCESS: No Match. Did not SetInfo

    W3SVC/1/ScriptMaps (Inherited)

    Ignoring inherited property for Recursive Modification

    W3SVC/1636682815/ScriptMaps (Inherited)

    Ignoring inherited property for Recursive Modification

    W3SVC/7989556/ScriptMaps (Inherited)

    Ignoring inherited property for Recursive Modification

    Failed to retrieve W3SVC/AppPools/ScriptMaps

    Failed to retrieve W3SVC/Filters/ScriptMaps

    Failed to retrieve W3SVC/Info/ScriptMaps


  37. Paul M says:

    I tried use this script to set a Wildcard application map for a virtual directory, but it seems to be setting a blank application extension instead. Here is the command line I am using:

    script.vbs w3svc/1/ROOT/<VirtualDir>/ScriptMaps "" C:WINDOWSMic

    rosoft.NETFrameworkv1.1.4322aspnet_isapi.dll /INSERT /COMMIT

    Am I using the wrong property?

  38. loralynne says:

    Hi David,

    I’m using your script to add an Application Mapping.  However, on  Windows 2000 and Windows XP, I need the path to the dll to be in 8.3 format.  Can you help me please?



  39. Pokche says:

    I am trying to run <chglist.vbs> W3SVC/1/HttpErrors 404 404,*,URL,/CustomErrors/404.asp /COMMIT  but I want to change the error code 403;4 instead but am unable to do so. I ran the following:

    <chglist.vbs> W3SVC/1/HttpErrors 403 403,4,URL,/CustomErrors/404.asp /COMMIT

    I can however update 403;1 error code using the above line but not 403;4.  Can you help me on what i am missing here?


  40. David.Wang says:

    Pokche – Since you want to change the specific custom error 403;4, try matching match against "403,4" instead of just "403" for replacement.

    HttpErrors is a LIST of custom errors for ALL error codes, 403.1 as well as 403.4. Since 403.1 comes before 403.4 numerically in the LIST, the tool changes the FIRST entry that matches by default, and you gave "403", which matches 403.1, 403.2, 403.3, 403.4, etc, that is why you are updating 403.1 custom error with your syntax.


  41. David.Wang says:

    Paul M – When you make changes to IIS configuration without using the UI (such as with a script through the IIS Admin Interfaces), you can insert whatever you want, including invalid/incorrect values… so it is important to follow documentation for syntax.

    See the documentation for ScriptMaps from here:

    A trick for determining the syntax is to use the IIS Manager UI to make the change and then see what it changed and how.

    In your case, your syntax inserts an application mapping without an extension… which is exactly what you observed.

    I updated the examples in the blog entry to show how to add a wildcard application mapping.


  42. David.Wang says:

    loralynne – I am not certain why you require a 8.3 filepath. IIS on Windows 2000, Windows XP, and Windows Server 2003 all support Application Mappings with long filepath. In fact, IIS6 rejects 8.3 filepath for security reasons.

    I updated the examples in the blog entry to show how to add an application mapping with long filepath (see the wildcard application mapping example which uses %ProgramFile%, usually a long filepath).

    Please consider using long filepath because it is the secure choice.


  43. loralynne says:

    Hi David,

    Thanks for your response.

    I’m doing a PHP installation, and the problem is that PHP doesn’t work if the php isapi dll is installed in say, C:Program Files, or any directory whose path has spaces in it.  It works if this path is in 8.3 format in the application mapping or if the dll is moved to the WINDOWS directory.

    Here are a couple of links that suggest using 8.3 format:



  44. David.Wang says:

    loralynne – PHP ISAPI DLL works fine for me in "C:Program FilesP H P" on Windows 2000, Windows XP, and Windows Server 2003 – I just tried it myself.

    So, I am still confused of what you are trying to ask of me. What is stopping you from giving the pathname in 8.3 format to the script? Or are you asking for the script to translate a longpath to shortpath for you?


  45. David.Wang says:

    loralynne – I just went to read the "Suggestions" made at the links that you pointed me to. What a good chuckle! 🙂

    Don’t get me wrong — I understand and appreciate the efforts made by other kind users trying to help each other out. It’s just that many of the "suggestions" are of the "I got it to work by doing this" variety and not necessarily done the right way through an understanding of IIS — so you have to take it with a grain of salt. Most of the suggestions, while they’ll "work", are actually quite bad because IIS works much better than they assume. I wish I can delete most of those bad suggestions!

    I assure you that using:

    chglist.vbs W3SVC/1/root/ScriptMaps "" ".php,%ProgramFiles%P H PPHP5ISAPI.DLL,1" /INSERT /COMMIT

    Will work for PHP installed in "C:Program FilesP H P". You do not need to use 8.3 format and you do not need the DLL nor PHP.INI to be in Windows directory.


  46. loralynne says:

    Hi David,

    A colleague of mine actually showed me the error that occurs after he manually entered the long path on Win XP.  He then changed it to 8.3, and it worked like a champ.  So unless we come up with a better solution, we might actually have to resort to this solution, and I figured out how to do this in the script.

    Thanks again for all your help.  I really appreciate your input.


  47. David.Wang says:

    loralynne – If you do not enter the long path correctly (from the UI or from the commandline), it will fail with a pretty bizarre error. I think that the older IIS Manager UI (W2K and WXP) actually require you to input a long path format that doesn’t work; it was subsequently fixed in WS03.

    The instructions and samples I gave on how to use long paths work on W2K, WXP, WS03, and Vista – I literally installed PHP, then typed in that commandline, and verified PHP’s phpinfo(); work with "%ProgramFiles%P H PPHP5isapi.dll" on all the platforms.

    You can certainly use 8.3 format if you need, but I am obligated to tell you that 8.3 will not work in any version of IIS after Windows XP due to security. All I can say is that suggestions to use 8.3 format as a "requirement" are incorrect.


  48. loralynne says:

    Hi David,

    The instructions and samples you gave work great and add the information to the metabase as expected.  However, our problem is that using the long path on XP doesn’t work.  If we don’t find a correct fix, we’re planning on using 8.3 format only on 2K and XP.  The long path works fine on Server 2003.

    Thanks for all your advice and taking the time to actually verify this on all the platforms.  I’ll relay this information to my colleague.


  49. David.Wang says:

    loralynne – when you say "our problem is that using the long path on XP doesn’t work", are you saying:

    1. Your version of PHP does not work with long pathnames

    2. Your PHP-based application does not work with long pathnames

    Because it is possible that the PHP-based application fails with long pathnames, and that would be an issue with that application.

    From my casual observation, PHP itself seems to work fine with long pathnames, and IIS can certainly invoke the PHP Application Mapping with long pathnames.

    One thing to remember with long pathnames and a CGI Application Mapping (i.e. php-cgi.exe) – you *may* need to enclose %s parameter in quotes to make sure spaces are properly escaped. This totally depends on the CGI.

    For example, when configuring CMD.EXE as an Application Mapping for .cmd in IIS (so that you can launch batch files via an HTTP request), you have to use:

     cmd.exe /c "%s" "%s"

    Or else it will fail if the resource has a long pathname.


  50. loralynne says:

    Hi David,

    My apologies.  I found out from my colleague (who ran your script) that the reason why the long path wasn’t working was because there were quotes around it.  In my first post (on 4/21), I asked about how I can add quotes around the path using your script since when I manually entered it via the GUI, it gave the error "wrong executable filename", until I put quotes around it.  So I assumed that PHP wouldn’t work if I ran your script to add the app mapping without quotes.

    I guess if you want to add an app mapping that has spaces in the path to the dll/exe, you’ll have to do it via a script since the GUI won’t let you without putting quotes around the path.

    Anyways, thanks again for all your help, and sorry for wasting your time on this.


  51. David Wang says:

    A short while ago, I came out with a small script to properly configure PHP for IIS7. Sure enough, I…

  52. millhouse50 says:

    I’ve been stuck on this issue for the past week now and it’s really driving me crazy. I need to know how to programmatically add/delete extensions in web directory when I create the web.

    What I mean is that if you open the IIS manager, then right click on the default web site, go down to properties and open that up. Then click on the home directory tab, and then hit the configuration button. There is a list of extensions there that I need to manipulate when I make the web site.

    I’ve found tons of examples and code, but I don’t know which one to use. Also I’m doing this all in vbscript. If you could provide me a sample, or show me to a little code snippit or something I would be VERY relieved.

    Thanks a ton in advance.

  53. David.Wang says:

    millhouse50 – this blog entry has the VBScript code as well as the sample commandline to do what you want.

    Please either take the necessary code snippet or determine your necessary commandline, or read the blog comments, to help yourself.


  54. David.Wang says:

    loralynne – Ah, I see. Yeah, long pathnames, quotes, and IIS Configuration can be confusing. Here’s the short summary:

    – IIS uses Application Mapping pathnames as long pathname and without need for quotes

    – The GUI in W2K/XP had a bug where it puts quotes around pathnames and then puts it into the Application Mapping. This usually happens when type a pathname with spaces into the GUI.

    – When you run a script, it is impossible to pass in quotes unless you use a different encoding; but you need to use quotes on the commandline to pass in spaces

    What this means is that when you set an IIS configuration value, you need to know what value IIS wants, and what each configuration tool will actually put into configuration. No safe-guards anywhere.


  55. loralynne says:

    Thanks for the summary, David!

  56. Pat says:

    Thanks for this script, i use before the Admin IIS 6.0 script iiscnfg.vbs for export and import the ScriptMaps, but the attribute was not exported with them. Only Export of the ScriptMaps when i edit the property before in MMC, bad!

    Now i use your script and i have integrate it to my deployment & building solution. Works fine.


  57. David.Wang says:

    Pat – it sounds like you are only exporting/importing settings on a per-Website basis, while many properties like ScriptMaps are inheriting from global values by default and do not show up per-Website. Thus, when you export, inheriting values are not there (so that you continue to re-inherit from global values on the destination machine).

    When you edit the property in MMC, it stops the inheritance and sets them on a per-Website basis, so it shows up on export.

    The problem you must resolve is that a website has many global settings on the source machine which are not exported/imported into the destination machine.


  58. Mert Sakarya says:

    Thanks for the code. I’m trying to do the samething with javascript.

    How can I modify LIST data type in IIS with javascript.

    I can convert LISTs with toArray function of javascript but I can’t put the updated value back!!!

  59. David.Wang says:

    Mert – Since you converted LISTs to JScript Array for modification, it makes sense that you must convert the JScript Array BACK INTO a VB SafeArray to put it back.

    This is one reason why I wrote the sample in VBScript – because LIST modification is simpler in VBScript.

    With JScript, I must convert LISTs from VBArray to JScript Array since VBScript cannot manipulate VBArray directly, manipulate it as JScript Array, then convert it back to VBArray to update the LIST data type.


  60. Mert Sakarya says:

    Than the question becomes;

    How can I create a VB Safe Array and modify it with JScript?

    Why I’m insisting on JScript is because, it is way much powerful than VBScript. You’ve got classes, try catch blocks, cool arrays,  interesting object notation like ( == obj["property"]) and also JSON 😉

    I am using HTA, Javascript, XMLHTTPRequest and JSON, JQuery in a Setup application, the possibilities are weird!!!

  61. Mert Sakarya says:

    Than the question becomes;

    How can I create a VB Safe Array and modify it with JScript?

    Why I’m insisting on JScript is because, it is way much powerful than VBScript. You’ve got classes, try catch blocks, cool arrays,  interesting object notation like ( == obj["property"]) and also JSON 😉

    I am using HTA, Javascript, XMLHTTPRequest and JSON, JQuery in a Setup application, the possibilities are weird!!!


  62. David Wang says:

    I recently got a question about how to manipulate the LIST data type within JScript since my sample code…

  63. David.Wang says:

    Mert – I suggest searching for code to manipulate VB Safe Array.

    It is possible to convert between VB Safe Array and JScript Array (both directions) to do the manipulation.


  64. Eric E says:

    Excellent Script!!!! I needed to remove some script mappings from our websites and this made it possible to do it programmatically.  Thanks!!!!

  65. Juan says:

    Removing a Wildcard application map removes all Cache ISAPI extensions, althought it used to work before enabling SSL (I don’t know it is related with the problem).

    Example: C:Inetpubchglist.vbs W3SVC/1/root/ScriptMaps "" "*,D:WWWdllsmyappMap.dll,0" /REMOVE /COMMIT

  66. Joe says:

    I’m trying to install a wildcard application mapping on every site on a server. If I invoke it like so:

       <script> W3SVCScriptMaps "" "*,wildcard.dll,1" /insert /recurse /commit

    …it successfully installs the map at the global server level, as specified, but it doesn’t recurse into the siges (e.g., W3SVC/1/root/ScriptMaps); instead it says:

       Ignoring inherited property for Recursive Modification

    It works the way I expect when I pass W3SVC/1/root/ScriptMaps (or similar), finding any overridden ScriptMaps settings in the subtree and adding my extension.

    Rather than simply change the code, I’d like to understand why you designed it this way. The obvious downside is that I have to know a priori which sites exist in the metabase (1, 2, 54241, etc), which means I need to manually enumerate them and invoke this script on each path. That doesn’t seem like the best way to do this.

    I realize this has been partially asked before, but I’d appreciate it if you could explain the concept, rather than simply the syntax.


  67. Okey_Dokey1 says:

    Question: We use your "ChgList.vbs" script (called in as an external script to run "command = "chglist.vbs") in one of our IIS 6 server scripts to perform "Script Map Deletion". What is the easiest way to turn this around in a secondary script used to not actually perform the action but just to verify if it has been performed in the main script or if the specific types of files exist (.cer, .cdx, and .idc). I am new at this and just trying to learn how to. Thanks.


  68. Andrew says:

    I just wanted to drop a quick thank you for the script. I needed a way to flick the ASP.NET Web Service Extensions on and off and this worked like a charm. Thank you David for the script, I appreciate it.

  69. Landho says:

    This is perfect.  Thanks so much…

  70. David.Wang says:

    Joe – the reason for "Ignoring inherited property for Recursive Modification" is because I do not want to make a recursive config change at a node that is already inheriting that property value from its parent.

    You can view "recurvise modification" as the same as "manual-override of property value inheritance".

    In other words, suppose you only had ScriptMaps set at W3SVC/ScriptMaps. This means all websites are already inheriting this value, so when you tell ChgList.vbs to recurse from W3SVC/ScriptMaps, it only makes sense to change W3SVC/ScriptMaps.

    If ChgList.vbs also modified W3SVC/1/ROOT/ScriptMaps, it would change W3SVC/1/ROOT/ScriptMaps to no longer inherit from W3SVC/ScriptMaps, a conceptual change. While this is no danger this initial time, any *future* edits to W3SVC/ScriptMaps will no longer automatically inherit to W3SVC/1/ROOT/ScriptMaps.

    Now, in your situation, you may choose to always remember to use /recursive so it does not matter, but not everyone has that luxury in their environment, nor will everyone remember to use /recursive.

    Thus, ChgList.vbs explicitly ignores inherited property on /recurse

    It would be completely different functionality to recursively edit all non-inherited values. You can get that functionality by stitching together ADSUTIL.VBS FIND to do that recursion and ChgList.vbs to do the edit of the LIST data type.


  71. David.Wang says:

    Okey_Dokey1 – To Verify that the action has been performed or if specific types of extensions exist, you can simply call ChgList.vbs without /commit

    <chglist.vbs> W3SVC/1/root/ScriptMaps ".idc" "***FOUND***""

    The output of the command will include ***FOUND*** if .idc is in any list entry of W3SVC/1/root/ScriptMaps . Just parse the output.


  72. I recently decided to experiment with hosting my own blog and after looking at the various packages available

  73. Peter Pojuner says:

    Brilliant – Works a treat for me !!

  74. renato tirone says:

    I love you David ! indeed ! thanks a lot .

  75. Dani says:

    Mr Wang,

    How do I do remove a specifc script mapping? Do I used putex command?

  76. Moe Sislak says:

    I am new to all of this, can you cut and paste the section of your code that adds the host headers?

    The reason being is for someone like myself it is sometimes hard to wade through all the error checking, etc

    All I need to see is the snippet of code that adds the host headers

    On a side note:

    Have you considered providing more examples using WMI?

  77. Ritz says:

    Hi David,

    I run PHP4 and PHP5 both on my IIS. I use following different mapping for them :

    PHP4 : C:phpphp.exe and for PHP5 : C:php5php-cgi.exe

    Now how can I list sites that are using PHP4 and PHP5 mapping respectively using this script.


  78. David.Wang says:

    Ritz – your specific task is best left to the reader.

    Hint: if you need to list sites, then you need to read the value of Script Mappings of IIS nodes. This script is all about editing/modifying Script Mappings, so I doubt it works for your scenario.

    I would use ADSUTIL.VBS to FIND all the ScriptMaps properties, then read them with ADSUTIL.VBS, and finally, parse the ScriptMaps entry to determine if PHP4 or PHP5 is installed the way you have it.


  79. David.Wang says:

    Moe – your specific task is best left to the reader.

    Basically, I am not allowed to write your code for you, including code snippets. You are free to take my existing code and reuse/modify as you wish.

    If you cannot wade through the code to find the necessary code snippet, then I suggest you use the entire source code to add the host header.


  80. David.Wang says:

    Dani – this tool illustrates how to remove a specific script mapping, so please read and follow the example.


  81. Frode says:

    Hi, I try to manipulate W3SVC/1/Root/DefaultDoc but I get an error message saying "Cannot handle W3SVC/1/ROOT/DefaultDoc with type string". I ran the following command:

    C:InetpubAdminScripts>cscript.exe chglist.vbs W3SVC/1/ROOT/DefaultDoc "" "index

    .php" /INSERT /COMMIT

    What is wrong?

  82. Chad says:

    Is there a simple way of adding the ability to target remote servers?  Like the adsutil.vbs "-s" switch for example.

    Thanks, great script.

  83. David.Wang says:

    Chad – Sorry, I designed it to target remote servers but forgot to expose a commandline parameter.

    You just need to change this line to take in a commandline parameter.

    strServer = "localhost"

    Add a little parsing, copying the existing code, and the rest should just work.


  84. David.Wang says:

    Frode – DefaultDoc stores multiple values in a single string with commas separating their values.

    Meanwhile, this script is for dealing with multiple values in a LIST.

    Thus, this script will not work for DefaultDoc, and it stops with that error appropriately.

    I know this all looks confusing because you probably just want to have one way to deal with all the different types of multi-value properties in IIS.

    Unfortunately, that was not my intent for the script. Otherwise I would have named the blog entry: "How to manipulate multi-value data types in IIS Configuration".

    Minor cases like DefaultDoc and MimeMaps can be handled, just not in this script.


  85. postrgrl says:

    Hi,  I am trying to use your script to remove an application mapping for an extension (home directory tab, configuration via the GUI).  Then I am trying to add a new mapping.  Really the ultimate goal, and the purpose of using the script is that we are changing where the dll files are stored from the e:content directory to the e:inetpub directory.  

    So, I ran:

    cscript chglist.vbs W3SVC/1156155428/root/ScriptMaps "" ".myext,e:contentmyappwls-iismyfile.dll,0" /REMOVE /COMMIT

    and was able to remove the .myext

    however when I try to insert one using the following:

    cscript chglist.vbs w3svc/1156155428/root/ScriptMaps "" ".myext,e:inetpubwwwrootmyappwls-iismyfile.dll,1" /INSERT /COMMIT

    I get a success message that says nothing to update.  In addition, there are no mappings added when looking in the GUI

    I also tried to run the insert command first, thinking that I could remove the duplicate extension later, but when I do this and then run the remove command it removes the newly created ext (which is the one I want to keep)

    What am I doing wrong?  I just want to remove on app mapping and add another (or edit the app mapping that is in there)

    I am on IIS6


  86. erdem ustun says:

    how to check iis web side is up or down? is there a script to  check all web sites and write a text file.

    is it possible to conrtol with vbs


  87. David.Wang says:

    erdem – please define what you mean by "if a web site is up or down".

    Suppose IIS is running perfectly, but DNS outage prevents users from locating and reaching your website, is the website up or down?

    Suppose one application on your website is functioning but another application on your website is failing, is the website up or down?

    Once you clearly define what you mean by "if a website is up or down", then one can always write a script to do what is necessary using any language of choice. It is only a matter of time and effort.


  88. David.Wang says:

    postrgrl – in the blog entry there are functioning examples of how to add, remove, and edit a LIST property.

    The tool has a very simple syntax where you specify "the text to match against" to produce an index into the desired LIST property, and once you have an index, whether to remove the item, replace the text, or insert at that index.

    Thus, your /REMOVE syntax does not do what you say. It is only removing the first scriptmapping at W3SVC/1156155428/root/ScriptMaps, no matter what it is. If you want to remove the .myext scriptmapping, then you need to provide ".myext" to match against, instead of "".

    Likewise, your /INSERT syntax does not do what you want. It finds index 0 as the first item that matches "" and attempts to insert after that item. And since your /REMOVE syntax removes the first scriptmapping, that’s why your removal of duplicates attempt does not work.

    The easiest thing for you to do is to change an existing item, documented in the blog entry.

    cscript chglist.vbs w3svc/1156155428/root/ScriptMaps ".myext" ".myext,e:inetpubwwwrootmyappwls-iismyfile.dll,1" /COMMIT

    The syntax looks for an entry with .myext and changes it to .myext,e:inetpubwwwrootmyappwls-iismyfile.dll,1

    Of course, if .myext does not already exist, this will do nothing.


  89. Jim Evans says:


    Your article is great and it looks like we have been beating this old, dead horse for years!!  😉

    I have been everywhere on the net trying to figure out how to add a custom extension via a VB.NET 2003 Setup project.  I know this is probably not your "forte", but do you have any idea how I can get this done?

    Thanks in advance,

    Jim Evans, MCAD

      and frustrated developer!

  90. Aécio Lemos says:


    You have no idea how much simpler you made my job! You rock! I have been hacking my brain to use WMI and such but stubled on the whole complicated MS authentication problems when trying to access a remote server (I need my scripts to create sites and DNS and such on several servers for my hosting company).  I have finished my control panel for clients now and it should be up and running next week after the testing stage.

    Ten thumbs up to you. Just bookmarked your site!

    Thanks a bunch.

    Aécio Lemos

    Curitiba, Brazil

  91. Prakash says:

    Is it possible to edit and update just the IP of a web site in an shared web server env.

  92. David.Wang says:

    Prakash – if you can modify the ServerBindings property then you can change the IP of a website in IIS with this tool.


  93. Aecio Lemos says:

    Just a quick fact for a quick laugh. If you type "chglist.vbs" in Google and search, it suggests CHRIST.vbs! So is this a holy script or what? Just thought I’d share! 😀

    Take care!


  94. Aecio Lemos says:

    I have run into a problem. I try to insert a record like this:

    C:windowssystem32cscript.exe C:InetpubAdminScriptschglist.vbs W3SVC/1110424359/ServerBindings LAST "" /INSERT /COMMIT

    It works fine. But then when I try to delete it like this:

    C:windowssystem32cscript.exe C:InetpubAdminScriptschglist.vbs W3SVC/1110424359/ServerBindings ""  /DELETE /COMMIT

    it deletes the entry, but I get a blank entry in the server bindings, which generates an error and stops the website. I can’t find an example of how to delete the bindings.

    What am I doing wrong?


  95. Aecio Lemos says:

    SORRY!!!! Wrong command. It is REMOVE and not DELETE. Sorry for the misunderstanding! It works now!

  96. Steve Livingston says:

    David you mentioned that we need to change the strServer = "localhost" line to take in commandline parameters if we wanted to make changes on remote servers.

    With the way I did it, I had to change another section of code  to ignore the additional commandline parameter as well as adjust the parameter count and parameter numbers now that I introduced the extra paramater.

    So here are the changes I made.

    ‘ changed from strServer = "localhost" so that the first paramater is the remote server name

    strServer = WScript.Arguments(0)

    strNamespace = "IIS://" & strServer

    strSchemaNamespace = strNamespace & "/" & "Schema"

    ‘ Parse the commandline

    ‘ Increased the WScript.Arguments.Count to check for from 3 to 4.

    If WScript.Arguments.Count < 4 Then


       HandleError "Insufficient number of arguments." & CRLF &_

                   CRLF &_

                   strHelp &_


    End If

    nOperationType = LIST_OPTION_REPLACE

    ‘Started the for loop to begin from the second parameter now that the first one is the name of the remote server (for i=1).  

    ‘Also increased the WScript.Argument numbers by 1.

    For i = 1 To WScript.Arguments.Count – 1

       Select Case UCase( WScript.Arguments( i ) )

           Case "/INSERT"

               nOperationType = nOperationType Or LIST_OPTION_INSERT

           Case "/REMOVE"

               nOperationType = nOperationType Or LIST_OPTION_REMOVE

           Case "/ALL"

               nOperationType = nOperationType Or LIST_OPTION_ALL

           Case "/RECURSE"

               nOperationType = nOperationType Or LIST_OPTION_RECURSE

           Case "/COMMIT"

               Debug = false

           Case "/VERBOSE"

               Verbose = true

           Case "/REGEXP"

               reMatch = true

           Case Else

               If ( i = 1 ) Then


                   ‘ Split out PropertyName and its ParentPath from PropertyPath



                   strNormalizedPath = NormalizePath( WScript.Arguments( 1 ) )

                   HandleError "Failed to normalize PropertyPath."

                   j = InstrRev( strNormalizedPath, "/", -1, 0 )

                   If ( j = 0 Or j = 1 ) Then

                       Err.Number = ERROR_PATH_NOT_FOUND

                       HandleError "Invalid PropertyPath."

                   End If


                   strPropertyPath = NormalizePath( Mid( strNormalizedPath, 1, j – 1 ) )

                   HandleError "Failed to retrieve/normalize PropertyPath."


                   strPropertyName = NormalizePath( Mid( strNormalizedPath, j + 1 ) )

                   HandleError "Failed to retrieve/normalize PropertyName."

               ElseIf ( i = 2 ) Then


                   ‘ The existing match value


                   strPropertyExistValue = Replace( UCase( WScript.Arguments( 2 ) ), "“", """" )

               ElseIf ( i = 3 ) Then


                   ‘ The new replace value


                   strPropertyNewValue = Replace( WScript.Arguments( 3 ), "“", """" )


                   Err.Number = ERROR_INVALID_PARAMETER

                   HandleError "Unknown parameter " & WScript.Arguments( i ) & CRLF &_

                               CRLF &_

                               strHelp &_


               End If

       End Select


  97. David.Wang says:

    Steve – your approach is one possible way. However, it introduces unnecessary positional-dependent parameters (i.e. your solution MUST pass in a server name for the first parameter, even though it is not necessary).

    My code uses a really quick and dirty commandline parsing routine, meant mostly for example/illustration.

    If I wanted to add server support on the commandline to this script, I would add a new switch case named "/SERVER", which sets strServer to the value of WScript.Arguments(i+1) (appropriately error checking against /SERVER without a follow-on parameter or /SERVER /COMMIT). And also move strNamespace and strSchemaNamespace assignments to after the commandline parsing for-loop. This would produce mostly code insertion, no modification of existing logic, and no positional-dependent parameters.


  98. T Fairweather says:

    Thanks very much for this script – works a treat.

  99. Brendan says:

    How do I use this if I don’t know the site idendifier?  I only know the site description.

    I had already managed to use IISWEB to add new sites to IIS but unfortunately, it appears that it can only add one host header.  I need to be able to also bid the site domain without the host header "www" prefix.

    Is there any way to query the site identifier # (via coldfusion) and then pass that value to your script?

  100. Jimmy Gilley says:

    Thanks for make the script David,

    I use it to insert wildcard Application maps into IIS websites.  But I am not sure how to remove or change the one that is already there.  

    Would love it if you could show me how or let me know if it is possible.

  101. David.Wang says:

    Brendan – you can use ADSUTIL.VBS FIND ServerComment to get all site descriptions and then filter through it to find the corresponding SiteID.

    If you create/use a dedicated script calling ADSI, it is pretty easy because CreateWebsite will return the SiteID as well as the Site Object, which allows you to do the other manipulation.

    If you use script tools, then you have to be creative and stitch them together.


  102. David.Wang says:

    Jimmy – this blog entry provides exact samples for how to remove or change the one that is already there.

    There are many possible variantions using this tool, but those are exercises to the reader. The source code is already provided, so the reader must figure out how to use the tool and support him/her self.


  103. spring yan says:

    thanks david, it help me to avoid the shortage of adsutil.vbs

  104. Tricky says:

    After much grinning, I found a script that would add *just* MIME types you want to add, *NON*-destructively. The original code was commented and formatted for a different purpose. I modified it specifically just to add Office 2007 MIME types and re-commented appropriately. You should be able to add MIME types easily by just simply replacing my Office 2007 MIME types with the ones you need. See

  105. Edward M says:

    David,  /INSERT option allows to add a value second to the last one in the LIST, but  how can I use this script to add new value to the end of the LIST?  I am trying to add new HTTPCustomHeader.  

    Than you.

  106. I have one issue while getting httperrors list.  I am getting the list of httpErrors but only for the type ‘FILE’.  Why I am not getting for the type’Default’?.  Somehow my 500 error code is set to ‘Default’ and I am not getting through ["HttpErrors"] property.  Any clue on that?

  107. Gary Wright says:


    I’ve been running this on a test rig fine with no problems.

    I call this in a script:

    cscript /nologo chglist.vbs W3SVC/1595303702/HttpErrors 404 404,*,URL,/index.shtml /commit

    However, if the HttpError has been changed manually through the GUI beforehand, it won’t make the change, although it does say it has been successful.

    Any ideas?



  108. Kevin Heathfield says:


    Fantastic work, you modified script work like a bomb.

    I am able to add and remove a (singular) application extension.




  109. 人过留声 says:

    王先生您好,我使用您的这个脚本 添加一项iaspi应用扩展,chglist.vbs W3SVC/ScriptMaps "" ".php,D:PHPphp5isapi.dll,5" /INSERT /COMMIT  只有主网站添加了这个扩展,而下面的网站都没有继承,请问有什么办法可以解决吗?

  110. Jon Breen says:

    This is a great piece of code and I'd love to use it. Is there a license attached to it? I don't wish to presume it can be used freely without your permission