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
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."
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.
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".
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.
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\backupdirectory. If you do not specify a name, appcmd will generate a directory name automatically using the current date and time.
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:
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:
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:
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.
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:
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:
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:
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")
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:
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:
'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
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
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