Tag Archives: SharePoint 2010

Automating a tedious task: Testing SharePoint page performance

Here’s a quick and dirty PowerShell script that hits a supplied SharePoint-related URL and outputs the correlation ID so you can check the ULS logs to further investigate why the page took longer than expected to load.

The script takes three parameters:

  1. SharePointUrl: The URL to test. Can be a SharePoint site collection, site, list, library, page. A resource in SharePoint.
  2. numTries: The number of times to try hitting the URL. Default is 1000
  3. unnaceptableTime – how long you deem is “too long” — milliseconds (i.e. 1000 = 1 second)

When you run the script, it will try connecting to the SharePoint site repeatedly and output attempts that take too long.

When SharePoint receives requests from users, it times how long it takes to process the request and returns this time in the SPRequestDuration HTTP header (in milliseconds). This script compares the returned SPRequestDuration to the unacceptableTime parameter and if the request took longer, it will output the SPRequestGUID which you can then use with Merge-SPLogFile to pull the ULS logs for the request.

param (
	
	$SharePointUrl = "https://yoursharepoint.example.com/demo/TypicalSharePointSite/SitePages/SomePageToTest.aspx",
	
	# Number of times to try hitting the page
	$numTries = 1000,
	
	# Number of milliseconds we'll say is too long for the page to return
	$unacceptableTime = 8000	
)

$timesTooLong = 0

# Repeat the number of times specified by $numTries
for ($i = 0; $i -lt $numTries; $i++) {

	# Build our URL to query SharePoint
	# We're going to abuse the rev parameter to trick our session into not caching the results from each query
	$requestUri = $SharePointUrl + "?rev=$i"
	
	# Issue our request to the fine SharePoint Server
	$Request = Invoke-WebRequest -Uri $requestUri -UseDefaultCredentials
	
	# The request took too long so send out the details
	if ([int]$Request.Headers["SPRequestDuration"] -gt $unacceptableTime) {
	
		Write-Output "$($Request.Headers["SPRequestGuid"]) $($Request.Headers["SPRequestDuration"])ms $requestUri"
		
		$timesTooLong++
	
	}
	
	
}

Write-Output "$timesTooLong request(s) took longer than $($unacceptableTime)ms"
Share Button

Clear the Configuration Cache in a SharePoint 2010, 2013, or 2016 farm

Here is a script that will clear the SharePoint Configuration Cache on all servers in the farm. This is a more compact script than the one I previously released.

Simply copy to one of the servers and run in an elevated PowerShell window. The script will determine where the configuration cache is stored on all servers in the farm, stop the timer services, clear the cache, reset the counter, and start the timer services again.

This script is provided as-is.

<#
.SYNOPSIS
Clear the Configuration Cache in a SharePoint 2010, 2013, or 2016 farm
  
.DESCRIPTION
Clear-SPConfigCache.ps1 will:
 1. Stop the SharePoint Timer Service on all servers in the farm
 2. Delete all xml files in the configuration cache folder on all servers in the farm
 3. Copy the existing cache.ini files as a backup
 4. Clear the cache.ini files and reset them to a value of 1
 5. Start the SharePoint Timer Service on all servers in the farm

Clear-SPConfigCache.ps1 will work in either single-server and multi-server farms.

Run in an elevated SharePoint Management Shell

Author: Jason Warren

.LINK
 http://jasonwarren.ca/ClearSPConfigCache ClearSPConfigCache.ps1
 
.EXAMPLE
 .\Clear-SPConfigCache.ps1
 
.INPUTS
None. Clear-SPConfigCache.ps1 does not take any input.

.OUTPUTS
Text output that describes the current task being performed.

#>


Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction Stop
$farm = Get-SPFarm
$ConfigDB = Get-SPDatabase | where {$_.Name -eq $Farm.Name}

# Configuration Cache is stored in %PROGRAMDATA\Microsoft\SharePoint\Config\[Config ID GUID]
# %PROGRAMDATA% is C:\ProgramData by default, it is assumed it's in the same location on all servers in the farm
#	i.e. if it's X:\ProgramData on one server, it will be X:\ProgramData on the others
# We'll be connecting via UNC paths, so we'll also change the returned DRIVE: to DRIVE$
$ConfigPath = "$(($env:PROGRAMDATA).Replace(':','$'))\Microsoft\SharePoint\Config\$($ConfigDB.Id.Guid)"

# Stop the timer service on all farm servers
$TimerServiceName = "SPTimerV4"
foreach ($server in $farm.TimerService.Instances.Server) {
	Write-Output "Stopping $TimerServiceName on $($server.Address)..."
	$service = Get-Service -ComputerName $server.Address -Name $TimerServiceName
	Stop-Service -InputObject $service -Verbose
} # Foreach server


