Archive for the ‘SharePoint 2010’ Category

SharePoint Tools learned at ShareCamp

April 20, 2013

I had the opportunity to attend to ShareCamp in Microsoft München and hier are some interesting tools that I saw during the lessons:

Name Description
Search query tool Really nice tool for generating search queries against SharePoint 2013. You can see the xml and field names that come from SharePoint. Really helpful when creating custom search templates.
dotPeek A free alternative to .NET Reflector by JetBrains
PowerGUI A free tool like Powershell ISE but better.
IronSP Interesting tool for development for SharePoint in Ruby. Currently under development and not simple to use without deep knowledge of the project.
Collaboration Manager A commercial tool for managing SharePoint templates including upgrades. However it costs lots of money.

Hope you find this list helpful.

Fixing Metadata Field Connection after importing a Website to another Farm

April 10, 2013

This is a follow up to this post, where I described how you can create new website from template using Import-SPWeb. If you use managed metadata fields in the you will find out, that these fields cannot be used after importing of the website. The reason is, that the link to the managed metadata application is broken. This script will fix it:

$url = "http://yoursitecollection"
$termStoreName = "yourTermStoreName"
$termSetName = "nameOfTheLinkedTermSet"
$listName = "nameOfTheListWithManagedMetadataField"
$fieldName = "nameOfTheManagedMetadataField"

$web = Get-SPWeb $url

$session = Get-SPTaxonomySession -Site $url

$termStore = $session.TermStores[0]

$group = $termStore.Groups[$termStoreName]

$termSet = $group.TermSets[$termSetName]

$list = $web.Lists[$listName]
$field = $list.Fields[$fieldName]
$field.SspId = $termStore.Id

$field.TermSetId = $termSet.Id
$field.Update()

$list = $web.Lists[$listName]
$field = $list.Fields[$fieldName]

$taxonomyList = $web.Lists["TaxonomyHiddenList"]

$field.SchemaXml = $field.SchemaXml.Replace($field.LookupWebId.ToString(), $web.ID.ToString())
$field.SchemaXml = $field.SchemaXml.Replace($field.LookupList.ToString(), $taxonomyList.ID.ToString())
$field.Update()

$web.Dispose()

The script relinks the managed metadata field to the termstore and fixed the link to the webid and link to the taxonomy hidden list.

Custom templates using SP-ExportWeb

March 25, 2013

When creating custom templates for users, you have following possibilities:

  1. Create a template in Visual Studio
  2. Create a template website in SharePoint and save website as a template (wsp).
  3. Create a template website in SharePoint and save it with Export-SPWeb powershell command.

Each of this solutions has its drawbacks:

Ad 1. complex and time consuming solution, prone to errors.
Ad 2. Following features are not supported: Customized permissions, running workflow instances, list item version history, workflow tasks associated with running workflows, people or group field values, taxonomy field values, publishing pages and publishing sites, My Sites, and stapled features. See following article http://msdn.microsoft.com/en-us/library/jj938033.aspx#bkmk_WhatIsTemplate
Ad 3. the taxonomy fields in the website created from template in the different sharepoint farm will be broken.

As the title suggests I will describe the third option in this article.

Creating the template

  1. Create your template in SharePoint. (Activate the features, add lists, fields and documents)
  2. Open the Powershell console and execute following command:

Export-SPWeb http://yoursite–Path "c:\temp\export.cmp"

Creating a website from the template
Create new empty website and use the Import-SPWeb to import the content from the file:
New-SPSite http://newsiteurl/ -OwnerAlias "loginname" -Name "newWebSiteName"
Import-SPWeb http://newsiteurl/ -Path "c:\temp\export.cmp" -IncludeUserSecurity

The advantage of this approach is, that if you create a new version of the template you can reimport it on an existing website. The changes in the new template will be merged with the changes in the existing website made by the users . However I recommend to create a backup from the website before reimporting.

There are two things  that remain open:

  1. The metadata fields will not be relinked to the termsets after importing into another farm.
  2. The “Self Service Creation”-like functionality is missing. There is some development that needs to be done.

Maybe next time.

 

Announcement

March 25, 2013

Recently me and my friend Radek Matouch  started a new company. We focus on development and consulting in SharePoint  and .NET. Check out our website www.codeeffect.cz if you are interested and wish us luck . 😉

