Roundup: SharePoint Warm-Up Scripts

SharePoint

This is a cross-post of my article on nbsp.

Harry Chen did a comparison of SharePoint Warm-Up scripts in October 2010, this is essentially a follow up to his findings. At the end, I’ll share the script that I’m using. Do we really need another SharePoint Warm-Up Script? No, but I found some useful, others not so much and decided to modify one for my needs.

First, lets describe briefly what these scripts are and their benefit. During normal operation, IIS will recycle application pools, this is normally done once per day. An IISRESET or computer restart will recycle application pools as well. When this happens, there is a significant performance hit when loading a web site for the first time because everything needs to be compiled.

A Warm-Up Script essentially loads one or more webpages so that Just-In-Time (JIT) compilation is performed. The idea is to "warm up" the site before users start requesting it so they don’t suffer that first time hit. More info here.

With that said, this isn’t useful for SharePoint Farms with large numbers of users access SharePoint all day and night. It’s probable a user will get that first hit before your script does. However, for smaller Farms or where there is a usage profile (e.g., 9am to 5pm), this can be useful. It could also be useful for development environments or demo machines where you just need to warm up ahead of time.

Now, let’s take a look at some of the options I found. CodePlex had a few solutions:

  • SPWakeUp – This is an exe file that takes a few parameters. It can exclude site collections you specify, send an email log of results and you can specify a username/password. As an IT Pro, I just don’t like compiled programs/scripts even if the source code is available because its hard to modify if I need to.
  • SPSiteWakeUp – This is similar to SPWakeUp but what’s cool here is that it can run as a Windows Service.
  • PSWarmUp – This is a bundle of PowerShell files, a batch file to start up and some configuration files. For me, this one just seems unnecessarily complex. There’s a configuration file with not much in there and a few temp files get created for the script. It’s also unnecessarily hitting all sites in all zones. I like that is based on PowerShell but it still uses good ‘ole stsadm.exe.
  • SharePoint WarmUp Tool – This last one on CodePlex seems unfinished. The source code is there but there is no compiled version so you’ll have to compile yourself. However, this is the only script I’ve found so far that claims (it will) work with Claims and FBA. Still, I’m not too sure I like compiled scripts for this purpose. Alternatively for FBA, here’s a sample.

There are also several on the blogosphere. You may find variations of these scripts on other blogs (besides the ones listed here). However, I tried to make sure I captured the one which was the source (there’s so much plagiarism going on!!).

  • WarmupServer (Joel Oleson 2006) – Joel does not take credit for writing these scripts but does a good job of explaining what they do. This is a set of vbs and batch files. This one is really old (from 2006) and requires a lot of customization. I wouldn’t touch it.
  • Daniel Bugday SharePoint 2010 Warmup Server Script – Also vbs based and uses stsadm.
  • Kirk Hofer’s SharePoint Warm Up Script (2008) – This was originally created for MOSS 2007 but should work on SharePoint 2010 as well. It enumerates all zones and sites and loads each one. It still uses stsadm.exe. What I didn’t like about this one is that it wasn’t easy to configure. In MOST cases, there’s no use "warming up" different zones because they are all contained in the same application pool. However, this PowerShell based script is small and easy to use! (Another variation here to allow specifying additional sites and here for a simpler version).
  • Ingo Karsteins SharePoint Warm Up (2011) – This is a PowerShell based script, similar to Kirk Hofer’s. It includes the ability to set a timeout and does some Windows Event Logging (which I thought was cool). About half way down, there is a parameter called $urls that needs to be defined. This is really the only thing I didn’t like about this script – where the parameter is located and the fact that you have to define it.
  • Andrew Connells Site Collection Keep-Alive Job – This is a solution file (WSP) for SharePoint. Frankly, this is probably the best implementations of warming up sites. You can specify how often to ‘refresh,’ which web applications, sites, and sub-site as well. All in a friendly Central Administration GUI.

Finally, there used to be an IIS Application Warm-Up module. It’s officially retired, if you see it somewhere else, don’t use it. I never did get it to work for SharePoint 2010 anyway.

OK, at long last, what am I proposing? I like components of Ingo Karsteins and Kirk Hofer’s script, so I’m going to combine them. I wanted to avoid using stsadm and I wanted to keep it simple (one file). I also did some testing on warming up individual site collections and found that it really was unnecessary. Once the application pool is warmed up (by hitting the web application URL), there’s no significant benefit to hitting the site collections within it.

Modifications:

  • Put the variables on top
  • Loads the SharePoint Snapin so you can run it from a regular PowerShell window
  • Automatically retrieves all of the Web Applications by default and loads them. Optionally, you can uncomment the $urls variable at the top and specify only the ones you want.
  • Uses Get-SP* cmdlets instead of stsadm.exe

Here is the script, a slightly modified version of Ingo Karstein’s script:

#############################################
# Title: Warmup-SPSites.ps1		
# Author: Ingo Karstein: http://ikarstein.wordpress.com/2011/08/03/sharepoint-warm-up-now-with-timeout/					
# Modified by: Wahid Saleemi
# Twitter: @wahidsaleemi					
# Reference: https://wahidsaleemi.com	
#############################################

#Region Define Variables
### Setup your variables here
$timeout = 60000 #=60 seconds
# Leave the line below commented if you want all of the Web Apps. Uncomment and set for only specific ones.
#$urls= @("http://finweb", "http://another.sharepoint.local")
#EndRegion
 