$TimeStamp = Get-Date -Format "yyyymmddhhmmssms"

# Clear and reset the cache on each server in the farm
foreach ($server in $farm.TimerService.Instances.Server) {

	Write-Output $server.Address
	
	# build the UNC path e.g. \\server\X$\ProgramData\Microsoft\SharePoint\Config\00000000-0000-0000-0000-000000000000
	$ServerConfigPath = "\\$($server.Address)\$($ConfigPath)"
	
	# Delete the XML files
	Write-Output "Remove XML files: $ServerConfigPath..."
	Remove-Item -Path "$ServerConfigPath\*.xml"
	
	# Backup the old cache.ini
	Write-Output "Backup $ServerConfigPath\cache.ini..."
	Copy-Item -Path "$ServerConfigPath\cache.ini" -Destination "$ServerConfigPath\cache.ini.$TimeStamp"
	
	# Save the value of "1" to cache.ini
	Write-Output "Set cache.ini to '1'..."
	"1" | Out-File -PSPath "$ServerConfigPath\cache.ini"

	Write-Output ""
	
} #foreach server

#Start the timer service on all farm servers
foreach ($server in $farm.TimerService.Instances.Server) {
	Write-Output "Starting $TimerServiceName on $($server.Address)..."
	$service = Get-Service -ComputerName $server.Address -Name $TimerServiceName
	Start-Service -InputObject $service -Verbose
	
}
Share Button

Get a list of SharePoint sites that allow anonymous authentication

For administrators who manage (usually) public-facing SharePoint farms, it’s good to keep tabs on the sites that allow anonymous users. Configuring anonymous access is a multi-step process — there are web application settings, site settings, and permissions. Although there is a lot of configuration, it’s easy to see which sites allow anonymous authentication using the SPWeb.AnonymousState site-level flag. Using this property we can write a short PowerShell script to list out all the sites in the farm and display whether or not they allow anonymous authentication.

SharePoint 2013 and SharePoint 2010

For SharePoint 2010, SharePoint 2013, and presumably future versions of SharePoint, getting this list is simple using the Get-SPSite cmdlet which can be used to list every site collection in the farm:

$sites = Get-SPSite -Limit All
foreach ($site in $sites) {
	$site.AllWebs | Select Url, AnonymousState
}

The output will look like something like this:

Url                                         AnonymousState
---                                         --------------
http://example.com                                 Disabled
http://example.com/searchcenter                    Disabled
http://example.net                                      On
http://example.net/About                                On
http://example.net/Careers                              On
http://example.net/Contact                              On
http://example.net/Search                               On

SharePoint 2007

If you have PowerShell installed on a server in the farm (you really should), you can use PowerShell to build this handy report just it takes a bit more effort:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
$websvcs = $farm.Services | where -FilterScript {$_.GetType() -eq [Microsoft.SharePoint.Administration.SPWebService]}
$webapps = @()
foreach ($websvc in $websvcs) {
	foreach ($webapp in $websvc.WebApplications) {		
		foreach ($site in $webapp.Sites) {
		
			$Site.AllWebs | Select Url, AnonymousState
		
		}
    }
}

The output will look look the same as with later versions of SharePoint:

Url                                          AnonymousState
---                                          --------------
http://example.com                                 Disabled
http://example.com/searchcenter                    Disabled
http://example.com/sites/Example                         On
http://example.com/sites/Example/Site1                   On
http://example.com/sites/Example/Site1/SubSite           On

