Automated Consolidation of Application Pools
SharePoint leverages IIS, and runs within Application Pools. One should recognize up front that there are two distinct categories of Application Pools used in SharePoint; Web Application pools and Service Application Pools.
Overview
Application Pools consume an estimated 80-100MB RAM each, and possibly a lot more, depending on usage. These appear as w3wp.exe processes in Task Manager. When you have a number of w3wp processes running, it can be hard to tell them apart; which is for a given web or service application? Here’s a way to get the PID (Process ID) for each worker process, along with the user-friendly name, so you can correlate each w3wp process:
c: cd C:WindowsSystem32inetsrv appcmd.exe list wp [/sourcecode ] A nice listing of Web Application Pools is generated by this single command. It ensures the fields are not truncated, and is extensible to allow display of any properties/columns you wish: |
[sourcecode language="powershell"] get-SPWebApplication | select displayname, url, applicationpool | format-table -autosize | out-string -width 2000 [/sourcecode ] Note the CmdLet "get-SPWebApplication". For Service Application Pools, the CmdLet is "Get-SPServiceApplicationPool", as in: [sourcecode language="powershell"] Get-SPServiceApplicationPool | select Id, Name, DisplayName, processaccountname [/sourcecode ] |
Within IIS, the Service Application Pools are identified by GUID. Their mapping can be explored individually by examining the application pool binding, but this is a bit laborious.
Removing a Service Application Pool
To remove a Service Application Pool by name, you can use: [sourcecode language=”powershell”] Remove-SPServiceApplicationPool -Identity “Your Orphaned SharePoint Service Application Pool Name”
[/sourcecode ]
My own preference is to first consolidate the application pools, then in IIS quiesce the desired application pools, and only once things are truly running smoothly, they can be removed. It is important to do the removing and adding in PowerShell and not directly in IIS. This will ensure that the correct IIS configuration gets propagated to all current and future WFEs (Web Front Ends).
Consolidating Web Application Pools programmatically
Consolidating Web Application Polls is quite easy. If you do not have security driven segregation of Application Pools, you can consider doing so. Note I have received conflicting advice on doing this. Todd Klindt who I hold in the highest regard recommends considering consolidation. Microsoft does advise quite a low maximum number of Application Pools, yet their support staff have advised segregation.
First let’s grab an existing Application Pool, and simply reassign it to the target Web Application Pool:
[sourcecode language="powershell"] $sourceWebAppPool = (Get-SPWebApplication < URL of a webapp whose application pool you want to use>).ApplicationPool $webApp = Get-SPWebApplication < URL of the web application you want to change> $webApp.ApplicationPool = $sourceWebAppPool $webApp.ProvisionGlobally() $webApp.Update() |
iisreset
Lather, rinse, and repeat for each of your Web Apps to be consolidated…
Note that there is no SharePoint CmdLet for creating an Application Pool. You can use the IIS CmdLet, but I am not convinced this is a safe method, as right away I can see the service account is an IIS Service Identity reference, and the application pools have a different type and cannot be assigned to a web application directly. here’s the CmdLet for reference:
Import-Module WebAdministration
$appPool = New-WebAppPool “My new App Pool”
[/sourcecode ]
If you need to segregate previously consolidated web application application pools, the following round-about procedure is safe and works:
- Create a brand new temporary Web Application and associated pool
- Reassign your target web app’s pool, as described above
- Destroy the temporary Web Application
The sequence is key. If you destroy the temporary web application, the associated pool is destroyed with it, because there are no other associated applications. In contrast, once you assign a second web application to this new application pool, the application pool will not be destroyed when the temporary web application is removed.
Consolidating Service Application Pools programmatically
On some farms I’ve inherited, there is a profusion of unnecessary Service Application Pools. Note there are reasons to isolate distinct service application pools, generally around security and multi-tenancy.
I wanted to consolidate my Service application pools but in a safe and programmatic manner. While you can change the account associated with a service application, there is the risk that the new service account won’t quite have the necessary access. When SharePoint does automatically grant access to the new service account, it won’t remove access from the original service account. Lastly, one needs to make sure the new service account is configured as a managed account. Lastly, SharePoint doesn’t support managed service accounts for all service applications. Exceptions do include the User Profile Service ADSync account, unattended user accounts (Excel, Visio, PerformancePoint), search crawl accounts (Foundation, Enterprise, and FAST), and the two Object Cache Portal Accounts (which are configured for each Web Application for performance reasons).
Not every Service Application runs under an Application Pool; some run under the Farm’s pool, and hence can’t be directly reassigned. Farm-wide service applications have one and only one instance in the farm. So the Security Token Service Application, Web Usage Application (WS_UsageApplication), State Service and Application Registry Service Application don’t run under their own Application Pools, and their CmdLets are simpler. So while one can create multiple Session State Service Applications and corresponding databases, there’s only one State Service Application. The script below lists them by name in an array and makes sure not to even try to remap these. For good measure I include the FAST Content Service Application in this category. Note yours may be named differently.
Next, I wanted to start with a clean Service Application Pool named clearly denoting the desired service account.
$MyRefAppPool=new-spserviceapplicationpool -name “SPService Service Application Pool” -account “YourDomainspservice” $SPaps = get-spserviceapplication for ($i=0;$i -lt $SPaps.Count; $i++) { $SPap = $SPaps[$i]; #Some service applications run at the farm level and don’t have selectable application pools, hence is it wiser to filter these out up front. if (@(“SecurityTokenServiceApplication”,”Application Registry Service “,”FASTContent”,”State Service”,”WSS_UsageApplication”,””) -notcontains $SPAP.DisplayName) { try { $testAppPool=$SPAp.get_applicationpool(); #Don’t mix & match the application pools and accounts, best is to consolidate along the lines of existing process accounts, to avoid permissions issues if ($testAppPool.ProcessAccountname -eq $MyRefAppPool.processaccountname) { write-host “Processing $($SPAp.name) because it has the target process account: $($MyRefAppPool.processaccountname)” $SPAp.set_applicationpool($MyRefAppPool) $SPAp.update() #update() is actually required. You will notice a processing delay during the update } else { write-host “Skipping $($SPAp.name) because it has a different process account: $($SPAp.get_applicationpool().ProcessAccountname)” } } catch { $testAppPool=$null; write-host “Skipping $($SPAp.name) because it had an error” } } } [/sourcecode ] |
An IISReset at this point is advisable. Lastly, you can go into IIS after running this, view Application pools, and “Stop” the GUID named Application Pools with zero associated Applications. Another IISReset is advisable to ensure you are recovering your RAM.
For a more general overview of Application Pool configuration, please see TechNet.
2 thoughts on “Consolidation of Application Pools”
Leave a Reply
Want to talk?
Drop us a line. We are here to answer your questions 24*7.
Hi there,
Just wanted to let you know that I get an error when running this script. It says it’s missing a closing curly bracket “}”
Once I added a line with the final bracket it worked great – thank you!
Thanks David! I will correct script shortly. I must have had a typo when redoing it for public consumption.
joel