SP Warm-up

This post will be extended with ways of doing .Net warm-up

Method Cat Pro Cons
1. Scripts Tool – Can be configured to do anything
– Can execute centrally on a server
– Needs to add each app to hosts file, if each WFE behind a loadbalancer needs warmup
2. IIS Application Initialization IIS Mod – Trigged by recycling – not by time
– Overlapped recycling makes warmup invisible
– Must be installed and configured on each WFE
– Requests are anonymous
3. IIS Application Warm-Up IIS Mod – Requests can be with specific identities – Must be installed and configured on each WFE
– Depricated, Beta, Use module above
4. Utilities Tool – Can be coded to do anything

Please note

  • Warmed apps takes up memory in the application pool. Do only warm apps, that are used/important.

Other comparisons

1. Warm-up scripts – SP Specific

Please note

  • A warm-up scripts usually uses urls. This can be a problem, when both WFE’s behind a loadbalancer needs to be started.

2. IIS Application Initialization (IIS 7.5 and up)

3.  IIS Application Warm-Up

This module is not awailable for download anymore. Since spring 2012 it is replaced by IIS Application Initialization module.

4. Utilities

Conclution

Option 3. IIS Application Warm-Up seems to be best, but the the module is not downloadable anymore.

Option 2. IIS Application Initialization seems to be the best choise, if the url supports anonymous access. It is supported for the future and does not give problems with loadbalancing.

Option 1. Scripts gives operations the choise to read, modify and approve code. In loadbalanced environment there is a script for exchanging domain name with servername. See above.

Update 2013-08-02

Not much has happened in this area.

  • @wahidsaleemi concludes you only need to warmup WebApps (I didn’t notice that last time): Quote:

“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.”

  • Jeff Jones has recently created a script – SPBestWarmUp – that can be installed as scheduled task on a WFE and automatically go through all WebApps – even finds the password of the running user.
  • Todd Klindt suggests to use a PowerShell 3 cmdlet Invoke-WebRequest, when invoking an url.

I think I will test the SPBestWarmUp toghether with Bram Nuyts’s loadbalanced WFE trick.

The preliminary mash is SPBestWarmUpInt.ps1:

#==================================================================================================================
#  http://spbestwarmup.codeplex.com/
#==================================================================================================================
#  Filename:        SPBestWarmUpInt.ps1
#  Author:          Jeff Jones - Last Modified:   07-27-2013
#  Modified By:     @Rasor
#  Last Modified:   2013-08-02B
#  Description:     Warmup IIS memory cache by viewing pages from Internet Explorer.  Loads the full page so
#                   resources like CSS, JS, and images are included.  Please modify lines 59-67 to suit your
#                   portal content design (popular URLs, custom pages, etc.)
#
#                   Comments and suggestions always welcome!  spjeff@spjeff.com or @spjeff
#==================================================================================================================

param (
	[switch]$install,
	[switch]$whatif
)

Function Get-Credential() {
	$global:user = $ENV:USERDOMAIN+"\"+$ENV:USERNAME
	Write-Host "  Current User: $global:user"

	#Init
	$global:pass = $null

	# Attempt to detect password from IIS Pool (if current user is local admin & farm account)
	$appPools = gwmi -namespace "root\MicrosoftIISV2" -class "IIsApplicationPoolSetting" | select WAMUserName, WAMUserPass
	if ($appPools) {
		foreach ($pool in $appPools) {
			if ($pool.WAMUserName -like $global:user) {
				$global:pass = $pool.WAMUserPass
				if ($global:pass) {
					break
				}
			}
		}
	}

	# Manual input if auto detect failed
	if (!$global:pass) {
		#$global:pass = Read-Host "Enter password for $global:user "
	}
	#Write-Host "  Psw: $global:pass"
}