(HT to Gary Lapointe for the code to get the web applications in a SharePoint 2007 farm using PowerShell: Getting an SPWebApplication object using PowerShell.

Share Button

Add and remove MIME types from SharePoint (PowerShell)

Petro Margaritis has a PowerShell script for adding a MIME type to a SharePoint web application: Setting Trusted IIS MIME Types In SharePoint using PowerShell. I modified it to allow you to remove the MIME type if it already exists:

Write-Host "This script will check if a particular MIME Type is excluded from the AllowedInlineDownloadedMimeTypes list when STRICT Browser File Handling Permissions are set on the Web Application" -foregroundcolor Darkcyan
$webAppRequest = Read-Host "What is the name of your Web Application? i.e. http://<serverName>"
$webApp = Get-SPWebApplication $webAppRequest
$mimeType = Read-Host "Which MIME Type would you like to confirm is included in the AllowedInlineDownloadedMimeTypes list for $webApp ? i.e. application/pdf"
If ($webApp.AllowedInlineDownloadedMimeTypes -notcontains "$mimeType")
{
    write-host "$mimeType does not exist in the AllowedInlineDownloadedMimeTypes list" -foregroundcolor Yellow
    $addResponse = Read-Host "Would you like to add it? (Yes/No)"
    if ($addResponse -contains "Yes")
    {
        $webApp.AllowedInlineDownloadedMimeTypes.Add("$mimeType")
        $webApp.Update()
        Write-Host "The MIME Type ' $mimeType ' has now been added" -foregroundcolor Green
        $iisresponse = Read-Host "This change requires an IIS Restart to take affect, do you want to RESET IIS now (Yes/No)"
        if ($iisResponse -contains "Yes")
        {
            IISRESET
            Write-Host "IIS has now been reset" -foregroundcolor Green
        }
        else
        {
            Write-Host "IIS has not been reset, please execute the IISRESET command at a later time" -foregroundcolor Yellow
        }
    }
    else
    {
        Write-Host "The MIME Type ' $mimeType ' was not added" -foregroundcolor Red
    }
}
else
{
    Write-Host "The MIME Type ' $mimeType ' already exists in the AllowedInlineDownloadedMimeTypes list for this Web Application" -foregroundcolor Yellow
	$addResponse = Read-Host "Would you like to remove it? (Yes/No)"
    if ($addResponse -contains "Yes")
    {
		$webApp.AllowedInlineDownloadedMimeTypes.Remove("$mimeType")
        $webApp.Update()
        Write-Host "The MIME Type ' $mimeType ' has now been removed" -foregroundcolor Green
        $iisresponse = Read-Host "This change requires an IIS Restart to take affect, do you want to RESET IIS now (Yes/No)"
        if ($iisResponse -contains "Yes")
        {
            IISRESET
            Write-Host "IIS has now been reset" -foregroundcolor Green
        }
        else
        {
            Write-Host "IIS has not been reset, please execute the IISRESET command at a later time" -foregroundcolor Yellow
        }
	}
    else
    {
        Write-Host "The MIME Type ' $mimeType ' was not removed" -foregroundcolor Red
    }

}
Share Button

Script: Clearing the SharePoint configuration cache on all servers in the farm

Need to clear the configuration cache on all of your SharePoint servers but don’t want to take the time to do it manually?

If you’ve configured PowerShell Remoting between the farm servers and are logged onto any server in the farm with an administrative account, you can run this script to automate this process.

Note the folder is for SharePoint 2010 and SharePoint 2013.

I borrowed the bulk of the clearing code from Thomas Bernhard’s blog post Clear SharePoint Config Cache with PowerShell and wrapped it in a script block so we can run it remotely.

Save the code below in a .ps1 and run it from one of the SharePoint servers in the farm in an elevated PowerShell window (you could also just paste it into the PowerShell window if you’re into that sort of thing).

#Script block for stopping the timer service
$sb_stop = {
	Write-Output "`t$($env:computername)"
	Stop-Service -Name "SPTimerV4"
}

#Script block for starting the timer service
$sb_start = {
	Write-Output "`t$($env:computername)"
	Start-Service -Name "SPTimerV4"
}

#Script block for finding and clearing the configuration cache
$sb_cache = {
	Write-Output "`t$($env:computername)"
	
	$folders = Get-ChildItem "C:\ProgramData\Microsoft\SharePoint\Config"
	
	foreach ($folder in $folders) {
		$items = Get-ChildItem $folder.Fullname -Recurse
		foreach ($item in $items) {
			if ($item.Name.ToLower() -eq "cache.ini") {
				$cachefolder = $folder.FullName
			} #if
		} #foreach item
	} #foreach folder
	
	Write-Output "`tDeleting xml..."	
	$cachefolderitems = Get-ChildItem $cachefolder -Recurse
	foreach ($cachefolderitem in $cachefolderitems) {
		if ($cachefolderitem -like "*.xml") {
			$cachefolderitem.Delete()
		} #if
	} #foreach
	
	Write-Output "`tResetting cache ini..."
	$a = Get-Content $cachefolder\cache.ini
	$a = 1
	Set-Content $a -Path $cachefolder\cache.ini

} # sb


Add-PSSnapin Microsoft.SharePoint.PowerShell
$servers = Get-SPServer | where {$_.Role -eq "Application"} | select -ExpandProperty Address
Write-Output "Servers in the farm: $servers"


#Stop timer
foreach ($server in $servers) {
	Write-Output "Stopping Timer Service on $server"
	Invoke-Command -Computername $server -ScriptBlock $sb_stop
	Write-Output " "
}

#Clear cache
foreach ($server in $servers) {
	Write-Output "Clearing configuration cache on $server"
	Invoke-Command -Computername $server -ScriptBlock $sb_cache
	Write-Output " "
}

#Start Timer
foreach ($server in $servers) {
	Write-Output "Starting Timer Service on $server"
	Invoke-Command -Computername $server -ScriptBlock $sb_start
	Write-Output " "
}

The output will look something like this:
clearconfigcache

Share Button

Are we using SharePoint Enterprise Features?

Here’s a quick PowerShell script (actually two scripts) that will go through your web applications, site collections, and sites and tell you which ones are using Enterprise features.

The first script is for SharePoint 2010 and SharePoint 2013:

Add-PSSnapin Microsoft.SharePoint.PowerShell
foreach ($webapp in Get-SPWebApplication) {

	foreach ($feature in $webapp.Features) {

		if ($feature.Definition.Displayname -eq "PremiumWebApplication") {
			Write-Output "$($Webapp.DisplayName) contains enterprise web application features"
		} # if enterprise web application feature

	} # foreach web application feature

	foreach ($site in $webapp.Sites) {

		foreach ($feature in $Site.Features) {

			if ($feature.Definition.Displayname -eq "PremiumSite") {
				Write-Output "$($Site.Url) contains enterprise site collection features"
			} # if enterprise site collection feature

		} # foreach site collection feature

		foreach ($web in $site.AllWebs) {

			foreach ($feature in $web.Features) {

				if ($feature.Definition.Displayname -eq "PremiumWeb") {
					Write-Output "$($web.Url) contains enterprise site features"
				} # if enterprise site feature

			} # foreach site feature

		} # foreach site

	} # foreach site collection

} # foreach web application

The second is for SharePoint 2007:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
$websvcs = $farm.Services | where -FilterScript {$_.GetType() -eq [Microsoft.SharePoint.Administration.SPWebService]}
$webapps = @()
foreach ($websvc in $websvcs) {
    foreach ($webapp in $websvc.WebApplications) {  

		foreach ($feature in $webapp.Features) {
						
			if ($feature.Definition.Displayname -eq "PremiumWebApplication") {
				Write-Output "$($Webapp.DisplayName) contains enterprise web application features"
			} # if enterprise web application feature
			
		} # foreach web application feature
			
        foreach ($site in $webapp.Sites) {
		
			foreach ($feature in $Site.Features) {
				
				if ($feature.Definition.Displayname -eq "PremiumSite") {
					Write-Output "$($Site.Url) contains enterprise site collection features"
				} # if enterprise site collection feature
				
			} # foreach site collection feature
	
			foreach ($web in $site.AllWebs) {
			
				foreach ($feature in $web.Features) {
				
					if ($feature.Definition.Displayname -eq "PremiumWeb") {
						Write-Output "$($web.Url) contains enterprise site features"
					} # if enterprise site feature
					
				} # foreach site feature
				
			} # foreach site
			
		} # foreach site collection
		
	} # foreach web application
						
} # foreach web service

The output will look something like this:

WebAppExample1 contains enterprise web application features
http://webappexample1/sites/Test contains enterprise site collection features
http://webappexample1/sites/Test contains enterprise site features
http://webappexample1/sites/Test/Site1 contains enterprise site features
http://webappexample1/sites/Test/Site1/SubSite contains enterprise site features
http://webappexample1/sites/testteamsite contains enterprise site collection features
http://webappexample1/sites/testteamsite contains enterprise site features
WebAppExample2 contains enterprise web application features
MySites contains enterprise web application features
SSPAdmin contains enterprise web application features
http://sspadmin/ssp/admin contains enterprise site collection features
http://sspadmin/ssp/admin/Content contains enterprise site features
Share Button

Where’s that pesky Correlation ID?

Sometimes when you’re kicking around on a SharePoint site you encounter something strange or you get an error. On some sites, for example a public web site, the error may not contain the correlation ID — SharePoint’s unique identifier for your request — that comes standard on error pages in SharePoint 2010 and SharePoint 2013. At some point the site’s architect decided outputting this to the user wasn’t something they wanted and the developers removed it from the error page. As in, the “error page” is “friendly” and contains no “useful” diagnostic information.

Not having the correlation ID makes troubleshooting difficult, because the ID helps enormously with tracking down exceptions and makes following the flow of a request within the ULS logs (relatively) simple.

[Got a correlation ID and not sure how to find the log entries? Check out An even better way to get the real SharePoint error from the ULS logs featuring the always excellent Merge-SPLogFile SharePoint PowerShell cmdlet)]

