Archive

Archive for May, 2012

Warm-up script for Form Based Authentication (FBA) SharePoint sites

Abstract

During a project we created a SharePoint environment which uses custom membership and claims providers. To make sure the first visitor in the morning doesn’t have to wait too long, we want to use a warm-up script. On the Internet there are a lot of warm-up scripts for SharePoint, but they mainly focus on SharePoint sites which use Active Directory as authentication source. I did find some executables which allow the warm-up of FBA SharePoint sites, but I prefer a PowerShell script. Mainly because a script will be readable by the administrators of the servers (current and future administrators) and they can see what happens.

Steps of form based authentication

If we look at the process of form based authentication, the following steps can be defined:

In order to mimic this process, the warm-up script will need:

  1. The URL of the site to warm-up.
  2. The URL which is used when redirecting. This is the URL you’ve set as login page for your authentication provider and you could add some query string variables for the return URL.
  3. The pages you actually want to hit. When you have pages which are really important and used cached data or something like that, you might want to pre load all of these pages.

When you have this in place, you might want to use an application like Fiddler to actually perform this process once. What you will need in the script, is the generated authentication cookie so you can actually login to your site and perform the warm-up. Not to worry, the script itself actually gathers almost all the information for you. The important pieces you will need from the login page are the __VIEWSTATE and __EVENTVALIDATION. These you’ll need to actually perform the login before you can warm-up your site. The script already retrieves this data from the page. The part you’ll need to paste in yourself is the ID’s you use for the login controls. This is also noted in the script itself.

The script

The script itself is pretty self-explanatory, there is plenty of commenting in it:

#———————————————————————————————————————-

# Add the System.Web assembly to allow the use of the web client

#———————————————————————————————————————-

Add-Type -AssemblyName System.Web

#———————————————————————————————————————-

# This method will call the site to warm up

#———————————————————————————————————————-

function WarmUpFBASite([string] $rootUrl, [string] $username, [string]$password,[string] $serverRelativeLoginUrl, [array] $serverRelativePageUrls){

    # Build the complete login url

    $loginUrl = $rootUrl + $serverRelativeLoginUrl

    # Create a cookie container for the authentication cookie

    $CookieContainer = New-Object System.Net.CookieContainer

    # Retrieve the authentication cookie

    $CookieContainer = RequestAuthenticationCookie -url $loginUrl -username $username -password $password

    # Load all pages

    foreach($relativeUrl in $serverRelativePageUrls) {

        # Build the page url

        $url = $rootUrl+ $relativeUrl

        # Create a new request and add the properties for it

        [net.httpWebRequest] $request = [net.webRequest]::create($url)

        $request.Method = “GET”

        $request.Accept = “text/html”

        $request.AllowAutoRedirect = $false

        $request.CookieContainer = $CookieContainer

        # Determine which timeout you need

        $request.TimeOut = 120000

        # Get the response

        [net.httpWebResponse] $response = $request.getResponse()

        # Read the resonse stream

        $responseStream = $response.getResponseStream()

        $streamReader = new-object IO.StreamReader($responseStream)

        # The result will hold the actually returned html

        $result = $streamReader.ReadToEnd()

        # Close the response steam

        $streamReader.Close()

    }

}

#———————————————————————————————————————-

# This method retreives the authentication cookie

#———————————————————————————————————————-

