Living a SharePoint life

Tuesday, October 14, 2014

Fire up those caches

Picture by Caroline Gutman
If you’re working with SharePoint you probable heard already about something called the Warm-Up Script. It won’t keep you warm in the night and you must ask your partner or cat to do so. The Warm-Up script prefetches SharePoints ASPX pages and loads them into the IIS cache. This will help to improve the user experience. There are different approaches to do this. But beside of the script itself, the proper configuration will get things really started.

This post is

I won’t go into detail how to write a Warm-Up script, because this would be done for the x-time. It is much more convenient to download a finished script from another page. I like to use the Warm-Up script which can be downloaded from .It is written in PowerShell, easy to understand, the project is still maintained, it supports logging and it runs on SharePoint 2010 and 2013. Download the file and save it to your server, because we’ll need it in a minute.

Warm-Up scripts need to be configured in a manner that when the server is restarted, the Warm-Up script is triggered. Windows offers us an easy way to do this thru the task scheduler. Since version 1.4 of the SPBestWarmUp script, you can use a switch to create a new task. I however will show you how to setup everything by yourself, so you get a better understanding what is going on. Later you can use the script to create the task and then modify it later.

Windows Account preparation

Before we can start to create tasks in the task scheduler, we must consider a few things in advance. For instance, in which security context the script should be executed? You could use your own login credentials, but that wouldn’t be such a good idea. Your logon ID would show up in the event logs when the script is executing. Also only you could make changes to the script configuration without resetting the credentials running the script, or would you like to share your password with your coworkers?

We need a new domain logon which only purpose is to execute our scripts. This is what I call a Script-Runner account. If you haven’t done already, create a new account in your AD. Make sure that you have chosen a strong password and keep it in a security spot, because this account will need some advanced privileges.

Ok, now that we have the new Script Runner account, we’ll make sure the account can do its job. Because our script is a PowerShell script, the account will need the SharePoint_Shell_Access rights. You can add this right by using the PowerShell cmdlet Add-SPShellAdmin. However, as you might already know, this command is executed against the Content DB in your Farm and not against the Farm itself. So we need to run this command for every Content DB in the Farm. But hey, we’re talking about the PowerShell here and it wouldn’t be the PowerShell if it was hard, wouldn’t it? Use this one liner to add the SharePoint_Shell_Access right to all of your Content DB:

foreach($db in Get-SPContentDatabase){Add-SPShellAdmin –Username [ScriptRunner] -Database $}

Next we’ll have to make sure that the account can be executed as a batch job. This is even more important if you decide to deny the account logon rights as a user, which is by the way not such a bad idea. The Log on as a batch job right is managed by the Local Securtiy Policy Manager on the Windows Server and because it’s a local policy you’ll have to modify this on every web frontend server in your Farm. You could create a Domain Policy for this, but be aware that you’ll might extent this right to more server than necessary.

To modify the Local Policy open the Local Security Policy Manager from the Administrative Tools in your Start menu. In the left panel navigate to Local Policies / User Rights Assignment and search for the Log on as a batch job setting. Add your Script-Runner Account to the list and finish everything up.

And finally, our script will try to open the web pages on our SharePoint server, so we need to be sure it has access to the sites. We could add the Script-Runner Account to every site, but this would be error prone. Every time a new site is created, we’d had to make sure the Script-Runner is added to that site as well. Take a guess how well this will work.

Much easier is to use the Web Application User Policies. Add the Script-Runner Account to the User Policy of each of your Web Applications and give it reading access. This way the script will always have access to all sites in your Farm.

The task scheduler

Now that everything is prepared, you can start to create the task in the task scheduler. The Windows task scheduler can be found under the administrative tools in your start menu. When you open the manager you’ll see a list with already configured tasks in the left panel. I suggest you create a new folder to store your own tasks.

Do so by selecting the node in the left panel and select New Folder from the Actions menu. To add a new task right click on the center panel and select Create New Task. A new window pops up on your screen and you can start configuring the task.

  • First chose a name for the new task.In this example I use SPBestWarmUp.
  • At the Securtiy options use the Script-Runner Account to run this task by selecting Change User or Group.
  • Select the option Run whether user is logged on or not.
  • Select the option Run with highest privileges.

The Trigger

