Cartographie des application pools au travers d’IIS, de Performance Monitor et du système/Mapping of the application pools across IIS, Performance Monitor and the System.


[MAJ 10/03/2017] Performance Monitor (ou PerfMon) est l’outil indispensable pour monitorer les performances de vos serveurs Windows. L’un des problèmes les plus fréquents avec Perfmon est d’identifier une instance particulière d’un processus. En effet PerfMon les numérotent de manière séquentielle (ici pour des worker processes IIS) : w3wp, w3wp#1, w3wp#2, w3wp#3 … Il est donc difficile de faire la correspondance avec un ID de processus (PID). Heureusement un workaround existe : https://blogs.technet.microsoft.com/askperf/2010/03/29/perfmon-identifying-processes-by-pid-instead-of-instance/.

Dans le cadre d’un serveur IIS, il ne nous reste plus qu’à faire le lien entre le PID et l’application concernée via le task manager (ou autres outil comme pslist, PowerShell).

Deux possibilités :

  • Pour le peu que l’on utilise l’identité par défaut depuis IIS 7.5 (cf. ApplicationPoolIdentity), il est alors facile de faire la correspondance (Identité = Nom de l’application pool – voire le nom du site web si celui ci a été créé via la console IIS) comme en atteste la capture d’écran ci-dessous:

applicationpoolidentity

  • Dans d’autres cas cela parait un peu plus compliqué 🙂

applicationpoolidentity2

Je vous propose dans cette article un script PowerShell (disponible ici) qui vous offrira un état des lieux comme celui-ci et sans devoir effectuer par le workaround précédemment évoqué (une solution universelle en somme) :

Get-W3WPData

On constate rapidement que :

  • Nous avons 6 applications réparties sur 5 sites (le site www.northwindtraders.com hébergent 2 applications : www.northwindtraders.com et www.northwindtraders.com/HR)
  • L’application pool www.northwindtraders.com est utilisé par les sites www.northwindtraders.com et intranet.northwindtraders.com
  • Le site www.contoso.com est configuré en mode « web gardening » et actuellement 2 worker processes prennent en charge les requêtes à destination de ce site.
  • Les colonnes PID et Instance  nous permettent de faire le lien entre les PID et les instances sous PerfMon. Dans le cas de la deuxième ligne le processus 1512 correspond à l’instance w3wp#1 et le processus 1520 correspond à l’instance w3wp#2 (l’ordre est préservé)

Ce script est aussi disponible dans le TechNet Script Center : https://gallery.technet.microsoft.com/Mapping-of-the-application-ee96fb1f


 

[Update 03/10/2017] Performance Monitor (or Perfmon) is the essential tool to monitor the performance of your Windows servers. One of the most common problems with Perfmon is to identify a particular instance of a process. Indeed PerfMon numbers them sequentially (here for the IIS worker processes): w3wp, w3wp # 1, w3wp # 2, # 3 w3wp … It is difficult to match a process ID (PID). Fortunately, a workaround exists: https://blogs.technet.microsoft.com/askperf/2010/03/29/perfmon-identifying-processes-by-pid-instead-of-instance/.

As part of an IIS server, it remains for us to make the connection between the PID and the relevant application via the task manager (or other tool like pslist, PowerShell).

 

Two possibilities :

  • If the default identity for IIS 7.5 (cf. ApplicationPoolIdentity) is used, it is easy to make the connection (ID = Name of the application pool – even the name of the website if it has created via the IIS console) as illustrated in the screenshot below:

applicationpoolidentity

  • In other cases it seems a little more complicated 🙂

applicationpoolidentity2

I propose in this article a PowerShell script (available here) that offers an inventory like this and without having to perform the previously mentioned workaround (an universal solution):

Get-W3WPData

We quickly found that:
  • We have 6 applications spread over 5 sites (The site www.northwindtraders.com hosts 2 applications www.northwindtraders.com and www.northwindtraders.com/HR)
  • The www.northwindtraders.com application pool is used by the www.northwindtraders.com and intranet.northwindtraders.com sites
  • The site www.contoso.com is configured for « web gardening » mode and 2 worker processes currently support queries to this site.
  • The PID and Instance columns allow us to make the connection between the PID and the instances in PerfMon. In the case of the second line the PID 1512 matches the instance w3wp#1 and the PID 1250 matches the instance w3wp#2 (the order is preserved)