Multilanguage in Navigation using Webtemplate does not work

May 15, 2012

I created a webtemplate (http://msdn.microsoft.com/en-us/library/ms434313.aspx) in SharePoint and added following localized Navigation Bar to the top the navigation in the onet.xml:

<NavBar Name="$Resources:osrvcore,SspAdministrationTopNavBarTitle;" ID="1002">
<NavBarLink Name="$Resources:osrvcore,HelpText;" Url="default.aspx" />
 </NavBar>

then I created a web site based on the template and turned the multilanguage on.

The problem is that the navigation bar stays always in one language and is never localised to current language of the website. If I use the same xml file in the sitetemplate everything works correctly.

The problem is recognized as designed by Microsoft and there is only workaround available.

Solution

  1. Delete the navigation from the onet.xml
  2. Recreate the Navigation with code.

Creating the navigation programmatically

  • Create the xml file called navigation.xml with the navigation and let it be deployed to the layouts folder. The file should have following structure:
</div>
<?xml version="1.0" encoding="utf-8" ?>
<NavBars>
<NavBar Template="templatename">
<NavBarLink Url="$Resources:cmscore,List_Pages_UrlName;/page1.aspx" Name="$Resources:osrvcore,HelpText"/>
 <NavBarLink Url="$Resources:cmscore,List_Pages_UrlName;/page2.aspx" Name="$Resources:osrvcore,HelpText"/>
</NavBar>
</NavBars>
  • Load the xml file:
public IList<NavigationNode> GetNavigation(string templateName)
{
{
var fileName = SPUtility.GetGenericSetupPath("TEMPLATE\\LAYOUTS\\navigation.xml");
var navigation = new List<NavigationNode>();
var data = new XmlDocument();
data.Load(fileName);
var xpath = string.Format("/NavBars/NavBar[@Template='{0}']/NavBarLink", templateName);
var nodes = data.SelectNodes(xpath);

foreach (XmlNode node in nodes)
{
navigation.Add(new NavigationNode
{
Name = node.Attributes["Name"].Value,
Url = node.Attributes["Url"].Value
});
}

return navigation;
}
}
  • Add the navigation nodes to the top navigation. There is also handling if the url contains resources that have to be replaced
foreach (var navigationNode in GetNavigation(templatename))
{
var parsedUrl =  ParseNavigationUrl(navigationNode.Url, web.Language);
var spNavigationNode = new SPNavigationNode(navigationNode.Name, parsedUrl, true);
web.Navigation.TopNavigationBar.AddAsLast(spNavigationNode);
}
private static string ParseNavigationUrl(string url, uint language)
{
var resourceExpression = GetResourceExpressionFromString(url);
if (string.IsNullOrEmpty(resourceExpression))
return url;
var localizedString = SPUtility.GetLocalizedString(resourceExpression, string.Empty, language);           return url.Replace(resourceExpression, localizedString);
}
private static string GetResourceExpressionFromString(string text)
{
if (string.IsNullOrEmpty(text))
return string.Empty;
var dollarIndex = text.IndexOf("$");
var semicolonIndex = text.IndexOf(";");
if ((dollarIndex == -1) || (semicolonIndex == -1))
return string.Empty;
return text.Substring(dollarIndex, semicolonIndex - dollarIndex + 1);
}

Custom Solutions on Multiple Server SharePoint Farm

April 23, 2012

Consider following basic Farm Configuration

The Web Frontend Server processes the requests and the application server is designated for other applications like search. According to Microsoft best practices you should turn off the “Microsoft SharePoint Foundation Web Application” service on the application server.

If you do this and you have a solution that contains web, site or webapplication scoped features your solution will be deployed only on the web front end server. This is pretty bad if you have timer jobs that should run on the application server. The dlls on the application server are missing and the timerjob will fail.

Here are your options:

  1. Turn the “Microsoft SharePoint Foundation Web Application” role on again. The drawback is that you in this do not follow the best practices from Microsoft. The other drawback ist that the web applications will take resources on the App Server (RAM, Applicaiton pools)
  2. Turn of the timer job service on the application server. The drawback is that you actually disable the application server and change the farm to single farm solution.
  3. Split the solutions
Split the solution into two separate solutions.

The first solution will contain the farm timer jobs and farm scoped features and will be deployed globally. It means also on the application server. The other solution will contain all web, site or webapplication scoped features and will be deployed into your web application as before.

One thing you have to do is to change the deployment type of the farm scoped solution to Application Server. Open the package folder in the solution and in the properties window change the deployment server type to ApplicationServer. See screenshot

The other nice thing that you could do is to create an activationdependency from the WFE soltuion to the APP server solution.


Google Id/Windows Authentication in SharePoint 2010 using Windows Azure

December 11, 2011

In this article I will describe how to enable signing in using Google Id, Windows Open Id, Facebook or Yahoo account to a SharePoint 2010 site collection. As authentication provider I will use Windows Azure Platform.
Here are the steps you have to do:

Configure the Azure platform

  1. Create an account on Windows Azure Platform using your Windows Live Id. There is 90 days evaluation period available on Windows Azure that is free, additionaly the Access Control Services I will use as authnetication provider are free at least until December 2012. During the registration process you will be however asked to fill in you credit card number. For more information about pricing see this.
  2. After you created your azure account go to the Windows Azure management portal  https://windows.azure.com/.
  3. In the portal click “Services Bus, Access Control & Caching ” and then “Access Control”. See following picture
  4. Click new to create a new namespace and select a unique name for the namespace and the region where your server exists and click “Create namespace” button
  5. Wait until the namespace is activated. It takes several minutes
  6. Click the newly created namespace and then “Access Control Service”
  7. Click “Identity providers” and add the providers that should be used in your SharePoint site collection for the authentication. See folllowing image.
  8. Click Relying party application button in the left tab and add a new Relying application and fill the form as marked in the following image. The url should be the url of your sharepoint web application.
  9. Also check the “Create new rule group”
  10. Now click the “Rule groups” and click Generate. The form should look like this afterwards:
  11. Click save.
  12. Click  “Application Integration” under “Development” tab. Then “Login pages” and then your relying service application.
  13. Copy the content of the textbox und option 1. It should look like this https://yournamespace.accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&wtrealm=http%3a%2f%2fsharepoint2010%2f
  14. For now you are done with the azure platform configuration. Now go to your SharePoint server where should be the claims authentication enabled.

Create and export new certificate

  1. Run following command “MakeCert.exe -r -pe -n “CN=<yournamespace>.accesscontrol.windows.net” -sky exchange -ss my”. The Makecert.exe can you find in this folder: C:\Program Files\Microsoft Office Servers\14.0\Tools
  2. Here http://msdn.microsoft.com/en-us/library/gg185932.aspx  you can find a description how to export the newly created certificate for the communication betwen SharePoint and Azure.
  3. Once you have the file go back to Azure platform to your namespace and click “Certificates and keys” and click “Add” button in the “Token signing” section.
  4. Upload the exported certificate and leave the other setings to default

Configure SharePoint to use claims
Run following script. Replace following things:

  1. Path to the certificate
  2. Password of the certificate
  3. $realm (it is the Url you gave in the Relying Application Settings as Realm). Mind the slashes.
  4. $signinurl It is the url from step 17
  5. The names of the providers.

Add-PSSnapin "Microsoft.SharePoint.PowerShell"

$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("yourcertificatename.pfx","yourpassword")

$map1 = New-SPClaimTypeMapping "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" -IncomingClaimTypeDisplayName "Email" -SameAsIncoming

$realm = "http://sharepoint2010/"

$signinurl = "https://yournamespace.accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&wtrealm=http%3a%2f%2fsharepoint2010%2f"

New-SPTrustedIdentityTokenIssuer -Name "Azure ACS" -Description "Windows Azure ACS v2" -Realm $realm -ImportTrustCertificate $cert -ClaimsMappings $map1 -SignInUrl $signinurl -IdentifierClaim $map1.InputClaimType

New-SPTrustedRootAuthority -Name "Azure Test Token Signing" -Certificate $cert

$issuer = Get-SPTrustedIdentityTokenIssuer
$authority = Get-SPTrustedRootAuthority
$issuer.ProviderUri = $signinurl
$issuer.Update

Check if the things work:

  1. Open central administration and open Web application
  2. Click Create new Web application
  3. Switch to claims authentication
  4. Check the “Azure ACS”
  5. Create new web application
  6. Create new site collection
  7. Set the permissions on the site collection that the users have access to the site collection
  8. Log in with your Google Id to the site collection

References:  Travis Nielsen blog

Creating Secure Store Service Application through Powershell

November 24, 2011

SSSA is a good way how to store credentials for accessing external systems.
Here is a script that will help you to create such a service application through powershell.
Thanks to the codeplex project autospinstaller for the inspiration.

Add-PsSnapin Microsoft.SharePoint.PowerShell
$serviceApplicationPool  = "SecurityTokenServiceApplicationPool" #name of the application pool under which the application should run
$secureStoreDatabaseName  = "SecureStoreServiceDatabase" #the sharepoint database where the service app will store the data
$secureStoreApplicationName  ="Secure Store Service Application" #name of the service application
$secureStoreApplicationProxyName  ="Secure Store Service Application Proxy" #name of the service application proxy
$secureStoreAdministrator = "domain\administrator" #the administrator of the application
$secureStoreUser = "domain\user" #the group or user that will have access to service application. I use the group configuration
$secureStoreAdministratorEmail = "adminemail" #email of the administrator
$serviceContext = "http://localhost" # the url for getting the service application context
$targeApplicationUserName= "administrator" #user name which will be used to access the external application
$targetApplicationUserPassword = "password"
#password which will be used to access the external application
$passPhrase = "PassPhrase" #passphrase for securing the application

If ($secureStoreApplicationName -eq $null) {$secureStoreApplicationName = "State Service Application"}
# Get the service instance
$SecureStoreServiceInstances = Get-SPServiceInstance | ? {$_.GetType().Equals([Microsoft.Office.SecureStoreService.Server.SecureStoreServiceInstance])}
$SecureStoreServiceInstance = $SecureStoreServiceInstances | ? {$_.Server.Address -eq $env:COMPUTERNAME}
If (-not $?) { Throw " - Failed to find Secure Store service instance" }
# Start Service instance
If ($SecureStoreServiceInstance.Status -eq "Disabled")
{
	Write-Host  " - Starting Secure Store Service Instance..."
	$SecureStoreServiceInstance.Provision()
	If (-not $?) { Throw " - Failed to start Secure Store service instance" }
	# Wait
	Write-Host  " - Waiting for Secure Store service..." -NoNewline
	While ($SecureStoreServiceInstance.Status -ne "Online")
	{
	   Write-Host  "." -NoNewline
		Start-Sleep 1
		$SecureStoreServiceInstances = Get-SPServiceInstance | ? {$_.GetType().ToString() -eq "Microsoft.Office.SecureStoreService.Server.SecureStoreServiceInstance"}
		$SecureStoreServiceInstance = $SecureStoreServiceInstances | ? {$_.Server.Address -eq $env:COMPUTERNAME}
	}
	Write-Host  $($SecureStoreServiceInstance.Status)
}
			# Create Service Application
			$GetSPSecureStoreServiceApplication = Get-SPServiceApplication | ? {$_.GetType().Equals([Microsoft.Office.SecureStoreService.Server.SecureStoreServiceApplication])}
			If ($GetSPSecureStoreServiceApplication -eq $Null)
			{
				Write-Host  " - Creating Secure Store Service Application..."
				New-SPSecureStoreServiceApplication -Name $secureStoreApplicationName -PartitionMode:$false -Sharing:$false -DatabaseName $secureStoreDatabaseName -ApplicationPool $serviceApplicationPool -AuditingEnabled:$true -AuditLogMaxSize 30 | Out-Null
				Write-Host  " - Creating Secure Store Service Application Proxy..."
				Get-SPServiceApplication | ? {$_.GetType().Equals([Microsoft.Office.SecureStoreService.Server.SecureStoreServiceApplication])} | New-SPSecureStoreServiceApplicationProxy -Name $secureStoreApplicationProxyName -DefaultProxyGroup | Out-Null
				Write-Host  " - Done creating Secure Store Service Application."
			}
			Else {Write-Host  " - Secure Store Service Application already provisioned."}

			$secureStore = Get-SPServiceApplicationProxy | Where {$_.GetType().Equals([Microsoft.Office.SecureStoreService.Server.SecureStoreServiceApplicationProxy])}
			Start-Sleep 5
			Write-Host  " - Creating the Master Key..."
			Update-SPSecureStoreMasterKey -ServiceApplicationProxy $secureStore.Id -Passphrase $passPhrase
			Start-Sleep 5
			Write-Host  " - Creating the Application Key..."
			Update-SPSecureStoreApplicationServerKey -ServiceApplicationProxy $secureStore.Id -Passphrase $passPhrase -ErrorAction SilentlyContinue

$usernameField = New-SPSecureStoreApplicationField –Name “UserName” -Type UserName –Masked:$false
$passwordField = New-SPSecureStoreApplicationField –Name “Password” –Type Password –Masked:$true
$fields = $usernameField,$passwordField

$adminClaim = New-SPClaimsPrincipal –Identity $secureStoreAdministrator –IdentityType  WindowsSamAccountName
$userClaim = New-SPClaimsPrincipal –Identity $secureStoreUser –IdentityType  WindowsSamAccountName
$targetApp = new-spsecurestoretargetapplication -name "externalApplication" -friendlyname "externalApplication" -contactemail $secureStoreAdministratorEmail -applicationtype Group -timeoutinminutes 3
$ssApp = New-SPSecureStoreApplication –ServiceContext $serviceContext –TargetApplication $targetApp –Field$fields –Administrator $adminClaim -CredentialsOwnerGroup $userClaim
$firstCredential = ConvertTo-SecureString $targeApplicationUserName –AsPlainText –Force
$secondCredential = ConvertTo-SecureString $targeApplicationUserPassword –AsPlainText –Force
$credentialValues = $firstCredential,$secondCredential
Update-SPSecureStoreGroupCredentialMapping  –Identity $ssApp –Values $credentialValues

Start content type synchronisation from within a feature

November 7, 2011

The standard way to consume the content types from content type hub in your site collection. It is described for example here.  If you want  the content types available direct during creating of the site collection, this will not work for you. You try to start the Timer Job programmatically, but you will receive access denied exception. Because starting timer jobs is not allowed during feature activation. Here is a sample how you can consume content types immediately only for a specific site collection without permissions problems. However it includes a little bit of reflection.

using System;
using Microsoft.SharePoint;
using System.Reflection;

namespace NameSpace
{
public class ContentTypeSubscriber
{
public void Execute(SPSite site)
{
var taxonomyAssembly = Assembly.Load("Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
var subscriberType = taxonomyAssembly.GetType("Microsoft.SharePoint.Taxonomy.ContentTypeSync.Internal.Subscriber");

var processSiteMethodInfo = subscriberType.GetMethod("ProcessSite",
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new[] { typeof(SPSite) },
null);

var subscriberTypeConstructor = subscriberType.GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null, new Type[] { }, null
);

var subscriberInstance = subscriberTypeConstructor.Invoke(new object[] { });
processSiteMethodInfo.Invoke(subscriberInstance, new Object[] { site });
}
}
}

Restoring site or list from a full farm backup

June 12, 2011

This post covers a scenario, when a user makes some irreversible changes and the only place where the undamaged data is, is the farm full backup. The scenarios can be list deletion, site deletion, permissions damage etc.
So here are the instructions:

  1. Locate the folder where your farm full backup is and open the file spbackup.xml
  2. Find the content database name in the file and in the found node  locate a line that looks like this:
    <SPParameter Key="SHAREPOINT2010:WSS_Content.dat"><![CDATA[00000055.bak]]></SPParameter>
    
  3. 00000055.bak is the name of the database backup of the content database.
  4. Go to SQL Management Studio and create a new database.
  5. Perform a restore into this database from the backup file mentioned above. You have to change the name of the ldf and mdf file and check the “overwrite the existing database” checkbox.
  6. Now open the Central administration. Click “Backup and Restore” tab and then “Recover data from an unattached content database” link.
  7. Type in the name of the currently restored database and click Next.
  8. Navigate to a list / site collection that you want to restore and click Next.
  9. On the following page type in where you want to store the exported data of the list / site collection and click Next.
  10. When the backup is created use the Import-SPWeb command to restore the data. The command should look like this:
Import-SPWeb -Path C:\temp\backup.bak -Identity http://localhost