Switch to the Trigger tab in the window now. Each task needs at least one or more trigger that gets the things started. The most obvious trigger would be to run the script when the server is started. This for instance is the case when a reboot is necessary. There is a trigger on its own for this type of event. Add a new trigger by selecting the button New and from the drop-down control Begin the task, select the option At startup. Make sure the trigger has the option Enabled selected and finish by selecting OK.

Now we have a pretty simple setup. But there are other ways to restart the IIS Server without restarting the entire Windows server. IIS Reset is one way to do that and it would be nice if our script would fill up the IIS Caches afterwards for us as well. Lucky for us, the task scheduler supports monitoring events on the Windows event log.

Start adding a new trigger by selecting the New button again, but this time select On an event from the dropdown control. You can now specify the Log, the Source and the Event ID to monitor. Executing the iisreset.exe from the command line creates a new entry in the System log with the Event ID 3201. The source is IIS-IISReset.

Besides of the IIS Reset Event there are other events that might be interesting for us as well. Because the workflow to add these triggers to your list is always the same and I don’t want to bore you, I shorten things a bit. Following up is a table with the most appealing events to keep an eye on.

Log Source Event ID Description
System IIS-IISReset 3201 Start event after an IIS Reset
System WAS 5079 An administrator has requested a recycle of all worker processes in application pool '%1'.
System WAS 5074 A worker process with process id of '%1' serving application pool '%2' has requested a recycle because the worker process reached its allowed processing time limit.
System WAS 5075 A worker process with process id of '%1' serving application pool '%2' has requested a recycle because it reached its allowed request limit.
System WAS 5076 A worker process with process id of '%1' serving application pool '%2' has requested a recycle because it reached its scheduled recycle time.

Of course there are some more possibilities, but these are from my point of view the most interesting ones. Take a look at and for further details.

And ... Action

All triggers are set and ready to fire in the case of event. Now we must define what to execute when the events occur. Go to the Actions tab and add a new action to the list by selecting the New button. From the drop down control select Start a program and for the setting Program/script enter the following path:


As argument you enter the path where you saved the SPBestWarmUp.ps1 script. That’s all.

Continue to configure the rest of the task as you wish and save everything. You’re ready to run the script. To test your configuration, do a IISReset on the Web Server and monitor the status of the task in the task manager. If everything goes well, you should get a (0x0) for the last run results.

Great it works, but…

does it really do what you expect from the script? What if you use a load balancer? Think for it a moment. The script gets a list with all sites to call, so these are populated to the server cache. The script returns a list of URL of all sites and starts an Internet Explorer object which is used to call the URLs.

Now before an URL is opened in the browser (the script loads the IE), the browser must do a DNS lookup for the URL (1). Now guess what. The DNS returns us the virtual IP of the Load Balancer (2)(3). Therefore the script will only target one server in the farm. What may be even worse, if you have for instance two servers you restart server A but the load balancer returns the result from server B (4). Then the script wouldn’t do its work as expected.

To fix this issue, you must add all sites to the servers hosts file ( C:\Windows\System32\drivers\etc\hosts ) and use the servers ip-address instead. So if the script is executed it will resolve the URLs from the host file instead of the DNS. Check the log file the script has created and add the URLs listed there. Usually a Windows Server resolves names by the following order: Local Cached Information -> Hosts File -> DNS Servers -> NetBt (NetBIOS over TCP/IP). If you have trouble try flushing the dns cache. You can learn more about Setting the Name Resolution Search Order for TCP/IP-32 here.

I hope this article gives you a deeper understanding what the SharePoint Warm-Up scripts are used for and how to setup an environment properly. If you have questions feel free to leave a message in the comment section below.


  1. Great tutorial, though it took me a while to figure out to use foreach instead of % (foreach-object).

    1. Thanks for the hint. I've changed it into foreach. Shouldn't be a problem now any more.

  2. I can't use the runner account if it's not in the administrators group of the server. UAC is disabled. I've logged on with the runner account to run the script manually and it says "You do not have elevated Administrator rights to run this script"

    1. Go to the servers "Local Securtiy Policy Manager" and check if the account was added to the "Log on as a batch job" group.


Featured Post

The Retro Powershell - Looking good in 8-Bit | Part 1

I wrote a little script that, when placed in your PowerShell Profile, will print a message similar to the old boot message you got from you...