The script file is available at the TechNet Script Center repository, at: https://gallery.technet.microsoft.com/Mapping-of-the-application-ee96fb1f

 

#requires -version 4 -Module WebAdministration Import-Module -Name WebAdministration #Region Function definition <#Get the pair Instance, PID for the running worker processes from Performance Data Collection Instance PID -------- --- w3wp#6 4504 w3wp#5 5848 w3wp#4 5088 w3wp#3 5520 w3wp#2 3884 w3wp#1 5476 w3wp 5964 #> function Get-W3WPDataFromPerformanceMonitor { [CmdletBinding()] Param() #Returned results will be stored into this array $Data = @() #Regular expression pattern to find the instance name in the counter path $Pattern = @([regex]'^.*\((?<INSTANCE>(.*))\).*$') #Get Path a,d PID from running worker processes from Performance Monitor $Counters = Get-Counter -Counter '\Process(w3wp*)\ID Process' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty CounterSamples | Select-Object -Property CookedValue, Path #Processing the returned collection foreach ($CurrentCounter in $Counters) { #Regular expression matching to keep only the instance name (for instance: w3wp#1) $CurrentMatches = $CurrentCounter.Path | Select-String -Pattern $Pattern | Select-Object -ExpandProperty matches if ($CurrentMatches) { #Getting the instance name (for instance: w3wp#1) $CurrentInstance = $CurrentMatches.Groups[$currentMatches.Groups.Count-1].Value #Creating an object with the instance name and the path $CurrentData = New-Object -TypeName PSObject -Property @{ PID = $CurrentCounter.CookedValue Instance = $CurrentInstance } #Storing the object into the array $Data += $CurrentData } } #Returning the data return $Data } <#Get the link between the applications, the sites and the site ids from ServerManager Applications Site SiteId ------------ ---- ------ {Default Web Site/} Default Web Site 1 {www.contoso.com/} www.contoso.com 2 {www.northwindtraders.com/, www.northwindtraders.com/HR} www.northwindtraders.com 3 {www.microsoft.com/} www.microsoft.com 4 {intranet.northwindtraders.com/} intranet.northwindtraders.com 5 #> function Get-WebsitesFromServerManager { [CmdletBinding()] Param() #Loading the Web Administration DLL for handling ServerManager #$null = [System.Reflection.Assembly]::LoadFrom( "$env:systemroot\system32\inetsrv\Microsoft.Web.Administration.dll" ) Add-Type -Path "$env:systemroot\system32\inetsrv\Microsoft.Web.Administration.dll" #Creating a ServerManager Object $ServerManager = New-Object -TypeName Microsoft.Web.Administration.ServerManager #Getting applications and related sites and site ids. $WebApplications = $ServerManager.sites | Select-Object -Property Applications, @{ Name = 'Site' Expression = { $_.Name } }, @{ Name = 'SiteId' Expression = { $_.Id } } #Return them return $WebApplications } <#Get the pair ApplicationPoolName, PID for the running worker processes from Web Configuration ApplicationPoolName PID ------------------- --- DefaultAppPool 5964 HR 5476 www.contoso.com 3884 www.northwindtraders.com 5520 www.microsoft.com 5088 www.contoso.com 5848 www.contoso.com 4504 #> function Get-W3WPDataFromWebConfiguration { return Get-WebConfiguration system.applicationHost/applicationPools/workerProcesses/* | Select-Object -Property @{Name="ApplicationPoolName"; Expression={$_.appPoolName}}, @{Name="PID"; Expression={$_.ProcessId}} } <#Get the data by using the 3 previous functions to have a clear overview of the hosted web applications Instance ApplicationPool SiteId Site Application PID W3SVCPath -------- --------------- ------ ---- ----------- --- --------- {w3wp} DefaultAppPool 1 Default Web Site Default Web Site/ {5964} _LM_W3SVC1_ROOT {w3wp#2, w3wp#5, w3wp#6} www.contoso.com 2 www.contoso.com www.contoso.com/ {3884, 5848, 4504} _LM_W3SVC2_ROOT {w3wp#3} www.northwindtraders.com 3 www.northwindtraders.com www.northwindtraders.com/ {5520} _LM_W3SVC3_ROOT {w3wp#1} HR 3 www.northwindtraders.com www.northwindtraders.com/HR {5476} _LM_W3SVC3_ROOT_HR {w3wp#4} www.microsoft.com 4 www.microsoft.com www.microsoft.com/ {5088} _LM_W3SVC4_ROOT {w3wp#3} www.northwindtraders.com 5 intranet.northwindtraders.com intranet.northwindtraders.com/ {5520} _LM_W3SVC5_ROOT #> function Get-W3WPData { [CmdletBinding()] Param() #the pair Instance, PID for the running worker processes from Performance Data Collection $W3WPDataFromPerformanceMonitor = Get-W3WPDataFromPerformanceMonitor #Getting the pair ApplicationPoolName, PID for the running worker processes from WMI #$W3WPDataFromWebConfiguration = Get-W3WPDataFromWMI $W3WPDataFromWebConfiguration = Get-W3WPDataFromWebConfiguration #Getting the link between the applications, the sites and the site ids from ServerManager $WebsitesFromServerManager = Get-WebsitesFromServerManager #Returned results will be stored into this array $Data = @() #Hastable to get the worker process instance (from performance monitor) by using the PID as a key $W3WPDataFromPerformanceMonitorHT = $W3WPDataFromPerformanceMonitor | Group-Object -Property PID -AsHashTable -AsString #Processing each website foreach ($CurrentWebsite in $WebsitesFromServerManager) { #Processing each application for the processed website (from ServerManager) foreach ($CurrentWebApplication in $CurrentWebsite.Applications) { #Creating an object with the application, the website, the website id, the application pool name, the pids (can be multiple in case of web gardening) and the instances (can be multiple in case of web gardening) from performance monitor $ApplicationData = New-Object -TypeName PSObject -Property @{ Application = $($CurrentWebsite.Site+$CurrentWebApplication.Path) Site = $CurrentWebsite.Site SiteId = $CurrentWebsite.SiteId ApplicationPool = $CurrentWebApplication.ApplicationPoolName PID = @() Instance = @() } #Processing each worker process from data coming from WMI foreach ($CurrentW3WPData in $W3WPDataFromWebConfiguration) { #If the application pools are matching between the WMI and ServerManager data if ($ApplicationData.ApplicationPool -eq $CurrentW3WPData.ApplicationPoolName) { #Adding the PID to the PID collection $ApplicationData.PID += $CurrentW3WPData.PID #Adding the worker process instance to the worker process instance collection $ApplicationData.Instance += $W3WPDataFromPerformanceMonitorHT[$CurrentW3WPData.PID -as [string]].Instance #The PID and the associated instance are stored in the same order into the two differents collections } } #region Generating the W3SVC Path under the form _LM_W3SVC<ID>_ROOT[_APPLICATION] like _LM_W3SVC3_ROOT_HR $W3SVCPath = $ApplicationData.Application.Substring($ApplicationData.Application.IndexOf('/')+1) $W3SVCPath = $W3SVCPath -replace '/', '_' if ($W3SVCPath) { $W3SVCPath = '_LM_W3SVC' + $ApplicationData.SiteId + '_ROOT_'+ $W3SVCPath } else { $W3SVCPath = '_LM_W3SVC' + $ApplicationData.SiteId + '_ROOT' } $W3SVCPath = $W3SVCPath.ToUpper() #endregion #Adding the W3SVC Path as a property of the object we have previously created $ApplicationData | Add-Member -MemberType NoteProperty -Name 'W3SVCPath' -Value $W3SVCPath #Storing the object into the array $Data += $ApplicationData } } #Returning the data return $Data } #endregion Clear-Host $Data = Get-W3WPData $Data | Format-Table -Property * -Force -AutoSize
Laurent.
Comments (0)

Skip to main content