New-SPProfileServiceApplication -MySiteManagedPath documentation bug

Hot on the heels of my previous post, New-SPProfileServiceApplication -SiteNamingConflictResolution documentation bug, the -MySiteManagedPath parameter also has inconsistent documentation with the actual cmdlet in the wild.

[Note for reference this applies at the time of this writing to SharePoint Server 2013 with the March 2013 PU + December 2013 CU, farm buildversion 15.0.4551.1508]

TechNet defines the MySiteManagedPath parameter like this:

Parameter Required Type Description
MySiteManagedPath Optional System.String Specifies the managed path where personal sites will be created.The type must be a valid URL, in the form http://server_name.

And Get-Help New-SPProfileServiceApplication -Full like so:

-MySiteManagedPath <SPPrefixPipeBind>
    Specifies the managed path where personal sites will be created.


    The type must be a valid URL, in the form http://server_name.



    Required?                    false
    Position?                    Named
    Default value
    Accept pipeline input?       True
    Accept wildcard characters?  false

Both documentation references say you need to provide a valid URL. Of course, you’re providing a managed path so a better example would be something like “http://server_name/managedpath”.

When you specify a URL the cmdlet will throw a Microsoft.SharePoint.PowerShell.SPCmdletPipeBindException with the message:

Cannot find an SPPrefix object with Name: http://server_name/managedpath

What the cmdlet really wants is the actual name of the managed path. The cmdlet runs as expected when you give it a managed path name (that exists!) instead of a URL.

For example, say you have a My Sites web application http://mysites and you’ve created a Wildcard Inclusion managed path called “personal”.

The documentation says to do this (incorrect):

New-SPProfileServiceApplication ... -MySiteManagedPath "http://mysites/personal"

Instead give it the name of the managed path like this (correct):

New-SPProfileServiceApplication ... -MySiteManagedPath "personal"
Share Button

New-SPProfileServiceApplication -SiteNamingConflictResolution documentation bug

As of the writing of this post, there’s a weird discrepancy with the SharePoint 2013 New-SPProfileServiceApplication documentation and the actual expected values for the -SiteNamingConflictResolution parameter. This parameter allows you to specify the resolution method for naming personal sites when two users in different domains share the same account name.

[Note for reference this applies at the time of this writing to SharePoint Server 2013 with the March 2013 PU + December 2013 CU, farm buildversion 15.0.4551.1508]

From TechNet:

Parameter Required Type Description
SiteNamingConflictResolution Optional System.String Specifies the format to use to name personal sites.

Use one of the following integer values:

1   Personal site collections are to be based on user names without any conflict resolution. For example, http://portal_site/location/username/

2   Personal site collections are to be based on user names with conflict resolution by using domain names. For example, …/username/ or …/domain_username/

3   Personal site collections are to be named by using domain and user name always, to avoid any conflicts. For example, http://portal_site/location/domain_username/

The default value is 1 (do not resolve conflicts).

Please ignore for a moment that the type is a String and it says you need to specify an integer value. There’s a similar description from Get-Help New-SPProfileServiceApplication -Full:

-SiteNamingConflictResolution
    Specifies the format to use to name personal sites.

    Use one of the following integer values:

    1   Personal site collections are to be based on user names without any conflict resolution. For example,
    http://portal_site/location/username/

    2   Personal site collections are to be based on user names with conflict resolution by using domain names.
    For example, .../username/ or .../domain_username/

    3   Personal site collections are to be named by using domain and user name always, to avoid any conflicts.
    For example, http://portal_site/location/domain_username/

    The default value is 1 (do not resolve conflicts).

    Required?                    false
    Position?                    Named
    Default value
    Accept pipeline input?       False
    Accept wildcard characters?  false

Alright, so to specify the way I want to handle username conflicts for personal sites, I need to provide either a value of 1, 2, or 3 … or maybe “1”, “2”, or “3”. Of course, this blog post wouldn’t exist if this worked as written and both options are incorrect. 🙂

Specifying any of these values throws a System.Management.Automation.ParameterBindingValidationException with the message:

Cannot validate argument on parameter ‘SiteNamingConflictResolution’. The argument “2” does not belong to the set “None,Resolve,Block” specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again.

[Note: Whether you provide an integer (e.g. 2) or string (e.g. “2”) the exception message puts your value in quotes]

So the numbers don’t work because the parameter is validated against this set of values:

  • “None”
  • “Resolve”
  • “Block”

These values match up to the integers discussed in the documentation:

  1. “None” – no conflict resolution (prepare for fights!). Use this only if your users are in a single domain
  2. “Resolve” – add on the domain name for any conflicting accounts after the first exists. This is useful if most of your users come from one domain and there are some users in a different domain
  3. “Block” – block conflicts by always including the domain name. Use this if you have more than one domain and lots of users

Replace the numbers in your script with these values (1 -> “None”, 2 -> “Resolve”, 3 -> “Block”) and you should now be able to create your user profile service application.

Share Button

Changing the Distributed Cache Service Account

So you want to follow the security by least privileges best practice for your SharePoint 2013 farm and decide to create a dedicated service account for distributed cache. You head on over to TechNet and check out Manage the Distributed Cache service in SharePoint Server 2013: Change the service account where you find the following script:

$farm = Get-SPFarm
$cacheService = $farm.Services | where {$_.Name -eq "AppFabricCachingService"}
$accnt = Get-SPManagedAccount -Identity domain_name\user_name
$cacheService.ProcessIdentity.CurrentIdentityType = "SpecificUser"
$cacheService.ProcessIdentity.ManagedAccount = $accnt
$cacheService.ProcessIdentity.Update() 
$cacheService.ProcessIdentity.Deploy()

Provided you’ve already added your dedicated service account as a Managed Account, the script works. The trouble is the documentation is missing one important piece of information: the service account needs to be a local machine administrator on all the cache hosts before running the Deploy() method (the last line).

If the account is not a local machine administrator, you’ll get this exception after waiting a number of minutes:

Exception calling "Deploy" with "0" argument(s): "Error occurred while performing the operation on host
CACHEHOST:22233 : ErrorCode<ERRCAdmin003>:SubStatus<ES0001>:Time-out occurred on
net.tcp://CACHEHOST.example.com:22233."
At line:1 char:1
+ $cacheservice.ProcessIdentity.deploy()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : CmdletInvocationException

What happens is the AppFabricCachingService Windows service gets stuck on starting because the service account doesn’t have the necessary rights on the server to set up the service for the first time. Grant it local admin and Deploy() goes off smoothly.

Remember to remove the local admin rights for the service account and restart the server after distributed cache is running. After all you’re following least privileges and the last thing you want is a service account running around as a local administrator.

Note as well when you first set up the farm distributed cache uses the farm service account which too needs to be a local admin for the same reason (the AppFabricCachingService won’t start otherwise).

One last reminder: if you spin up a new server or want to turn on distributed cache on another server in the farm you’ll need to first grant the current distributed cache service account local admin rights on the new server otherwise you’ll encounter the same issue.

Share Button

Distributed Cache Needs Ping

After setting up a number of SharePoint 2013 farms in different environments I discovered that to correctly set up the Distributed Cache service you require allowing ICMPv4 (ping) traffic between the cache hosts. This requirement is partially documented at the bottom of a TechNet page.

Check out the full story in the Habanero Insight, Distributed Cache Needs Ping

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