Monday, February 9, 2015

Pre-provision personalized page for new (first-time) users

A SharePoint customer is realizing the concept of Digital Workplace with SharePoint 2013 as platform foundation. Crucial element of this Digital Workplace is that the entry point is personalized, each employee can personalize the entry point [Dashboard] to own interests and work responsibilities. The user can select Apps from the company AppStore to place on the personalized home page.
To familiarize the employees with this new concept, at Go-Live the homepage will already be pre-provisioned for each individual user with a default set of Apps from the company AppStore.
The following aspects make this task somewhat challenging:
  1. Personalization of the home page requires to pre-provision the page impersonated as the individual users, and access the personalized page scope.
  2. The Digital Workplace is a new webapplication; the employees have not yet visited this webapplication. (SharePoint) Consequence is that the employee accounts are not yet administrated in the SharePoint user list, and thus no usertoken can be determined.
  3. It is not allowed to deploy a custom-build application in the SharePoint farm. This precludes the usage of a .Net console application for pre-provision execution.

Solution design

Construct a Powershell script that is feed with an user list, for each user access the home page impersonated as that user, and add the collection of Apps as ClientWebPart to the personalized webpartmanager scope.

Structure

Specialties

The users have not yet visited the webapplication, and thus are not administrated yet in the SharePoint sitecollection user list. Solution: use ‘ensureUser’.

Powershell script

$snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'} if ($snapin -eq $null) { Add-PSSnapin "Microsoft.SharePoint.Powershell" } # # -- Initialization -- # # Environment specific settings # $siteUrl = "<site-url>" $ADDomain = "<AD-domain>" # Environment-transparant settings # $homePagePath = "/Pages/Home.aspx" $homePageUrl = "$siteUrl$homePagePath" $errorImportingWbMsg = "Error Importing WebPart" # Pre-Provision configuration value # $loc = Get-Location $Users = Get-Content "$loc\Config\Users.txt" $WebPartDefinitions = Get-Content "$loc\Config\WebPartDefinitions.txt" $webPartCatalogRoot = "$loc\WebPartFiles\" # Access the web as administrator # $web = Get-SPWeb -identity $siteUrl # # -- Functions -- # function AddWebPartToPage($limitedWebPartManager, $WebPartDefinition, $User) { $TitleInAppCatalog = $WebPartDefinition.Split("|")[0] $WebPartFile = $WebPartDefinition.Split("|")[1] $WebPartZoneId = $WebPartDefinition.Split("|")[2] # Initialize the XmlReaderSettings Object which is required for the # XmlReader Object $xmlReaderSettings = New-Object System.Xml.XmlReaderSettings # Create the XmlReader Object by using the WebPart Definition file # and the ReaderSettings Object $WebPartUrl = "$webPartCatalogRoot$WebPartFile" $xmlReader = [System.Xml.XmlReader]::Create($WebPartUrl, $xmlReaderSettings); # Get the WebPart Definition Object based on the webpart definition xml file $oWebPartDefinition = $limitedWebPartManager.ImportWebPart( $xmlReader,[ref]$errorImportingWbMsg); # Add the WebPart to the WebPartManager by specifing the Zone and the Index. $limitedWebPartManager.AddWebPart($oWebPartDefinition,$WebPartZoneId,1); $limitedWebPartManager.SaveChanges($oWebPartDefinition) } function PreProvisionForUser($User) { $impSite = New-Object Microsoft.SharePoint.SPSite( $web.url, $web.EnsureUser("$ADDomain\$User").userToken) $impWeb = $impSite.OpenWeb(); $page = $impWeb.GetFile($homePagePath) if ($page.Exists) { # Make the Web as AllowUnSafeUpdates as true $impWeb.AllowUnsafeUpdates = $true # Get the LimitedWebPartManager $limitedWebPartManager = $page.GetLimitedWebPartManager( [System.Web.UI.WebControls.WebParts.PersonalizationScope]::User) # Reset any personalization state (e.g. in case of repeated pre-provision) $limitedWebPartManager.ResetAllPersonalizationState() # Pre-provision the page by adding all the configured webparts foreach($WebPartDefinition in $WebPartDefinitions) { AddWebPartToPage $limitedWebPartManager $WebPartDefinition $User } # Revert the AllowUnsafeUpdates to False once we are done. $impWeb.AllowUnsafeUpdates = $false Write-Host "Pre-Provision done for user:" $User } $impWeb.Dispose(); $impSite.Dispose(); } #### EXECUTE ### foreach ($User in $Users) { PreProvisionForUser($User) }

Sunday, February 1, 2015

Beware, sign-in-as-different-user insufficient with Provider-hosted Apps

When verifying the end-user behaviour of a SharePoint functionality, it is sometimes useful to simulate using the application as another (test)user. SharePoint includes a convenient native capability that enables one to sign-in as another user direct from within the browser. However, be aware that this is insufficient in case your SharePoint 2013 scenario includes the usage of Provider-hosted Apps. SharePoint’s login-as-other-user namely only applies to the SharePoint webapplication process, it does not propagate to the browser-authentication of the external app-hosting webserver(s). The consequence is that ‘login-as-other-user’ is incomplete, successful applied in the SharePoint context, but still the original logged-on user in the Provider-hosted apps. And the App(s) will then access SharePoint resources as the original user, resulting in an inconsistent user context.
Approaches to successful achieve complete login-as-other-user are either to use Firefox, and utilize explicit login – on SharePoint webapplication and all of the Provider-hosted Apps. Or you can use IE, but then you first need to administrate per domain - for the SharePoint webapplication including SharePoint-hosted Apps, and for each webserver that hosts Provider-hosted Apps -, in the Windows Credential Store the credentials of the (test)user you aim to impersonate. And replace them all before accessing the application as another user, either as yourself or another test-account; and next restart with a fresh IE instance.