Thankfully, SharePoint tells you the correlation ID on every request to the site, even if there weren’t any errors. Finally reading ULS logs becomes a realistic hobby.

So where is the correlation ID? It’s in the SPRequestGuid HTTP response header (MSDN: SPResponseGuid). If you’re using a tool like Fiddler, it captures all the headers in its log. This is useful if you or your testers are doing lots of tests and you want to review a specific test in the logs later.

If you don’t use Fiddler, never fear. Chrome, Firefox, and probably IE can show you the headers in their “developer tools” (on Windows, other browsers and platforms may too).

Correlation IDs were introduced in SharePoint 2010 so this will only work in SharePoint 2010 or newer farms including SharePoint Online (Office 365)! You may wonder how useful it is to have the correlation ID in SPO (or any hosted SharePoint solution) since you don’t have physical access to the ULS logs, but consider providing the correlation ID to Microsoft Support when working with them so you can help them narrow down your request from the hojillion requests hitting their servers. Actually, same thing if you’re not the farm administrator. Putting the correlation ID in your email to your SharePoint administrators for them it’s like winning the lottery. You’ll totally make their day.

Let’s see it in action. In Chrome it looks something like this for SharePoint 2010:

The SPRequestGuid HTTP response header holds the correlation ID for a request to a SharePoint 2010 site
The SPRequestGuid HTTP response header holds the correlation ID for a request to a SharePoint 2010 site

