By: Christian Holslin
Warming up a SharePoint farm can be helpful if your users experience start-up delays in the morning when first accessing the system. To get around this hiccup, we commonly deploy what many refer to as a warm-up script. There are many ways to build one, and many out there to choose from. I will walk you through a simple .NET 4.5 console application built with the client-side object model which works for SharePoint 2010 and SharePoint 2013 and is easy to deploy almost anywhere on the network.
Skipping Ahead
If you’re just here for the code, feel free to skip down to the Source Code section at the bottom. There are some dependencies, but if you know what you’re doing already you might be able to guess what they are. If not, read the Dependencies and Assembly References sections.
Benefits of CSOM over Server-Side
The traditional server-side warm-up script designed for a MOSS 2007 environment requires direct access to the SharePoint farm. While these work great for SharePoint 2010 and SharePoint 2013 as well, you can only run the warm-up script on one of the SharePoint servers.
The client-side object model, or CSOM, frees us from this restriction allowing us to deploy our warm-up script onto any server or workstation on the network, so long as it can access SharePoint via the HTTP protocol.
Removing CSOM as a Dependency
You could take my code and remove CSOM as a dependency and just use the HttpClient class to send a request to the base URL. This will warm-up IIS, but what the CSOM code does is traverse the SharePoint sub-site hierarchy warming up the entire site collection so all welcome pages on all sub-sites are also warmed up.
Dependencies
You will need .NET 4.5 installed. I use .NET 4.5 and the SharePoint 2013 assemblies for SharePoint 2010 and SharePoint 2013. This allows me to take advantage of the HttpClient class which is ultimately what is needed to fully warm-up SharePoint.
You’ll want to take care if installing .NET 4.5 on a SharePoint 2010 box. If you do, just make sure IIS keeps .NET 2.0 as the default .NET Framework Version for new application pools.
Running anything with the .NET managed CSOM for SharePoint requires the SharePoint client-side assemblies. There are two ways to get these, depending on what type of server you’re planning to use to run the warm-up job:
Using a SharePoint Box
If you’re using a SharePoint 2013 box with SharePoint already deployed, you don’t need to do anything else. The assemblies are already installed.
If you’re using a SharePoint 2010 box, however, you will want to get the SharePoint 2013 client components from here http://www.microsoft.com/en-us/download/details.aspx?id=35585.
Using a Development Box
If you’re using a vanilla development box with Visual Studio 2012 or 2013 installed, get the Web Platform Installer from here http://www.microsoft.com/web/downloads/platform.aspx then using that install the Microsoft Office Developer Tools for Visual Studio.

Do a search for “SharePoint” in the Web Platform Installer and you will find the Visual Studio 2012 and Visual Studio 2013 versions. Install the one you need for your version of Visual Studio.
Using a Production Box
If you’re using a production box which does not have development tools installed, download and install the SharePoint Server Client Components SDK from here http://www.microsoft.com/en-us/download/details.aspx?id=35585 for SharePoint 2013.
Assembly References
To get the code to compile and run, you need these assembly references.
They should be installed from the dependencies above. If you’re starting from a new Visual Studio project you will find these assemblies in the C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI folder.

Note the number 15 in the ISAPI folder path. This is important. If you’re referencing the assemblies from the 14 path or 16 path you won’t be using the SharePoint 2013 on-premise client-side object model libraries. Those might work too, but all my testing was done with the v15 assemblies.
Also, you’ll want to add a reference to System.Net.Http. This is part of the .NET Framework so it should pop right up when you search for it in Visual Studio.

Note there are two versions; you want version 4.0.0.0.
Authentication
To keep things simple, the program uses the default credentials of the user running the program. What this means is you should run the warm-up script using a service account with read access to the site collections. Don’t use a user account, the SharePoint Admin account, or any other account with a volatile password such as your own login unless of course you’re just testing the script. Why not? User accounts, or other interactive accounts (meaning accounts people use to physically log into a machine), are typically bound to password expiration policies, or at the very least have volatile passwords. What this means is the password may change at any time, typically to keep the account secure. A warm-up script for SharePoint running as a Task requires a stored password to run autonomously. If this password changes, the script will fail.
If you aren’t sure which account is best, try the Default Content Access account used by the Search Service Application. Typically, this account will have full read to your SharePoint site collections. You can find this account by opening the Search Administration homepage. Go to Central Administration, open your list of Service Applications, find your Search Service Application, and click on it to open the management screen. The Search Administration homepage will appear and you will see the Default Content Access Account under System Status.

Look over to the right and grab the account Domain and Name. Use this account when you setup the warm-up job.
Setup the Warm-up Job
The easiest way to schedule warm-up is to use the Windows Task Scheduler.

You can pretty much find this on any Windows box. We recommend designating a low-horse power, cheap server as a task box simply for the purpose of running client-side scheduled tasks across the day. In most enterprise environments, you’re going to have a number of programmatic tasks running on a daily basis, and not just for SharePoint. It’s handy to have a server dedicated for just this purpose.
Designating the URLs
The way my example program works is simple: just stuff a bunch of URLs as command-line arguments and the program will loop through each one and do its thing. When you setup the Task, just type all the URLs you want to warm up in the “Add arguments (optional)” field for the Task’s Action.

