PowerShell to Detect Web Configuration Modification jobs

Introduction

Over the past few months I have been working on some automated SharePoint deployment scripts using Team Foundation Server and the TFS build service. As the development became more complex so did the scripts. One of the problems we had to work around was activating a number of features at the same time.

The deployment reinstalls five SharePoint solution packages, uninstalling and reinstalling all of the Features which are packaged in the solutions. Now some of these features perform custom tasks using feature receivers. For example making changes to the web.config using SPWebConfigModfications. However, one of the problems with modifying web.config using feature receivers is that if they are run on a multi server SharePoint farm then the modifications are performed using a timer job.

When you try and activate two features, one after the other, which perform the web configuration modifications you get the following error message:-

"A web configuration modification is already running"

This kills the deployment script!

Thus we needed to find a way to detect whether a web configuration modification job is in progress.

Understanding the process was made more dificult as the development machine was part of a single server SharePoint farm. With single server farms, when aa SPWebConfigModification is applied to a SPWebApplication then the modification is executed in a different manner and occurs immediately.

Anyway, after some digging about using Reflector I found an SPJobDefinition which looked like the web config modification timer job and say down and wrote the following PowerShell script.

Solution

To be able to detect whether a web config modification is running we need to see if a timer job is active.

The timer job that performs the web config modification has the name “job-webconfig-modification”.

To detect whether a web configuration is pending or running.  As web configuration operations occur against a web application. Therefore using the SPWebApplication’s SPWebService property which has two collections relating to the timer service:-

  • JobDefinitions – this contains the jobs that are pending to be run
  • RunningJobs – this contains the jobs that are currently running

Detecting whether a web configuration modification is in progress, we need to check those two collections for our “job-webconfig-modification” timer job.

The following PowerShell function, IsWebConfigModificationJobPendingOrRunning, is used to check whether a Web Configuration operation is taking place. The function takes a SPWebApplication as a parameter and returns true if the web configuration modification operation is running.

 


################################################################################################
#Function: IsWebConfigModificationJobPendingOrRunning
#Description: Checks to see if a web configuration job is pending or in progress
################################################################################################
function IsWebConfigModificationJobPendingOrRunning([Microsoft.SharePoint.Administration.SPWebApplication] $webApp)
{
Write-Host "IsWebConfigModificationJobPendingOrRunning() Enter";

$bRunning=$false;
try
{
$webConfigPendingJobCount = 0;
$webConfigRunningJobCount = 0;

#if there is only one job returned then array is not created
$webConfigPendingJobs = $webApp.WebService.JobDefinitions |
Where-Object {$_.Name -like "*job-webconfig*"};
$webConfigRunningJobs = $webApp.WebService.RunningJobs
| Where-Object {$_.Name -like "*Web.Config*"};

#if there is only one job returned then array is not created - check to see if an object has been returned
#check to see if its an array if not then presume its a job.
if($webConfigPendingJobs -ne $null)
{
if($webConfigPendingJobs.GetType().BaseType.Name -eq "Array")
{
$webConfigPendingJobCount = webConfigPendingJobs.Count;
}
else
{
$webConfigPendingJobCount = 1;
}
}

#if there is only one job returned then array is not created - check to see if an object has been returned
#check to see if its an array if not then presume its a job.
if($webConfigRunningJobs -ne $null)
{
if($webConfigRunningJobs.GetType().BaseType.Name -eq "Array")
{
$webConfigRunningJobCount = webConfigRunningJobs.Count;
}
else
{
$webConfigRunningJobCount = 1;
}
}

Write-Host "Found " $webConfigPendingJobCount " Pending Jobs and " $webConfigRunningJobCount " Running Jobs";
if(($webConfigPendingJobCount -gt 0) -Or ($webConfigRunningJobCount -gt 0))
{
$bRunning=$true;
}
else
{
$bRunning=$false;
}
}
catch
{
Write-Error "IsWebConfigModificationJobPendingOrRunning Exception: $_ ";
}

Write-Host "IsWebConfigModificationJobPendingOrRunning() Exit : $bRunning";
return $bRunning;
}

 

Example Script

The script below shows part of the deployment script. This would be used  to loop through an array of feature names, check their scope and activate them. The script waits until the feature has activated and checks that there are no web configuration modification jobs running.

$SharePointWebApp = Get-SPWebApplication "http://sharepoint";
$spfeature = "Feature1";

$checkspfeatureactivation = Get-SPFeature -WebApplication $SharePointWebApp
-Identity $spfeature -ErrorAction SilentlyContinue;

if($checkspfeatureactivation -eq $null)
{
Write-Host "Activating Feature: " $spfeature.Name " Scope: " $spfeature.Scope;
Enable-SPFeature -Identity $spfeature -Url $SharePointWebApp.Url -Confirm:$false;

#check that web config job mod not running, wait if it is
do{
Start-Sleep -Seconds 2;
Write-Host "Waiting for Web Config Job to be Completed";
$configJobRunning = IsWebConfigModificationJobPendingOrRunning $SharePointWebApp;
}while ($configJobRunning);

}
else
{
Write-Host "Feature Already Activated: " $spfeature.Name " Scope: " $spfeature.Scope;
}

 

I hope that helps someone who is having similar problems, I hope to add a bit more about the deployment process that I have been developing in later blog posts.

Please leave comments if you need any help or there are any problems.

Here are the actual PowerShell scripts as txt files.

7 Comments

  1. You can convert a single value into an array by using @()

    e.g.
    $var = get-spsite
    foreach ($site in @($var)) {
    #do stuff
    }

    Reply

    1. Hi Rhys,
      Thanks for the tip, yes thats a very good point. That’s what I love about PowerShell you learn something new every day!

      Thanks for taking the time to post this I will update the script.

      Regards
      Simon

      Reply

  2. Hi Simon,

    First of all, thank you for your post ! It was very interesting and it helps me a lot !
    But I think you made a mistake in your powershell code.

    You wrote : if($webConfigRunningJobCount.GetType().BaseType.Name -eq “Array”)
    and I think you wanted to write : if($webConfigRunningJobs.GetType().BaseType.Name -eq “Array”)
    And the same for : if($webConfigRunningJobCount.GetType().BaseType.Name -eq “Array”)
    instead of : if($webConfigPendingJobs.GetType().BaseType.Name -eq “Array”)

    regards,
    Arnaud.

    Reply

    1. Hi Arnaud,
      Jeez you are right, thats very embarassing. Thank you for taking the time to point out the mistake. I think I know what I did here, I wanted to improve the names of the variables before posting the script. Should have know and tested it again before posting.

      Regards
      Simon

      Reply

  3. […] The approach documented above worked fine in my single-server development environment. As soon as we tried activating the feature in a multi-server farm test environment all sorts of issues occurred. This has been documented however and you can read about it in Jeremy Jameson’s post Waiting for SharePoint Web.config Modifications to Finish and Simon Doy’s post PowerShell to Detect Web Configuration Modification jobs. […]

    Reply

Thoughts? Comments about this post? Please leave them here..

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.