SharePoint 2013:

The SPRequestGuid HTTP response header holds the correlation ID for a request to a SharePoint 2013 site
The SPRequestGuid HTTP response header holds the correlation ID for a request to a SharePoint 2013 site

SharePoint Online:

The SPRequestGuid HTTP response header holds the correlation ID for a request to a SharePoint Online site
The SPRequestGuid HTTP response header holds the correlation ID for a request to a SharePoint Online site

Wonderful.

Share Button

Opening SharePoint Networking Ports Before Creating a Farm

There are a few articles up on TechNet about hardening SharePoint:

Plan security hardening for server roles within a server farm (Office SharePoint Server)
Plan security hardening (SharePoint Server 2010)
Plan security hardening for SharePoint 2013

These guides detail the networking ports SharePoint needs in order to function.  And there are quite a few ports:

  • TCP 80, 443, custom Web applications
  • TCP 16500-16519 Search index component
  • TCP 22233-22236, ICMP AppFabric Caching Service, which is used by the Distributed Cache SharePoint service
  • TCP 808 Windows Communication Foundation used for communication between search components
  • TCP 32843 (HTTP), TCP 32844 (HTTPS), TCP 32845 (net.tcp) SharePoint web services
  • TCP 5725 Forefront Identity Manager (FIM), used by user profile service
  • TCP/UDP 389 (LDAP), TCP/UDP 88 (Kerberos), TCP/UDP 53 (DNS), UDP 464 (Kerberos Change Password) Active Directory queries and integration
  • TCP 1433 SQL Server
  • UDP 1434 SQL Server Browser (if using a non-default SQL instance and you’re not specifying the port in the connection string)
  • TCP 25 Incoming/Outgoing email

Anyway, my advice is to ensure these ports are opened on your farm servers before installing SharePoint. Out of the box Windows Firewall or a Group Policy Object (GPO) may block some of these ports, as well consider any network firewalls and ensure they are not blocking the ports between servers. There’s nothing like running in to issues while setting up a farm and finally figuring out the issue is because one of these ports is blocked!

I’m currently developing a SharePoint 2013 hardening guide which will look at these ports in more detail — why they’re needed, what they do, and on which servers they need to be opened. Stay tuned!

Share Button

X of X slides that were being published to http://sharepoint/slide/library failed. Try publishing again.

If you receive the error,

X of X slides that were being published to http://sharepoint/slide/library failed. Try publishing again

when trying to publish a PowerPoint file or slide to a SharePoint Slide Library where X is the number of slides in the presentation, make sure the WebClient Windows service is present on your computer and started.

To see if it’s present and its status, open an elevated CMD prompt and use sc.exe:

sc query WebClient

If it’s stopped, start it:

net start WebClient

The service may not be on your system. The WebClient service is normally a part of the client machines (Windows XP, Vista, 7, 8). On Windows Server you need to add the Desktop Experience Feature which will install the service. You’ll need to reboot as well. Once the server is back up you can start the WebClient service.

That said, WebClient is a client service. It’s not needed on a SharePoint server, just the end users need it.  You shouldn’t be installing the service on a SharePoint server unless you know what you’re doing. 😉

Share Button