#Region Load SharePoint Snapin
$ver = $host | select version
if ($ver.Version.Major -gt 1)  {$Host.Runspace.ThreadOptions = "ReuseThread"}
Add-PsSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
#EndRegion
 

#Region MyWebClient
    Add-Type -ReferencedAssemblies "System.Net" -TypeDefinition @"
    using System.Net;
    public class MyWebClient : WebClient
    {
        private int timeout = 60000;
         public MyWebClient(int timeout)
        {
            this.timeout = timeout;
        }
         public int Timeout
        {
            get
            {
                return timeout;
            }
            set
            {
                timeout = value;
            }
        }
         protected override WebRequest GetWebRequest(System.Uri webUrl)
        {
            WebRequest retVal = base.GetWebRequest(webUrl);
            retVal.Timeout = this.timeout;
            return retVal;
        }
    }
"@
#EndRegion
 
#Region Function to get Site List
Function Get-SiteList {
$script:sitelist = "$env:temp\siteURLs.txt"
New-Item $script:sitelist -itemType File -Force | Out-Null
# To WarmUp, we really just need the load the Web Apps
$sites = Get-SPWebApplication -IncludeCentralAdministration | Select Url
# If we want to try some caching too, get all the site collections, comment above and uncomment below
# $sites=Get-SPSite -Limit ALL
foreach ($site in $sites) 
	{
		#write-host $site.Url;
		$site.Url | Out-File $script:sitelist -append
	}
}
#EndRegion

#Region Set URLs to WarmUp
# check to see if a variable $urls is set.
if (!(test-path variable:\urls))
	{
	Get-SiteList
	$urls = (Get-Content $script:sitelist)
	}
#EndRegion

#Region Perform the WarmUp
New-EventLog -LogName "Application" -Source "SharePoint Warmup Script" -ErrorAction SilentlyContinue | Out-Null

$urls | % {
    $url = $_
    Write-Host "Warming up $_"
    try {
        $wc = New-Object MyWebClient($timeout)
        $wc.Credentials = [System.Net.CredentialCache]::DefaultCredentials
        $ret = $wc.DownloadString($url)
        if( $ret.Length -gt 0 ) {
            $s = "Last run successful for url ""$($url)"": $([DateTime]::Now.ToString('yyyy.dd.MM HH:mm:ss'))"
            $filename=((Split-Path ($MyInvocation.MyCommand.Path))+"\SPWarmUp.log")
            if( Test-Path $filename -PathType Leaf ) {
                $c = Get-Content $filename
                $cl = $c -split '`n'
                $s = ((@($s) + $cl) | select -First 200)
            }
            Out-File -InputObject ($s -join "`r`n") -FilePath $filename
        }
    } catch {
          Write-EventLog -Source "SharePoint Warmup Script"  -Category 0 -ComputerName "." -EntryType Error -LogName "Application" `
            -Message "SharePoint Warmup failed for url ""$($url)""." -EventId 1001
 
        $s = "Last run failed for url ""$($url)"": $([DateTime]::Now.ToString('yyyy.dd.MM HH:mm:ss')) : $($_.Exception.Message)"
        $filename=((Split-Path ($MyInvocation.MyCommand.Path))+"\lastrunlog.txt")
        if( Test-Path $filename -PathType Leaf ) {
          $c = Get-Content $filename
          $cl = $c -split '`n'
          $s = ((@($s) + $cl) | select -First 200)
        }
        Out-File -InputObject ($s -join "`r`n") -FilePath $filename
    }
}
#EndRegion

$script:sitelist | Remove-Item -force -ErrorAction SilentlyContinue

Keep in mind, you should run this on all Web Servers that users will access (needs to run on each WFE) and the account running the script should have appropriate permissions.

If I missed a Warm Up script that’s really different from the ones in this article, please leave a comment!

4 comments… add one
  • amac44 May 11, 2012 Link Reply

    Another factor is how often JIT compliations expire.  The default timeout in IIS is 15 min. – http://msdn.microsoft.com/en-us/library/s10awwz0.aspx – so must run this every 15 unless you’re confident there’s traffic, correct? @wahidsaleemi

    • wahidsaleemi May 11, 2012 Link

       @amac44
       I don’t think that’s right – I think you’re referring to batchTimeout setting which is not an expiration, rather a duration of time to complete JIT compilation. Compilation usually takes 30 seconds to 3 minutes but the timeout value allows up to 15 minutes. However, once compilation is completed, its in memory – it does not expire. JIT must be recompiled if memory is lost (app pool recycle, automatic or manual or caused by something else like a server reboot). On one of my servers, the Web Application Pool is set to recycle at 1am, so I can set up the script to run at 1:01am if I wanted. I normally don’t use these Warm up scripts in production though. Hope that helps.

    • amac44 May 11, 2012 Link

       @wahidsaleemi 
      Thanks for the clarification – of my mind, not your post ;)  I had come across on msdn, “even if a page has been previously compiled, if its code is updated or if the page has not been accessed for a period of time (I apologize, I do not know how this is) then IIS will have to recompile it when a request is submitted for it” — so was assuming that “period of time” was batchTimeout.  But no I think you are correct.
      Also worth a look, http://www.iis.net/download/ApplicationInitialization – i didn’t know about this.

Leave a Reply