function RequestAuthenticationCookie([string] $url, [string] $username, [string]$password) {

    # Create a new cookie container

    $CookieContainer = New-Object System.Net.CookieContainer

    # Get the post data needed for the request.

    $postData = GetPostData -url $url -username $username -password $password

    # Place the post data object in the buffer

    $buffer = [text.encoding]::ascii.getbytes($postData)

    # Open a new request and set the properties

    [net.httpWebRequest] $req = [net.webRequest]::create($url)

    $req.method = “POST”

    $req.Accept = “image/jpeg, image/gif, image/pjpeg, application/x-ms-application, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*”

    $req.Headers.Add(“Accept-Language: en-US”)

    $req.Headers.Add(“Accept-Encoding: gzip,deflate”)

    $req.Headers.Add(“Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7”)

    $req.AllowAutoRedirect = $true

    $req.ContentType = “application/x-www-form-urlencoded”

    $req.ContentLength = $buffer.length

    $req.TimeOut = 120000

    $req.KeepAlive = $true

    $req.Headers.Add(“Keep-Alive: 300”);

    $req.CookieContainer = $CookieContainer

    $requestStream = $req.getRequestStream()

    $requestStream.write($buffer, 0, $buffer.length)

    $requestStream.flush()

    $requestStream.close()

    # Get the response

    [net.httpWebResponse] $response = $req.getResponse()

    $responseStream = $response.getResponseStream()

    $streamReader = new-object IO.StreamReader($responseStream)

    $result = $streamReader.ReadToEnd()

    $response.close()

    # Return the cookie

    $CookieContainer

}

#———————————————————————————————————————-

# This method retreives the postdata needed to retrieve the authentication cookie

#———————————————————————————————————————-

function GetPostData ([string] $url, [string] $username, [string]$password) {

    # Open a new web client

    $webClient = New-Object System.Net.WebClient

    $webClient.Headers.Add(“user-agent”, “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)”)

    $data = $webClient.OpenRead($url)

    $reader = New-Object System.IO.StreamReader($data)

    $result = $reader.ReadToEnd()

    $data.Close()

    $reader.Close()

    # Retrieve the view state

    $viewState = ExtractPostDataElements -source $result -hiddenInputName “__VIEWSTATE”

    # Retrieve the event valudation

    $eventValidation = ExtractPostDataElements -source $result -hiddenInputName “__EVENTVALIDATION”

    # Be aware, in the postdata also the ID’s of the login controls are placed. You will have to look in your login page and replace the values in the string below!

    $postData = “__LASTFOCUS=&__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=$viewstate&__EVENTVALIDATION=$eventValidation&ctl00%24PlaceHolderMain%24signInControl%24UserName=$username&ctl00%24PlaceHolderMain%24signInControl%24Password=$password&ctl00%24PlaceHolderMain%24signInControl%24LoginButton=Log+In”

    # Return the post data object

    $postData

}

#———————————————————————————————————————-

# This method retrieves post data elements and is used to retrieve the viewstate and eventvalidation objects

#———————————————————————————————————————-

function ExtractPostDataElements ([string] $source, [string] $hiddenInputName) {

    $valueDelimiter = “value=`””

    $inputNamePosition = $source.IndexOf($hiddenInputName)

    $inputValuePosition = $source.IndexOf($valueDelimiter, $inputNamePosition)

    $inputStartPosition = $inputValuePosition + $valueDelimiter.Length

    $inputEndPosition = $source.IndexOf(“`””, $inputStartPosition)

    $inputElement = [System.Web.Httputility]::UrlEncode($source.Substring($inputStartPosition, $inputEndPosition $inputStartPosition))

    $inputElement

}

#———————————————————————————————————————-

# Call the warmup methods

#———————————————————————————————————————-

WarmUpFBASite -rootUrl http://www.sharepoint.local” -userName “” -password “” `

-serverRelativeLoginUrl “/_layouts/testproject/CustomLoginPage.aspx?ReturnUrl=%2f_layouts%2fAuthenticate.aspx%3fSource%3d%252F&Source=%2F” `

-serverRelativePageUrls (“/Pages/default.aspx”,“/subsite/Pages/default.aspx”)

Advertisements
Categories: PowerShell, SharePoint
Ben Prins

What I want to remember about SharePoint

blog.frederique.harmsze.nl

my world of work and user experiences

Bram de Jager - Coder, Speaker, Author

Office 365, SharePoint and Azure