Managing Worker Processes and AppDomains in IIS 7 with WMI

by Tim Ammann

WMI scripting lets you manage worker processes and application domains (AppDomains) in IIS with relative ease. IIS worker processes are spawned by the Windows Process Activation Service (WAS) and executed by W3wp.exe. Worker processes can contain AppDomains that are typically created in response to a request for an .aspx page.

This article describes how to accomplish, with just a few lines of VBScript, the following tasks:

  • View the currently executing requests for a worker process
  • Get the state of all worker processes
  • Unload a specific AppDomain or all AppDomains
  • Display all AppDomains and their properties

First Steps

  1. Make sure IIS and scripting are enabled.

    a. If you are using Windows Vista, open Control Panel, Programs and Features, and then Windows Features. Under "Web Management Tools," select "IIS Management Scripts and Tools" to enable scripting. b. If you are using Windows ServerĀ® 2008, open Server Manager. Use the Add Roles Wizard to install the IIS Web server. On the Select Role Services page, in the Management Tools section, select "IIS Management Scripts and Tools."

  2. Run commands as administrator. To open an elevated Command Prompt window, click Start, point to All Programs, click Accessories, right-click Command Prompt, and then click Run as administrator. If you open a command shell as administrator, all applications that you run from that command shell will run as administrator.

  3. Save the script files in text format with a .vbs extension. They can be run at the command prompt by using the syntax "cscript.exe <scriptname>.vbs".

  4. Before you start, make a backup of the System32\inetsrv\config\applicationhost.config file with the AppCmd tool. The backup copy will enable you to restore IIS to its original state by just copying the original version over the later one. To make a backup, follow these steps:

    a. Open an elevated Command Prompt window.
    b. Type cd %Windir%\system32\inetsrv\ c.Type appcmd add backup backupName to back up the ApplicationHost.config file, where backupName is the name that you specify for the backup. A directory with the backup name that you specify will be created under the %Windir%\system32\inetsrv\backup directory. If you do not specify a name, appcmd will generate a directory name automatically using the current date and time.

Worker Processes

This section shows you how to retrieve the currently executing requests for each worker process on a Web server. You then learn how to display the each worker process PID, state, and the application pool to which it belongs.

Get Executing Requests

One exciting new feature of IIS is the ability to see the requests that are currently executing in a worker process. You can do this with the WorkerProcess.GetExecutingRequests method.

The WorkerProcess.GetExecutingRequests method reports in a snapshot manner the requests that were executing at the time that the method was run. Because most requests execute very quickly, it may not be easy for you to test the method manually with a Web browser. For this reason, you will create a Web page just for this purpose.

Use notepad to put the following text into a text file. Then, save the file by using the name Sleep.aspx.

<%  System.Threading.Thread.Sleep(30000)
Response.Write ("I'm finally finished...") %>

Put the Sleep.aspx file in the content directory of the default Web site: %systemdrive%\inetpub\wwwroot.

The Sleep.aspx file that you created forces the request for the Web page to take 30 seconds to execute. This will give you time to run a script that will show GetExecutingRequests in action.

The GetExecutingRequests method takes an empty array variable as an OUT parameter, which it then fills with HttpRequest objects. You can iterate through these requests to show the attributes for each request. The following script takes the HttpRequest object output and displays the current module, verb, host name, and URL for each request.

Copy the following script into notepad and save it with the filename GetRequests.vbs.

Set oWebAdmin = GetObject("winmgmts:root\WebAdministration")
Set oWorkerProcesses = oWebAdmin.InstancesOf("WorkerProcess")
     
For Each oWorkerProcess In oWorkerProcesses
    ' Place the requests queued for a process into an array variable.
    oWorkerProcess.GetExecutingRequests arrReqs
    
    ' Show the number of requests queued.
    If IsNull(arrReqs) Then
        WScript.Echo "No currently executing requests."

    Else
        ' Display the number of requests.
        WScript.Echo "Number of currently executing requests: " & _
            UBound(arrReqs) + 1
        WScript.Echo
  
        ' List the properties of each request.
        For Each oRequest In arrReqs
            WScript.Echo "Module: " & "[" & oRequest.CurrentModule & "]"
            WScript.Echo "Verb:" & "[" & oRequest.Verb & "]"
            WScript.Echo "HostName: " & "[" & oRequest.HostName & "]"
            WScript.Echo "Url: " & "[" & oRequest.Url & "]"
            WScript.Echo
        Next
    End If
Next

Open an elevated command prompt window and navigate to the directory in which you saved the GetRequests.vbs file.