Function Installer() {
	# Add to Task Scheduler
	Write-Host "  Installing to Task Scheduler..." -ForegroundColor Green

	# Create Task
	#schtasks /create /tn "SPBestWarmUpInt" /ru $global:user /rp $global:pass /rl highest /sc daily /st 05:00 /ri 60 /du 24:00 /tr "PowerShell.exe -ExecutionPolicy Bypass $global:path"
	schtasks /create /tn "SPBestWarmUpInt" /ru $global:user /rp $global:pass /rl highest /sc daily /st 05:00 /tr "PowerShell.exe -ExecutionPolicy Bypass -NonInteractive -FILE $global:path"
	if ($?){
		Write-Host "  [OK]" -ForegroundColor Green
	}else{
		Write-Host "schtasks:" $error[1].Exception.Message -ForegroundColor Red
		Write-Host "Case Access denied: Ensure you have LogonAsBatch user right and script is RunAsAdmin" -ForegroundColor Red
		#http://technet.microsoft.com/en-us/library/dd469607(v=ws.10).aspx
	}
	Write-Host
}

Function WarmUp() {
	#Support -WhatIf
	#[cmdletbinding(SupportsShouldProcess=$True)]
	#when cmdletbinding is not supported then instead add parm manually above

	# Get URL list
	Add-PSSnapIn Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
	$was = Get-SPWebApplication -IncludeCentralAdministration | Select Url

	# Warmup SharePoint web applications
	Write-Host "Opening Web Applications..."
	#$global:ie = New-Object -com "InternetExplorer.Application"
	#$global:ie.Navigate("about:blank")
	#$global:ie.visible = $true
	#$global:ieproc = (Get-Process -Name iexplore)| Where-Object {$_.MainWindowHandle -eq $global:ie.HWND}
	foreach ($wa in $was) {
		$url = $wa.Url
		IENavigateTo $url
		#break
		IENavigateTo $url"_layouts/viewlsts.aspx"
		IENavigateTo $url"_vti_bin/UserProfileService.asmx"
		IENavigateTo $url"_vti_bin/sts/spsecuritytokenservice.svc"
	}

	# Warmup custom URLs
	#Write-Host "Opening Custom URLs..."
	#IENavigateTo "http://localhost:32843/Topology/topology.svc"
	# Add your own URLs here
	#IENavigateTo "http://portal/popularPage.aspx"
	#IENavigateTo "http://portal/popularPage2.aspx"
	#IENavigateTo "http://portal/popularPage3.aspx"

	# Warmup Host Name Site Collections (HNSC)
	Write-Host "Opening Host Name Site Collections (HNSC)..."
	#$hnsc = Get-SPSite -Limit All |? {$_.HostHeaderIsSiteName -eq $true} | select Url
	#foreach ($sc in $hnsc) {
	#	IENavigateTo $sc.Url
	#}

	# Close IE window
	if ($global:ie) {
		Write-Host "Closing IE"
		$global:ie.Quit()
	}
    Log-Line "Warmed-up $global:navigatedsuccess pages"
}

Function IENavigateTo([string] $url, [int] $delayTime = 500) {
	# Navigate to a given URL
	if(!$url){
		break
	}
	if($url -eq ""){
		break
	}
	Write-Host "  Navigating to $url"

	if(!$whatif){
	try {
		#$global:ie.Navigate($url)
		#Get-WebPages -url $url
		Get-WebPage -url $url
	} catch {
		#$procid = $global:ieproc.id
		#Write-Host "  IE not responding.  Closing process ID $procid"
		#$global:ie.Quit()
		#$global:ieproc | Stop-Process
		#$global:ie = New-Object -com "InternetExplorer.Application"
		#$global:ie.Navigate("about:blank")
		#$global:ie.visible = $true
	}
	IEWaitForPage $delayTime
	}
}

Function IEWaitForPage([int] $delayTime = 500) {
	# Wait for current page to finish loading
	$loaded = $false
	$loop = 0
	$maxLoop = 20
	while ($loaded -eq $false) {
		$loop++
		if ($loop -gt $maxLoop) {
			$loaded = $true
		}
		[System.Threading.Thread]::Sleep($delayTime)
		# If the browser is not busy, the page is loaded
		if (-not $global:ie.Busy)
		{
			$loaded = $true
		}
	}
}