If you don’t like the way this works you can easily change the code to do whatever you want. I like this method because you can run the program against any combination of URLs you want without having to tweak configuration files. It’s also very easy to bolt into an existing script or third-party application.
Designating the Service Account
Assuming you’re using the Task Scheduler, use the Change User or Group button to run the program as a different user.

Keep in mind the account you specify will need rights to log on locally. If these security policies are controlled by Group Policy at your Domain level, you may need to create a Policy in Active Directory to allow this. You’ll know if this is the case when you test run the Task.
For More on the Task Scheduler
How-To Geek has a fantastic, in-depth lesson on the Windows Task Scheduler which you can find here:
http://www.howtogeek.com/school/using-windows-admin-tools-like-a-pro/lesson2/all/
If you’re not familiar with creating Tasks with the Task Scheduler, go through that lesson to familiarize yourself with the tool.
Multiple Front-Ends
If you have multiple front-end servers, you are most likely load balancing HTTP traffic between them. The HttpClient class in .NET 4.5 makes an HTTP call (surprise, surprise) to the target URL provided. This is very similar to opening up Internet Explorer and typing a URL into the address bar. Thus, a single HTTP request will only warm-up one of your front-end servers. Here are some options for you to consider:
Use Alternate Access Mappings
The easiest way to warm up multiple front-end servers is to skip the load balancer entirely. Say you have a web site http://sharepoint and you have 4 front-end servers. The URL http://sharepoint goes to the load balancer, so we can’t use that to warm up the 4 servers. How do target each front-end individually? Answer: DNS hosts.
Add 4 new hosts (A or AAAA-type records) to your DNS server for sharepoint1, sharepoint2, sharepoint3, and sharepoint4. Tell each host to point to a specific front-end server. Then, add http://sharepoint1, http://sharepoint2, http://sharepoint3, and http://sharepoint4 as alternate access mappings to the http://sharepoint web application so your warm-up script can hit each front-end individually. Finally, you’ll want to make sure IIS knows about these host names by configuring the web application’s bindings in IIS:

Any IIS web site can have multiple bindings. Here I’ve added the sharepoint1 host to my web site on my primary front-end server. Repeat this for all your front-end servers using a distinct host for each one. When you run the warm-up script you can hit each front-end server using the following command:
spwarmup.exe http://sharepoint1 http://sharepoint2 http://sharepoint3 http://sharepoint4
This will cause the HttpClient class to make 4 distinct HTTP calls, 1 to each specific front-end server so they all get warmed up.
Multiple Hosts with SSL
If you’re using SSL for your web application, you can still use non-SSL warm-up URLs just like in the example above. However, if you’re not comfortable doing so, you can add Subject Alternative Names to your SSL certificates to support https://sharepoint and https://sharepoint1 and https://sharepoint2 and so on.
Load Balancer Rules
If you can’t avoid your load balancer, then the solution becomes more complex as you will be reliant on the load balancer to decide which front-end server to use when servicing the warm-up script’s requests. Try adding a rule to your load balancer for all traffic coming from your Task Scheduler box. Here are some techniques to consider:
I am not an expert on network load balancing, but I do know there are some powerful hardware and software solutions out there which handle many enterprise-grade scenarios. Speak with your network team and find a solution which works best for your end-users.
Source Code
Last but not least is the source code. All the code you need to run my warm-up script is here below. This works, quite well, and I tested it against SharePoint 2010 and SharePoint 2013 using a dedicated server as the Task box. It’s probably not bug-free, and I haven’t tested it in every scenario, but it definitely gets the job done.
I recommend creating a new Visual Studio command-line application project in .NET 4.5 then overwriting Program.cs with all the code below. Add your assembly references and you should be good to go.
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
namespace SharePoint.WarmUp
{
public class Program
{
private static string _root;
private static ClientContext _context;
public static void Main( string[] args )
{
foreach( string url in args )
{
try
{
// Echo each URL in case we’re running this interactively
Console.WriteLine( “Connecting to {0}”, url );
_context = new ClientContext( url );
_root = url;
// SharePoint 2010 Web object has no Url property, so use the ServerRelativeUrl property
Web web = _context.Web;
_context.Load( web, w => w.ServerRelativeUrl, w => w.Title );
_context.ExecuteQuery();
WarmUpUrl( _root );
TraverseWebs( web );
}
catch( Exception ex )
{
// Tell us if something goes wrong
Console.WriteLine( “Exception: {0}”, ex.GetType().Name );
Console.WriteLine( “Mesage: {0}”, ex.Message );
Console.WriteLine( “Stack: {0}”, ex.StackTrace );
}
}
}
private static void TraverseWebs( Web web )
{
Console.WriteLine( “Found: {0}”, web.Title );
WebCollection webs = web.Webs;
_context.Load( webs );
_context.ExecuteQuery();
foreach( Web w in webs )
{
_context.Load( w, q => q.ServerRelativeUrl, q => q.Title );
_context.ExecuteQuery();
WarmUpUrl( _root + w.ServerRelativeUrl );
TraverseWebs( w );
}
}
private static void WarmUpUrl( string url )
{
Console.WriteLine( “Warming up: {0}”, url );
HttpClientHandler handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
var client = new HttpClient( handler );
var response = client.GetAsync( url );
response.Wait();
var result = response.Result;
switch( result.StatusCode )
{
case HttpStatusCode.OK:
break;
default:
Console.WriteLine( “Warning, server responded with {1}:{0}”, result.StatusCode, (int)result.StatusCode );
break;
}
}
}
}
Comments are closed.