Before you run the script, type http://localhost/sleep.aspx into the address bar of a Web browser. This will start the request execution and set the browser spinning for 30 seconds while it waits to render the Sleep.aspx page.

While the browser is still waiting to render the page, run the script by typing the following in the command prompt window you just opened:

Cscript.exe GetRequests.vbs

Sample Output

The output you see should resemble the following.

Number of currently executing requests: 2
Module: [ManagedPipelineHandler]
Verb:[GET]
HostName: [localhost]
Url: [/MyApp/]
Module: [ManagedPipelineHandler]
Verb:[GET]
HostName: [localhost]
Url: [/MyApp/default.aspx]

Getting the State of a Worker Process

The WorkerProcess object in the IIS WMI provider has a GetState method that reveals whether a worker process is starting, running, or stopping. WorkerProcess also has two properties that interest us here: ApplicationPool and PID. The ApplicationPool property represents the application pool to which the worker process belongs. The PID property contains the process ID that uniquely identifies the worker process.

You can use the following code to list each worker process PID and state, and its application pool. If no worker processes are running, the script will exit silently. Copy the code into notepad and save it with the filename GetState.vbs.

' Connect to the WMI WebAdministration namespace. 
Set oWebAdmin = GetObject("winmgmts:root\WebAdministration") 
       
' Get the worker process instances. 
Set oWorkerProcesses = oWebAdmin.InstancesOf("WorkerProcess") 
       
' Get the ID of each worker process in the application pool and report its status. 
For Each oWorkerProcess In oWorkerProcesses 
       
    ' Report the worker process state via the GetStateDescription helper function. 
    WScript.Echo "WorkerProcess " & oWorkerProcess.ProcessID & ": " & _ 
        GetStateDescription(oWorkerProcess.GetState) 
    WScript.Echo "Application Pool: " & oWorkerProcess.AppPoolName
    WScript.Echo 
Next 

' The helper function translates the return value into text. 
Function GetStateDescription(StateCode) 
    Select Case StateCode 
        Case 0 
            GetStateDescription = "Starting" 
        Case 1 
            GetStateDescription = "Running" 
        Case 2 
            GetStateDescription = "Stopping" 
        Case 3 
            GetStateDescription = "Unknown" 
       
        Case Else 
            GetStateDescription = "Undefined value." 
    End Select 
End Function

Open an elevated command prompt window and navigate to the directory in which you saved the GetState.vbs file. Run the script by typing the following in the command prompt window you just opened:

Cscript.exe GetState.vbs

Sample Output

Your output should resemble this:

WorkerProcess 1336: Running 
Application Pool: DefaultAppPool 
       
WorkerProcess 3680: Running 
Application Pool: Classic .NET AppPool 
       
WorkerProcess 1960: Running 
Application Pool: NewAppPool

Now that you have learned to use WMI scripting to reveal the secrets of worker processes, do the same for application domains.

AppDomains

The first time a request for an ASP.NET page is received, the IIS managed engine module creates an application domain (AppDomain) in memory. The AppDomain processes requests for aspx pages, or any page that uses managed code. Unloading and enumerating AppDomains by using WMI is easy, and this section shows you how to do both.

Unloading a Specific AppDomain

AppDomain unloading in IIS 7 and above works somewhat differently than in IIS 6.0. Whereas the IIS 6.0 AppUnload command unloaded out-of-process ASP applications, the IIS 7 and above AppDomain.Unload method unloads only ASP.NET application domains. The AppUnload functionality has disappeared because the IIS 5.0 compatibility mode that it supported is no longer present in IIS 7 and above.

To unload a specific AppDomain, you must be able to uniquely identify it. AppDomain objects have three key properties: ApplicationPath, ID, and SiteName. However, just one of these may be sufficient for your purposes.

Incidentally, the AppDomain ID property is not a number, but a path that looks like this:

/LM/W3SVC/1/ROOT

The "1" in the path listed is the Site ID (by default, 1 corresponds to the default Web site.) If you must generate a list of your server's AppDomains and their properties first, see the "Enumerating AppDomains" section later in this article.

The next script unloads the AppDomain called "Northwind." The script iterates through the available AppDomains until it finds the one with the matching ApplicationPath. Copy the code into notepad, replace "Northwind" with the AppDomain application path of your choice, and save the file with the name AppDomainUnload.vbs.

Open an elevated command prompt window and navigate to the directory in which you saved the AppDomainUnload.vbs file. Run the script by typing the following in the command prompt window you just opened:

Cscript.exe AppDomainUnload.vbs
Set oWebAdmin = GetObject("winmgmts:root\WebAdministration")
Set oAppDomains = oWebAdmin.ExecQuery("SELECT * FROM AppDomain")

' Unload only the Northwind application domain.
For Each oAppDomain In oAppDomains
    If oAppDomain.ApplicationPath = "/Northwind/" Then 
        oAppDomain.Unload
        Exit For 
    End If 
Next

Unloading All AppDomains

Unloading all AppDomains on a server is even easier: you simply retrieve them, iterate through them, and unload each in turn.

The following example unloads all application domains on an IIS Web server. Note how a simple WQL query (WQL is WMI's version of SQL) is used to retrieve the AppDomains.

Copy the code into notepad and save the file with the name AppDomainUnloadAll.vbs. Open an elevated command prompt window and navigate to the directory in which you saved the AppDomainUnloadAll.vbs file. Run the script by typing the following in the command prompt window you just opened:

Cscript.exe AppDomainUnloadAll.vbs
Set oWebAdmin = GetObject("winmgmts:root\WebAdministration")

' Get all the application domains on the Web server.
Set oAppDomains = oWebAdmin.ExecQuery("SELECT * FROM AppDomain")

' Unload all the application domains.
For Each oAppDomain In oAppDomains
    oAppDomain.Unload
Next

As an alternative to the WQL query syntax, you can use the WMI InstancesOf method, just as you did earlier with WorkerProcess:

Set oAppDomains = oWebAdmin.InstancesOf("AppDomain")

Enumerating AppDomains

You can display all currently running AppDomains and their properties by using an approach similar to that of the previous scripts. Here is a list of AppDomain properties:

  • ApplicationPath
  • Id
  • IsIdle
  • PhysicalPath
  • ProcessId
  • SiteName

The following script shows all properties for each AppDomain except the Physical Path property, but you can add this easily enough. For convenience, the script displays the key and run-time properties separately.

Copy the code into notepad and save the file with the name AppDomainProps.vbs. Open an elevated command prompt window and navigate to the directory in which you saved the AppDomainProps.vbs file. Run the script by typing the following in the command prompt window you just opened:

Cscript.exe AppDomainProps.vbs
'Connect to the WMI WebAdministration namespace
Set oWebAdmin = GetObject("winmgmts:root\WebAdministration")
Set oAppDomains = oWebAdmin.InstancesOf("AppDomain")
WScript.Echo "AppDomain Count: " & oAppDomains.Count
WScript.Echo 
ADCounter = 0
For Each oAppDomain In oAppDomains
    ADCounter = ADCounter + 1
    WScript.Echo "---- AppDomain " & ADCounter & " of " & _
                oAppDomains.Count & " ----" & vbCrLf
    WScript.Echo "[ Key properties ]"
    WScript.Echo "ID: " & oAppDomain.ID
    WScript.Echo "Site Name: " & oAppDomain.SiteName
    WScript.Echo "Application Path: " & oAppDomain.ApplicationPath
    WScript.Echo
    WScript.Echo "[ Run-time properties ]"
    WScript.Echo "Process ID: " & oAppDomain.ProcessID
    WScript.Echo "Is idle: " & oAppDomain.IsIdle
    WScript.Echo vbCrLf
Next

Sample Output

Your output should look like the following:

AppDomain Count: 3
---- AppDomain 1 of 3 ----
[ Key properties ]
ID: /LM/W3SVC/1/ROOT
Site Name: Default Web Site
Application Path: /

[ Run-time properties ]
Process ID: 3608
Is idle: False

---- AppDomain 2 of 3 ----
[ Key properties ]
ID: /LM/W3SVC/2/ROOT/ContosoApp
Site Name: ContosoSite
Application Path: /ContosoApp/

[ Run-time properties ]
Process ID: 3608
Is idle: True

---- AppDomain 3 of 3 ----
[ Key properties ]
ID: /LM/W3SVC/1/ROOT/Fabrikam
Site Name: Default Web Site
Application Path: /Fabrikam/

[ Run-time properties ]
Process ID: 2552
Is idle: False

Conclusion

This article showed some basic WMI scripting techniques for retrieving information about IIS worker processes and AppDomains. The WMI InstanceOf method and WQL queries were used to retrieve them. Here is a brief review of the tasks presented and the methods that were used:

  • View the currently executing requests for a worker process: WorkerProcess.GetExecutingRequests
  • Get the state of all worker processes: WorkerProcess.GetState
  • Unload a specific AppDomain or all AppDomains: AppDomain.Unload