#http://bramnuyts.be/2011/08/18/sharepoint-warmup-script-for-loadblanced-wfes/
function Get-WebPage([string]$url)
{
	$uri = new-object System.Uri($url)
    $bypassonlocal = $false
    $proxyuri = "http://" + $env:COMPUTERNAME
    $proxy = New-Object system.Net.WebProxy($proxyuri, $bypassonlocal)

    $cred = new-object net.NetworkCredential($ENV:USERNAME, $global:pass, $ENV:USERDOMAIN)
	$creds = new-object net.CredentialCache
	$creds.Add($url, "NTLM" , $cred)

	#client: webclient
	#$wc = new-object net.webclient
	#Credentials
	# Use the entered password
	#$wc.credentials = $creds
	# or Assign the credentials of the logged in user or the user being impersonated.
	#$wc.credentials = [System.Net.CredentialCache]::DefaultCredentials
	#$wc.Headers["Host"] = $uri.Host
	#optional proxy
    #$wc.Proxy = $proxy

	#alternative client: WebRequest
	#http://msdn.microsoft.com/en-us/library/system.net.webrequest(v=vs.90).aspx
	$wr = [System.Net.WebRequest]::Create($url)
	# Use the entered password
	#$wr.credentials = $creds
	# or Assign the credentials of the logged in user or the user being impersonated.
	$wr.Credentials = [System.Net.CredentialCache]::DefaultCredentials
	#$wr.Host = $uri.Host #nope added by wr after some retries
    $wr.Proxy = $proxy

	try{
    	#$pageContents = $wc.DownloadString($url)
		$wrResp = $wr.GetResponse()
		if ($wrResp.StatusCode -eq 200){
	    	Write-Host "    $url is now warmed-up" -ForegroundColor Green
            $global:navigatedsuccess ++
		}else{
	    	Write-Host "    Failed to warm-up $url. Status: $stat" -ForegroundColor Red
		}
	}
	catch{
		$pageContents = ""
		#Write-Host $err
		#Write-Host "    $_.Exception.Message" -ForegroundColor Red
		Write-Host "    $_" -ForegroundColor Red
		Write-Host "    $wrStat" -ForegroundColor Red
	}finally{
		$wrResp.Close()
	    #$wc.Dispose()
	}
    #return $pageContents
}

function Get-WebPages([string]$url)
{
	Get-SPAlternateUrl -WebApplication $url -Zone Default | foreach-object {
	    write-host $_.IncomingUrl
	    $html = Get-WebPage -url $_.IncomingUrl
	}
}
function Log-Line([string]$line)
{
    $now = Get-Date
    Add-Content $global:logpath "`n$now $line"
}
#Main
cls
$global:path = $MyInvocation.MyCommand.Path
$global:logpath = "$global:path.log"
[int]$global:navigatedsuccess = 0

$cmd = ""
if($whatif){
	$cmd = "SPBestWarmUpInt -whatif"
}elseif($install){
	$cmd = "SPBestWarmUpInt -install"
}else{
	$cmd = "SPBestWarmUpInt"
}
Log-Line $cmd
Write-Host $cmd
Write-Host "-----------------"

if(!$whatif){
	Write-Host "  Tip: To see which urls will be warmed-up run the command ""SPBestWarmUpInt.ps1 -whatif""" -ForegroundColor Yellow
}
Get-Credential
#if we have a psw
if(!$global:pass){
	Write-Host "  Error: Dont have a psw" -ForegroundColor Red
}else{
	$tasks = schtasks /query /fo csv | ConvertFrom-Csv
	$spb = $tasks | Where-Object {$_.TaskName -eq "\SPBestWarmUpInt"}
	if (!$spb -and !$install) {
		Write-Host "  Tip: To install on Task Scheduler run the command ""SPBestWarmUpInt.ps1 -install""" -ForegroundColor Yellow
	}
	if ($install) {
		Installer
	}else{
		WarmUp
	}
}
Write-Host "The End"

The script now also creates a small logfile, so it is possible to see if the scheduled task does anything.

Some Tests created this SPBestWarmUpInt.ps1.log:

08/02/2013 12:33:16 SPBestWarmUpInt -whatif	//Which pages will be warmed?
08/02/2013 12:33:23 Warmed-up 0 pages
08/02/2013 12:34:01 SPBestWarmUpInt		//Test warm-up
08/02/2013 12:34:33 Warmed-up 28 pages
08/02/2013 12:36:00 SPBestWarmUpInt -install	//Install
08/02/2013 12:37:32 SPBestWarmUpInt		//Execute Task (Manual Test Run)
08/02/2013 12:37:58 Warmed-up 28 pages

The End

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

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

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

%d bloggers like this: