IIS Configuration Woes with ADSI, WMI, and VBScript


You know, configuration of IIS can be quite confusing, with the various interfaces, paradigms, and programming languages. However, if you keep your wits about you, you can avoid the common pitfalls…


Question:


I need help with the following code. I’m trying to create an application pool to set as the default pool when I make a website. When I create my web site with this code the application pool is set to <Invalid App Pool>, but then in the drop down choice box the <DefaultAppPool> and my <MyCrazyAppPool> exist. I need to have <MyCrazyAppPool> set as the default though when the site is created, not <InvalidAppPool>.


All help is greatly appreciated. Thank you for your time.

Set objSite = objWMIService.Get(“IIsWebServerSetting='” & strSitePath & “‘”)
Set objVirtualDirectory = objWMIService.Get(“IIsWebVirtualDirSetting='” & strSitePath & “/ROOT'”)

‘ Application Pool Creation

strAppPool = “MyCrazyAppPool”
Set objAppPools = GetObject(“IIS://localhost/W3SVC/AppPools”)
Set objAppPool = objAppPools.Create(“IIsApplicationPool”, strAppPool)
objAppPool.SetInfo

‘ Assign the Pool to the Site
objVirtualDirectory.AppPoolID = strAppPool
objVirtualDirectory.AppFriendlyName = “me app”
objVirtualDirectory.SetInfo


Answer:


Actually, your code illustrates several common problems and misconceptions. Let me dissect them all and hopefully you see what you need to do to fix them.


Problem 1: ADSI vs WMI


Your script snippet actually uses two completely different programming paradigms, with non-interchangeable features and syntax, to configure IIS – ADSI and WMI.


strAppPool = “MyCrazyAppPool”
Set objAppPools = GetObject(“IIS://localhost/W3SVC/AppPools”)
Set objAppPool = objAppPools.Create(“IIsApplicationPool”, strAppPool)
objAppPool.SetInfo

The above snippet uses ADSI, as evidenced by the GetObject() function call using the IIS:// namespace. It is using generic ADSI Create() syntax to create a new Application Pool and then save it with the generic ADSI SetInfo() syntax. One reason ADSI modifications are not immediately persisted but allow batched persistence by SetInfo() is to give the programmer fine-control over the balance between performance and immediacy. If you want immediate persistence, then call SetInfo() yourself as frequently as you want; if you want batched behavior, batch and then call SetInfo().


Set objSite = objWMIService.Get(“IIsWebServerSetting='” & strSitePath & “‘”)
Set objVirtualDirectory = objWMIService.Get(“IIsWebVirtualDirSetting='” & strSitePath & “/ROOT'”)

‘ Assign the Pool to the Site
objVirtualDirectory.AppPoolID = strAppPool
objVirtualDirectory.AppFriendlyName = “me app”
objVirtualDirectory.SetInfo


The above code snippet uses WMI, as evidenced through the objWMIService being created against the root/MicrosoftIISv2 namespace (which you did not show but must have done). It is using the generic WMI Get() syntax to retrieve a vdir definition for the website. However, it is attempting to use the ADSI SetInfo() syntax to save the changes, which is not supported. WMI uses Put_() to save the changes.


The syntax error prevents your customization of AppPoolId from ever persisting.



  • One way to correct it is to use the correct WMI function to commit the change:

objVirtualDirectory.Put_()


  • The other way is to use ADSI (where strSitePath looks like “w3svc/1”):

objVirtualDirectory = GetObject( “IIS://localhost/” + strSitePath + “/ROOT” )

Problem 2: Error Checking


Now, we know that objVirtualDirectory is a WMI object, SetInfo() is an ADSI syntax, and the WMI object does not support the SetInfo() syntax and its execution should trigger an error that breaks the VBScript. However, your description indicates that you did not notice this syntax error at all – you noticed that the AppPoolId was not customized (because the syntax error prevented the change from persisting). Where did the syntax error go?


Well, you must have specified something like: On Error Resume Next somewhere earlier in the script in the applicable scope, which you did not show. This directive tells VBScript to silently ignore all errors, including the syntax error which prevented AppPoolId customization from persisting, and simply continue execution at the following statement. This leads to the script seemingly run to completion, yet the expected change did not happen. This is the classic problem of using “On Error Resume Next”.


Thus, it should be clear that if you EVER use “On Error Resume Next”, you need to diligently Clear and check the return code of the Err object after every function invocation to detect errors and handle errors yourself  Yes, it can be a hassle and make the code look ugly and complicated, but you have no choice – you need to write code without glaring bugs and flaws. You can make it look prettier and simpler by writing better error handling abstractions (or just using a language with better error handling semantics).


Sure, by adding “On Error Resume Next”, your VBScript stopped bailing execution due to errors, but just because code continues running does NOT mean that everything worked and the fatal errors masked by “On Error Resume Next” were ok. In reality, computers simply don’t know how to fix them, so they simply stay silently masked until you DO notice the problem (like the AppPoolId change failing to show up).


Conclusion


Yeah, this nasty masking of errors and general hassle in handling errors really bug me about VBScript. It’s all nice and easy assuming nothing bad happens, but when you need to do something REAL like handle real-world errors, you need to use “On Error Resume Next”. And at that point, I end up writing VBScript code that exactly mirrors defensive C/C++ style code… by which point I am really not scripting… and then I get annoyed with the language itself. But that’s another topic for another day. :-)


//David

Comments (5)

  1. Jerry says:

    I think a problem for a lot of C# developers is that all the MS examples for the configuration of IIS are written in vbscript (and very occassionally vb.net).

    There seem to be very few C# examples, which makes converting the stuff from vbscript to C# a real pain, as so much of it uses calls to getobject().

    I’ve never liked using scripts to install IIS, as it doesn’t allow the same degree of control or compile checking as a proper setup app. We’re currently converting our old VB app to C# and this stuff took us a long while to get fully tested as the code was quite a bit different and basically had to be worked out from scratch.

    The vb.net developers are fine of course, as they can pretty much use the same code, but I think it’s about time MS starting providing C# examples for these calls.

    Also, I think MS should really start emphasising a preferred method for configuring IIS and configuration of ALL products so that devs can get more familiar each time they use the technology. I’m guessing the preferred method is WMI due to the work we have done with configuring BizTalk, but I’m still not 100% sure which way MS would prefer us to be coding and what will be supported in future.

  2. Shak says:

    Hello David,

    Awesome work :) . I have a requirement where i need to get to a page and analyze what it returns. The page when browsed through IE is Blank and it is supposed to be blank. So i want to script the check that if it does not return blank or a 404/501 etc then its not working.

    So, in short how to make sure a web page is working the way its supposed to without reading the httperr log or something.

    I would really really appreciate if you could point me in the right direction and guide me a bit on this.

    Have a great day :)

    Shak

  3. Phil says:

    Help, does this code work in IIS 7.0?

    I use this same approach, and it works in IIS 6,  but when I run it on a win2008 64bit box, I get  an error,   800401E4   invalid syntax

    my code

    var appPools = GetObject("IIS://localhost/w3svc/AppPools");

    strAppPool = "MyCrazyAppPool"

    Set objAppPools = GetObject("IIS://localhost/W3SVC/AppPools")

    Set objAppPool = objAppPools.Create("IIsApplicationPool", strAppPool)

    objAppPool.SetInfo

  4. David.Wang says:

    Phil – it works on IIS7 if you install the IIS6 Metabase Compatibility component to support legacy scripting.

    //David

  5. karethea says:

    How do I fix error messages on my android phone I have failed to fix them help me please and fix it for me