使用 WMI 管理 IIS 7 中的工作进程和 AppDomain
作者:Tim Ammann
借助 WMI 脚本,可以相对轻松地在 IIS 中管理工作进程和应用程序域 (AppDomain)。 IIS 工作进程由 Windows 进程激活服务 (WAS) 生成,由 W3wp.exe 执行。 工作进程可以包含通常为响应 .aspx 页请求而创建的 AppDomain。
本文介绍了如何只编写几行 VBScript 代码来完成以下任务:
- 查看工作进程中当前正在执行的请求
- 获取所有工作进程的状态
- 卸载特定 AppDomain 或所有 AppDomain
- 显示所有 AppDomain 及其属性
前几个步骤
确保已启用 IIS 和脚本。
a. 如果使用 Windows Vista,请依次打开“控制面板”、“程序和功能”,然后打开“Windows 功能”。 在“Web 管理工具”下,选择“IIS 管理脚本和工具”以启用脚本。 b. 如果使用的是 Windows Server® 2008,请打开“服务器管理器”。 使用“添加角色向导”安装 IIS Web 服务器。 在“选择角色服务”页上的“管理工具”部分中,选择“IIS 管理脚本和工具”。
请以管理员身份运行命令。 若要打开提升的命令提示符窗口,请单击“开始”、指向“所有程序”、单击“附件”、右键单击“命令提示符”,然后单击“以管理员身份运行”。 如果你以管理员身份打开命令 shell,则从该命令行管理程序运行的所有应用程序都将以管理员身份运行。
以文本格式保存脚本文件,用 .vbs 扩展名保存。 可以使用语法“cscript.exe <scriptname.vbs>”在命令提示符下运行这些脚本文件。
开始前,请使用 AppCmd 工具备份 System32\inetsrv\config\applicationhost.config 文件。 有了备份副本,只需复制原始版本即可将 IIS 还原到其原始状态。 若要进行应用,请执行以下步骤:
a. 打开提升的命令提示符窗口。
b. 键入cd %Windir%\system32\inetsrv\
c.Type appcmd add backup backupName 来备份 ApplicationHost.config 文件,其中 backupName 是为备份指定的名称。 将在目录下创建一个具有备份名称的%Windir%\system32\inetsrv\backup
目录。 如果未指定名称,appcmd 将使用当前日期和时间自动生成目录名称。
工作进程
本部分介绍如何检索 Web 服务器上每个工作进程当前正在执行的请求。 然后,了解如何显示每个工作进程 PID、状态以及所属于的应用程序池。
获取正在执行的请求
IIS 有一项新功能非常吸引人,那就是能够查看当前正在工作进程中执行的请求。 可以使用 WorkerProcess.GetExecutingRequests 方法来查看。
WorkerProcess.GetExecutingRequests 方法以快照方式报告在运行该方法时正在执行的请求。 由于大多数请求的执行速度都非常快,因此可能很难使用 Web 浏览器来手动测试该方法。 要进行测试,你需要创建一个网页。
使用记事本将以下文本粘贴到文本文件中。 然后,将文件另存为 Sleep.aspx。
<% System.Threading.Thread.Sleep(30000)
Response.Write ("I'm finally finished...") %>
将 Sleep.aspx 文件放在默认网站的内容目录中:%systemdrive%\inetpub\wwwroot
。
你创建的 Sleep.aspx 文件会强制请求网页执行 30 秒。 这样你就有时间来运行一个脚本,该脚本将显示执行中的 GetExecutingRequests。
GetExecutingRequests 方法采用空白数组变量作为 OUT 参数,然后用 HttpRequest 对象填充该变量。 可以循环访问这些请求以显示每个请求的属性。 以下脚本采用 HttpRequest 对象输出,并显示每个请求的当前模块、谓词、主机名和 URL。
将以下脚本复制到记事本,然后另存为 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
打开提升的命令提示符窗口并导航到保存 GetRequests.vbs 文件的目录。
在运行脚本之前,请在 Web 浏览器的地址栏中键入 http://localhost/sleep.aspx
。 这将启动请求执行,并将浏览器设置为在等待呈现 Sleep.aspx 页面的过程中旋转 30 秒。
当浏览器仍在等待呈现页面时,请在刚刚打开的命令提示符窗口中键入以下内容来运行脚本:
Cscript.exe GetRequests.vbs
示例输出
你看到的输出应如下所示。
Number of currently executing requests: 2
Module: [ManagedPipelineHandler]
Verb:[GET]
HostName: [localhost]
Url: [/MyApp/]
Module: [ManagedPipelineHandler]
Verb:[GET]
HostName: [localhost]
Url: [/MyApp/default.aspx]
获取工作进程的状态
IIS WMI 提供程序中的 WorkerProcess 对象具有 GetState 方法,用于显示工作进程是启动、运行还是停止。 WorkerProcess 还有两个属性需要注意:ApplicationPool 和 PID。 ApplicationPool 属性表示工作进程所属的应用程序池。 PID 属性包含用于唯一标识工作进程的进程 ID。
可以使用以下代码列出每个工作进程 PID 和状态及其应用程序池。 如果未运行任何工作进程,脚本将以无提示方式退出。 将代码复制到记事本,并将其另存为 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
打开提升的命令提示符窗口并导航到保存 GetState.vbs 文件的目录。 要运行脚本,可在刚刚打开的命令提示符窗口中键入以下内容:
Cscript.exe GetState.vbs
示例输出
输出应该与下面的内容类似:
WorkerProcess 1336: Running
Application Pool: DefaultAppPool
WorkerProcess 3680: Running
Application Pool: Classic .NET AppPool
WorkerProcess 1960: Running
Application Pool: NewAppPool
现在,你已了解如何使用 WMI 脚本来揭示工作进程的机密,请对应用程序域执行相同的操作。
AppDomain
首次收到对 ASP.NET 页的请求时,IIS 托管引擎模块会在内存中创建应用程序域 (AppDomain)。 AppDomain 处理 aspx 页面的请求,或是处理使用托管代码的任何页面。 使用 WMI 卸载和枚举 AppDomain 非常简单,本部分介绍如何同时执行此操作。
卸载特定 AppDomain
在 IIS 7 及更高版本中卸载 AppDomain 与在 IIS 6.0 中略有不同。 IIS 6.0 AppUnload 命令卸载进程外 ASP 应用程序时,IIS 7 及更高版本的 AppDomain.Unload 方法仅卸载 ASP.NET 应用程序域。 AppUnload 功能已消失,因为 IIS 7 及更高版本中已经不存在该功能支持的 IIS 5.0 兼容模式。
若要卸载特定的 AppDomain,必须能够唯一标识。 AppDomain 对象具有三个关键属性:ApplicationPath、ID 和 SiteName。 但其中任何一个都足以实现你的目的。
顺便说一句,AppDomain ID 属性不是数字,而是如下所示的路径:
/LM/W3SVC/1/ROOT
列出的路径中的“1”是站点 ID(默认情况下,1 对应于默认网站)。如果必须先生成服务器的 AppDomain 及其属性的列表,请参阅本文后面的“枚举 AppDomain”部分。
下一个脚本将卸载名为“Northwind”的 AppDomain。该脚本循环访问可用的 AppDomain,直至找到具有匹配 ApplicationPath 的 AppDomain。 将代码复制到记事本中,将“Northwind”替换为所选的 AppDomain 应用程序路径,并将该文件另存为 AppDomainUnload.vbs。
打开提升的命令提示符窗口并导航到保存 AppDomainUnload.vbs 文件的目录。 要运行脚本,可在刚刚打开的命令提示符窗口中键入以下内容:
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
卸载所有 AppDomain
在服务器上卸载所有 AppDomain 更容易:只需检索、循环访问,然后依次卸载。
以下示例卸载 IIS Web 服务器上的所有应用程序域。 请注意,如何使用简单的 WQL 查询(WQL 是 WMI 的 SQL 版本)来检索 AppDomain。
将代码复制到记事本,然后将文件另存为 AppDomainUnloadAll.vbs。 打开提升的命令提示符窗口并导航到保存 AppDomainUnloadAll.vbs 文件的目录。 要运行脚本,可在刚刚打开的命令提示符窗口中键入以下内容:
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
作为 WQL 查询语法的替代方法,您还可以使用 WMI InstancesOf 方法,就像之前使用 WorkerProcess 一样:
Set oAppDomains = oWebAdmin.InstancesOf("AppDomain")
枚举 AppDomain
可以使用与前面的脚本类似的方法显示当前运行的所有 AppDomain 及其属性。 下面是 AppDomain 属性的列表:
- ApplicationPath
- Id
- IsIdle
- PhysicalPath
- ProcessId
- SiteName
以下脚本显示每个 AppDomain 的所有属性,但未显示 PhysicalPath 属性,但你可以轻松添加此属性。 为方便起见,脚本单独显示密钥和运行时属性。
将代码复制到记事本,然后将文件另存为 AppDomainProps.vbs。 打开提升的命令提示符窗口并导航到保存 AppDomainProps.vbs 文件的目录。 要运行脚本,可在刚刚打开的命令提示符窗口中键入以下内容:
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
示例输出
您的输出应该如下所示:
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
结束语
本文介绍了一些基本的 WMI 脚本技术,用于检索有关 IIS 工作进程和 AppDomain 的信息。 WMI InstanceOf 方法和 WQL 查询用于检索它们。 下面简要回顾了呈现的任务以及所使用的方法:
- 查看当前正在执行的工作进程请求:WorkerProcess.GetExecutingRequests
- 获取所有工作进程的状态:WorkerProcess.GetState
- 卸载特定 AppDomain 或所有 AppDomain:AppDomain.Unload