Archive

Archive for the ‘PowerShell’ Category

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”)

Categories: PowerShell, SharePoint

PowerShell – Delete field and all references

December 9, 2011 Leave a comment

Sometimes you want to delete a site column from SharePoint and you get the nice message stating “Site columns which are included in content types cannot be deleted. Remove all references to this site column prior to deleting it.”. Really helpful that it states in which ContentTypes the field is used. It gets even worse when the column is also used in lists… You can do this via PowerShell easily:

# Add SharePoint PowerShell Snapin

if ( (Get-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null ) {
    Add-PSSnapin Microsoft.SharePoint.Powershell
}

#—————————————————————————-
# Delete Field
#—————————————————————————-
function DeleteField([string]$siteUrl, [string]$fieldName) {
    Write-Host “Start removing field:” $fieldName -ForegroundColor DarkGreen
    $site = Get-SPSite $siteUrl
    $web = $site.RootWeb

    #Delete field from all content types
    foreach($ct in $web.ContentTypes) {
        $fieldInUse = $ct.FieldLinks | Where {$_.Name -eq $fieldName }
        if($fieldInUse) {
            Write-Host “Remove field from CType:” $ct.Name -ForegroundColor DarkGreen
            $ct.FieldLinks.Delete($fieldName)
            $ct.Update()
        }
    }

    #Delete column from all lists in all sites of a site collection
    $site | Get-SPWeb -Limit all | ForEach-Object {
 
     #Specify list which contains the column
        $numberOfLists = $_.Lists.Count
        for($i=0; $i -lt $_.Lists.Count ; $i++) {
            $list = $_.Lists[$i]
            #Specify column to be deleted
            if($list.Fields.ContainsFieldWithStaticName($fieldName)) {
                $fieldInList = $list.Fields.GetFieldByInternalName($fieldName)

                if($fieldInList) {
                    Write-Host “Delete column from ” $list.Title ” list on:” $_.URL -ForegroundColor DarkGreen

                 #Allow column to be deleted
                 $fieldInList.AllowDeletion = $true
                 #Delete the column
                 $fieldInList.Delete()
                 #Update the list
                 $list.Update()
                }
            }
        }
    }

    # Remove the field itself
    if($web.Fields.ContainsFieldWithStaticName($fieldName)) {
        Write-Host “Remove field:” $fieldName -ForegroundColor DarkGreen
        $web.Fields.Delete($fieldName)
    }

    $web.Dispose()
    $site.Dispose()
}

#Delete the field below
DeleteField http://sharepoint “MyField”

Follow

Get every new post delivered to your Inbox.