Change the application pool associated with a web application in sharepoint.

Recently I researched on case where the SharePoint Service Pack 2 upgrade failed with the following exception.

[SPIisWebSiteWssSequence] [ERROR] [7/18/2009 11:13:56 PM]: Action 3.1.3.0 of Microsoft.SharePoint.Upgrade.SPIisWebSiteWssSequence failed.
[SPIisWebSiteWssSequence] [ERROR] [7/18/2009 11:13:56 PM]: The system cannot find the path specified.
[SPIisWebSiteWssSequence] [ERROR] [7/18/2009 11:13:56 PM]:    at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
   at System.DirectoryServices.DirectoryEntry.Bind()
   at System.DirectoryServices.DirectoryEntry.get_AdsObject()
   at System.DirectoryServices.PropertyValueCollection.PopulateList()
   at System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName)
   at System.DirectoryServices.PropertyCollection.get_Item(String propertyName)
   at Microsoft.SharePoint.Administration.SPIisApplicationPool.get_PeriodicRestartMemory()
   at Microsoft.SharePoint.Administration.SPProvisioningAssistant.EnableMemoryBasedAppPoolRecycling(SPIisApplicationPool local)
   at Microsoft.SharePoint.Administration.SPProvisioningAssistant.EnableMemoryBasedAppPoolRecycling(String applicationPoolId)
   at Microsoft.SharePoint.Upgrade.EnableMemoryBasedAppPoolRecycling.Upgrade()
   at Microsoft.SharePoint.Upgrade.SPActionSequence.Upgrade()

Looking at the call stack it was clear that SharePoint was trying to query the “PeriodicRestartMemory” setting of an application pool and that action failed with “The system cannot find the path specified”.

So the first step we did was check if any of the Application Pools used by SharePoint Web Applications were deleted in the recent past and for sure we got confirmation that there were some changes made. Few application pools were deleted manually through IIS Manager. The related Web Applications were then associated with a different Application Pool through IIS.

Now of course doing this does not change the association in SharePoint configuration. SharePoint does not provide a UI option to modify the Application Pool attached to a Web Application, you can use Object Model code to do it though.

So the solution here is to either recreate those Application Pools that were missing OR to update SharePoint configuration with the new association as per IIS setting.

Here is how you can do it.

Option 1:

Delete and recreate the web application using SharePoint. This will surely clear the orphan application pool entry.

Option 2:

1. Stop the “Windows SharePoint Services Web Application” service on the WFE. This step will remove all the application pools and web applications on that WFE.

2. Now restart the ‘Windows SharePoint Services Web Application’ service. This step will now recreate all the Web Applications and Applications Pools (including the missing ones) in IIS.

Please ensure you have a backup of the IIS metabase and the virtual directory folders as any customization here may be lost.

Options 3:

Finally we can use the object model to update the Application Pool association for every Web Application that points to a specific ‘deleted’ application pool. In an attempt to achieve this requirement, I wrote the below powershell script.

##############################################################################
## This script searches for all Web Applications using a specific application pool 'Old Application Pool' and updates it's property in SharePoint configuration to use a 'New Application Pool'
## USAGE:
## REQUIREMENT: Ensure the new application pool to be used is already registered in SharePoint. This happens when you create a new Web Application with a new Application pool.
## SYNTAX:      ChangeApplicationPool <old application pool name> <new application pool name>"
## NOTE:        Application pool name is case sensitive.
##############################################################################

# Define 2 parameters for this script
param([string] $oldAPName, [string] $newAPName)

# Check if both params are passed, else show Syntax.
if ($newAPName -eq "")
{
   "Syntax: ChangeApplicationPool <old application pool name> <new application pool name>"
   exit;
}

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Administration")

$WebService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService

## Get reference for the new application pool within the list of SharePoint objects
[Microsoft.SharePoint.Administration.SPApplicationPoolCollection] $appPools = $webService.ApplicationPools;
$newAppPool = $NULL;
foreach ($appPool in $appPools)
{
    if ($appPool.Name -eq $newAPName)
    {
        [Microsoft.SharePoint.Administration.SPApplicationPool]$newAppPool = $appPool;
    }
}

## If new application pool is not found, then give error and exit
if($newAppPool -eq $NULL)
{
    "ERROR: The New application pool to be assigned was not found within SharePoint!"
    "REQUIREMENT: Ensure the new application pool to be used is already registered in SharePoint. This happens when you create a new Web Application with a new Application pool."
    exit;
}

## Now loop through all Web Applications to find a match of the old Application pool and update it with New App pool.
[Microsoft.SharePoint.Administration.SPWebApplicationCollection] $webApps = $webService.WebApplications

"Searching through all Web Applications for Old Application pool - " + $oldAPName + " and changing it to - " + $newAPName
$count=0;
foreach ($webApp in $webApps)
{
    $webApp.DisplayName + " uses application pool " + $webApp.ApplicationPool.Name
    if($webApp.ApplicationPool.Name -eq $oldAPName)
    {
        $webApp.ApplicationPool = $newAppPool;   ## Changed to new Application pool reference.
        $webApp.Update();
        "............" + $webApp.DisplayName + " now uses the new application pool " + $webApp.ApplicationPool.Name
        $count = $count + 1;
    }
}
"Found and replaced " + $count + " web application(s)"

if($count -eq 0)
{
   "Syntax: ChangeApplicationPool <old application pool name> <new application pool name>"
   "Ensure the application pool name is an exact match"
}

########################################################################################################################

Disclaimer: The above code is provided "As Is". This is just a sample code and is not production ready.