Sunday, 26 January 2014

Add/delete and list Remote Event Receivers with PowerShell/CSOM

Recently I’ve been looking at Remote Event Receivers more and more, as I think they are important (and somewhat unavoidable) if you are trying to build “cloud-friendly” SharePoint solutions – either because you’re on Office 365, or simply want to leave the door open for such a move. You might need to use a RER for something in the host web or app web. I’ll most likely write more on RERs in the future, but if you need a basic step-by-step guide to Remote Event Receivers, my previous post Deploying SP2013 provider-hosted apps/Remote Event Receivers to Azure Websites (for Office 365 apps) may be useful. In this post I want to share some potentially useful PowerShell (and background info), for those who work with RERs.

As I note in the article at the previous link, when you create an RER you actually need to create an app for SharePoint, even if it is an RER to be used in the host web. The app must be either provider-hosted or auto-hosted. For production use I like the provider-hosted option, even if the code is deployed to a cloud service such as Azure. This offers much more flexibility than auto-hosted, which doesn’t have the same options for configuration/monitoring/scaling-up etc. An app is needed because you are creating remote code which most likely needs to use OAuth to communicate back to SharePoint, and the trust model means that (in the standard case at least) an administrator such as the site owner needs to agree to the permissions requested by the app. This could be “Web – Read” or “Site Collection – FullControl” and so on.

Registering Remote Event Receivers

There are several ways to register RERs:

  • Declaratively
  • With CSOM code e.g. in the AppInstalled event
  • With a PowerShell/CSOM script

One big downside to the declarative approach is that it can only be used for lists in an app web (i.e. a SharePoint list deployed by the app). It cannot be used for lists in the host web (e.g. to add a RER to a list in a team site). For completeness, the declarative XML is shown below – it’s just like the XML you might have used for any other event receiver, the only difference is the new “Url” element in the XML:

** N.B. There is a code sample here but it will not show in RSS Readers - click here for full article **

I’ve found more and more that as I’m doing development, the PowerShell approach is highly useful. Sometimes you just need to directly interact with the list - perhaps to see if your RER really is registered properly, or change the URL to a different WCF service for testing. Since there is no user interface for setting RERs, some quick PowerShell is ideal – this post is to share my functions in case they’re useful. I’ll list the different ones for adding/deleting/listing RERs, then provide a full/combined script at the end.

By the way, if you’re new to the idea of PowerShell scripts which have CSOM code embedded in them, see Using CSOM in PowerShell scripts with Office 365.

Adding a new Remote Event Receiver

The function below adds a remote event receiver to a named SharePoint list.

(N.B. Note that all the functions below require a valid ClientContext object to be passed in – see the Prerequisites section towards the end of this post for more details.)

** N.B. There is a code sample here but it will not show in RSS Readers - click here for full article **

Delete a Remote Event Receiver

The function below removes a remote event receiver from a named SharePoint list.

** N.B. There is a code sample here but it will not show in RSS Readers - click here for full article **

List Remote Event Receivers on a SharePoint list

In fact, RER declarations are just like regular event receivers – the SPList class just has one “EventReceivers” property, rather than separate collections for remote event receivers and regular event receivers:

** N.B. There is a code sample here but it will not show in RSS Readers - click here for full article **

Combined/all-up script

So having walked through the functions individually, here's a combined script for download/copy and paste:

** N.B. There is a code sample here but it will not show in RSS Readers - click here for full article **

Prerequisites

To get started with these scripts you should follow the “Getting Started” section of Using CSOM in PowerShell scripts with Office 365, including the “The top of your script – referencing DLLs and authentication” section.

All of the samples above need you to pass a valid ClientContext object – which you have once you have provided the credentials and URL, and have authenticated to SharePoint/Office 365. As in my previous posts, I obtain this in a separate file which I call something like TopOfScript_PSCSOM.ps1. For clarity, here’s an idea of what you need:

** N.B. There is a code sample here but it will not show in RSS Readers - click here for full article **

Summary

Hopefully this script is useful to those working with RERs. Using PowerShell/CSOM isn’t the only way to declare a Remote Event Receiver – in production you might use CSOM code in the AppInstalled event (which is itself declared declaratively in AppManifest.xml – the only way for that event), but the PowerShell/CSOM approach is definitely useful in dev. Happy coding!

Monday, 6 January 2014

Extending the SP2013/Office 365 search hover panel (e.g. adding “post to my feed” functionality)

The enhanced search experience is one of the great things about SharePoint 2013, and the “hover panel”, which shows more information about the result when you hover over it, is a key part of that. Being able to peek inside a document or presentation, or see a preview of a web page without clicking on the result makes for way more efficient searching. Just like search results themselves, the appearance and functionality of the hover panel can be easily extended with HTML, CSS and JavaScript – in this post I am providing some sample code I’ve used in conference talks, which I think highlights things in this area quite well. My sample could be used as-is or modified to provide some other customization to the hover panel.

For context, here’s a reminder of what the hover panel looks like:

Standard hover panel 2 
Actually that image shows a document preview *without* Office Web Apps being available – just a simple summary of the document is shown. Arguably the more normal experience is to have OWA (for example it is standard in Office 365), and in this case you can page through the document/presentation to see if it’s what you’re looking for:

Standard hover panel - OWA

Great. So now let’s look at tweaking the hover panel to add some custom behavior.

Customizing the hover panel – adding an “action”

[Minor diversion/story]: In September 2013, Microsoft added some new functionality to Office 365 which allows a user to “post to Yammer” from the search hover panel. The entry point is a new “action” in the bottom part of the hover panel:

O365 post to Yammer

As a coincidence, a few months earlier in April 2013 I had demo’d a very similar customization at the SharePoint Evolutions Conference in London, but in my case my code was posting to the SharePoint 2013 social feed (i.e. not Yammer). Spookily enough, I had even chosen the same word, “POST”:

Hover Panel actions - with guide - edges
Seeing the Office 365 change reminded me that I should post this code somewhere – maybe it could be useful to you if your organization uses the SharePoint newsfeed rather than Yammer, or you’re just generally looking for technical info on the hover panel.

[End of minor diversion/story]

My customization

My code modifies the hover panel for all item types (e.g. web page, Word doc, Excel doc etc.). As described above, the “POST” action is added to the actions bar. When clicked, a textbox appears *in the hover panel* to allow the user to type a message to post (to the accompany link):

Hover panel - before post to feed - large

[I’m sure the UX team at my place of work would have something (very bad!) to say about this, but really I’m just trying to show that you can do all sorts of things with the hover panel :)]

I display a new button to do the actual “Post” at this point. Once a message is typed and this button is clicked, an AJAX request is fired to the SharePoint social API, and a success or failure confirmation is displayed in the hover panel:

Hover panel - after post to feed - small
And as you’d expect, the message has now been broadcast to my followers (with a link to the original document) and is now listed in the activities section of my profile:

Message shown in social feed

Search hover panel – key info

The hover panel is broken down into three areas:

Hover Panel - with guide with edge 
All this stuff comes from HTML/JavaScript files in the Master Page Gallery of your SharePoint search site – so to be clear, let’s say you have a Search Center site at a URL of “/search” (as in Office 365), then these files can be found in that site’s Master Page Gallery. You’ll find the files under the “Display Templates/Search” folder path:

Search display templates
Firstly you’ll notice above that there is a HTML file for every JavaScript file – this is the case for any site which has the publishing feature enabled and therefore Design Manager support for display templates. Past that, there are three broad types of file:

  • “Item” display templates - for each item type, such as Item_PDF.js, Item_Word.js, Item_Person.js and so on. Customize these if you wish to tweak how that particular Result Type looks in search results
  • “Hover panel” templates – again for each item type, such as Item_PDF_HoverPanel.js and so on. Customize these to tweak the hover panel (which is what we’ll be doing in this post)
  • Files for “misc” things - like best bets, the search box control etc.

Importantly, as well as the “per item type” files there are some “common” files – these are hooks which can be used to implement customizations across all Result Types, without having to edit the files for each one. Effectively there is some pseudo-inheritance implemented in JavaScript by Microsoft, where both the “common” and “specific” templates are used provide the UI for a specific item (nice work Product Group). For the hover panel, this works in the following way:

  • Each “specific” file provides some outer HTML which may be specific to that item type, but also calls functions called:
    • ctx.RenderHeader()
    • ctx.RenderBody()
    • ctx.RenderFooter()
  • These functions are implemented in the “common” files

Effectively you could throw away the idea of calling the common functions for a specific item type if you wanted, and provide an entirely custom hover panel - usually you’ll want to keep the consistency though. The common files are:

Common display templates
It’s these files we’ll be modifying.

Code for my customization

So my sample adds some HTML/CSS, but also has some custom JavaScript code – effectively the moving parts are:

  • Some new CSS and JavaScript files, which need to be referenced on the page
  • Some changes to the HTML/JS files in the Master Page Gallery which are used for the hover panel

Here’s a run-down of the changes I make to which file:

File

Change description

Item_CommonHoverPanel_Actions.html Adds the “POST” action link which sits in the “actions” bar
Item_CommonHoverPanel_Body.html Adds the core customization – the textbox which appears for the comment to be typed into, and the button which does the actual “Post”.

Also has the JavaScript call to my custom JavaScript function which does the processing work.
COB-js-demos.js Custom JavaScript file holding my custom functions such as:
“ShowHoverPanelTextBox”
“PostToCurrentUserFeed”
etc.

I added this to the page using a CustomAction.

As you can see, I’m modifying the HTML file and allowing the JS file to be generated. In production you may want to package the JS files as a WSP and overwrite the OOTB ones (keeping a copy of the original of course). I’ll provide a link to a zip file with all files at the end, but here is the new code in each:

Item_CommonHoverPanel_Actions.html
** N.B. There is a code sample here but it will not show in RSS Readers - click here for full article **
Item_CommonHoverPanel_Body.html
** N.B. There is a code sample here but it will not show in RSS Readers - click here for full article **
COB-js-demos.js
** N.B. There is a code sample here but it will not show in RSS Readers - click here for full article **

So in summary we reference the custom JS file on the page (e.g. in a ScriptLink, CustomAction or script tag in the master page) and make the changes to the hover panel files. I’m supplying all the files which make up my solution in the zip linked below, but just as a set of files - you’ll need to package  them into a WSP if that’s what you need (and choose where you want CSS/JS files to deploy to). 

Summary

The search hover panel is a key part of the SharePoint 2013/Office 365 search experience, and is designed to be customized to meet different needs. A new behavior can be implemented across all item types or just for a specific one, such as a Word document or “person” result. In this sample I have shown not only how to tweak the HTML/CSS, but also provide some custom AJAX-based functionality in the hover panel. I chose to use the SharePoint social feed, but the mechanics could be adapted to any behaviour which SharePoint exposes through REST/CSOM/other client APIs.

Download

COB.SharePoint.SearchHoverPanel-Files.zip

Thursday, 5 December 2013

Using CSOM in PowerShell scripts with Office 365

In my recent “Office 365 developer decisions, tips and tricks” talk I mentioned that we’d been doing a lot of “PowerShell with CSOM” work, and this was enabling us to run scripts against SharePoint Online in the same way that we are used to (for on-premises SharePoint). This is becoming a popular approach, but since I got questions on it I thought it worth writing about.

When we first started to work with Office 365, I remember being quite concerned at the lack of PowerShell cmdlets – basically all the commands we’re used to using do not exist there. Here’s a gratuitous graph to illustrate the point:

image

So yes, nearly 800 PowerShell commands in SP2013 (up from around 530 in SP2010) down to a measly 30 in SharePoint Online. And those 30 mainly cover basic operations with sites, users and permissions – no scripting of, say, Managed Metadata, user profiles, search and so on. It’s true to say that some of these things are now available down at site-collection scope (needed, of course, when you don’t have a true “Central Admin” site but there are still “tenant-level” settings that you want to use script for rather than make manual changes through the UI.

So what’s a poor developer/administrator to do?

The answer is to write PowerShell as you always did, but embed CSOM code in there. More examples later, but here’s a small illustration:

# get the site collection scoped Features collections (e.g. to activate one) – not showing how to obtain $clientContext here..
$siteFeatures = $clientContext.Site.Features
$clientContext.Load($siteFeatures)
$clientContext.ExecuteQuery()

So we’re using the .NET CSOM, but instead of C# we are using PowerShell’s ability to call any .NET object (indeed, nearly every script will use PowerShell’s New-Object command). All the things we came to love about PowerShell are back on the table:

  • Scripts can be easily amended, no need to recompile (or open Visual Studio)
  • We can debug with PowerGui or PowerShell ISE
  • We can leverage other things PowerShell is good at e.g. easily reading from XML files, using other PowerShell modules and other APIs (including .NET) etc.

Of course, we can only perform operations where the method exists in the .NET CSOM – that’s the boundary of what we can do.

Getting started

Step 1 – understand the landscape

The first thing to understand is that there are actually 3 different approaches for scripting against Office 365/SharePoint Online, depending on what you need to do. It might just be me, but I think that when you start it’s easy to get confused between them, or not fully appreciate that they all exist. The 3 approaches I’m thinking of are:

  • SharePoint Online cmdlets
  • MSOL cmdlets
  • PowerShell + CSOM

This post focuses on the last flavor. I also wrote a short companion post about the overall landscape and with some details/examples on the other flavors, at Using SharePoint Online and MSOL cmdlets in PowerShell with Office 365

Step 2 – prepare the machine you will run scripts against SharePoint Online

Option 1 - if you will NOT run scripts from a SP2013 box (e.g. a SP2013 VM):

You need to obtain the SharePoint DLLs which comprise the .NET CSOM, and copy them to a folder on your machine – your scripts will reference these DLLs.

  1. Go to any SharePoint 2013 server, and copy any DLL
  2. which starts with Microsoft.SharePoint.Client*.dll from the C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI folder.
  3. Store them in a folder on your machine e.g. C:\Lib – make a note of this location.

CSOM DLLs

Option 2 - if you WILL run scripts from a SP2013 box (e.g. a SP2013 VM):

In this case, there is no need to copy the DLLs – your scripts will reference them in the original SharePoint install location (C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI).

The top of your script – referencing DLLs and authentication

Each .ps1 file which calls the SharePoint CSOM needs to deal with two things before you can use the API – loading the CSOM types, and authenticating/obtaining a ClientContext object. So, you’ll need this at the top of your script:

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

In the scripts which follow, we’ll include this “top of script” stuff by dot-sourcing TopOfScript.ps1 in every script below – you could follow a similar approach (perhaps with a different name!) or simply paste that stuff into every script you create. If you enter a valid set of credentials and URL, running the script above should see you ready to rumble:

PS CSOM got context

Script examples

Activating a Feature in SPO

Something you might want to do at some point is enable or disable a Feature using script. The script below, like the others that follow it, all reference my TopOfScript.ps1 script above:

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

PS CSOM activate feature

Enable side-loading (for app deployment)

Along very similar lines (because it also involves activating a Feature), is the idea of enabling “side-loading” on a site. By default, if you’re developing a SharePoint app it can only be F5 deployed from Visual Studio to a site created from the Developer Site template, but by enabling “side-loading” you can do it on (say) a team site too. Since the Feature isn’t visible (in the UI), you’ll need a script like this:

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

PS CSOM enable side loading

Iterating webs

Sometimes you might want to loop through all the webs in a site collection, or underneath a particular web:

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

PS CSOM iterate webs

(Worth noting that you also see SharePoint-hosted app webs also in the image above, since these are just subwebs (albeit ones which get accessed on the app domain URL rather than the actual host site’s web application URL).

Iterating webs, then lists, and updating a property on each list

Or how about extending the sample above to not only iterate webs, but also the lists in each - the property I'm updating on each list is the EnableVersioning property, but you easily use any other property or method in the same way:

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

 PS CSOM iterate lists enable versioning

Import search schema XML

In SharePoint 2013 and Office 365, many aspects of search configuration (such as Managed Properties and Crawled Properties, Query Rules, Result Sources and Result Types) can be exported and importing between environments as an XML file. The sample below shows the import operation handled with PS + CSOM: 

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

PS CSOM import search schema

Summary

As you can hopefully see, there’s lots you can accomplish with the PowerShell and CSOM combination. Anything that can be done with CSOM API can be wrapped into a script, and you can build up a library of useful PowerShell snippets just like the old days. There are some interesting things that you CANNOT do with CSOM (such as automating the process of uploading/deploying a sandboxed WSP to Office 365), but there ARE approaches for solving even these problems, and I’ll most likely cover this (and our experiences) in future posts.

A final idea on the PowerShell + CSOM front is the idea that you can have “hybrid” scripts which can deal with both SharePoint Online and on-premises SharePoint. For example, on my current project everything we build must be deployable to both SPO and on-premises, and our scripts take a “DeploymentTarget” parameter where the values can be “Online” or “OnPremises”. There are some differences (i.e. branching) in the scripts, but for many operations the same commands can be run.

Related post - Using SharePoint Online and MSO cmdlets in PowerShell with Office 365

Using SharePoint Online and MSOL/WAAD cmdlets in PowerShell with Office 365

This post is a companion post to Using CSOM in PowerShell scripts with Office 365. As I mention over in that article, broadly there are 3 different flavors to writing PowerShell for Office 365 – exactly what commands you need to run will dictate which you use, but it’s also conceivable that you might use all 3 in the same script. When you start with Office 365, I think it’s easy to get confused between them, or not fully appreciate that they all exist. What I’m thinking of here is:

Flavor

Notes

Examples

When installed you’ll have:

SharePoint Online (SPO) cmdlets These are SharePoint Online specific, and can be identified by “SPO” in the noun part of the cmdlet. 
  • Get-SPOSite (to list your site collections in Office 365)
  • New-SPOSite (to create a new site collection)
 SPO shell
MS Online (MSOL)/WAAD cmdlets These are commands related to an Office 365 tenancy (but not necessarily specific to Exchange, Lync or SharePoint) and can be identified by “Msol” in the noun part of the cmdlet.
  • Get-MSolUser (to list users in your tenancy)
  • Set-MsolUserPassword (to update a password)
 MSO shell
Using SP CSOM in PS scripts The main focus of my other post, Using CSOM in PowerShell scripts with Office 365
  • Activating a Feature in SharePoint Online
  • Updating webs or lists in SharePoint Online
No install needed – you can run this type of scripts in a regular Windows PowerShell command prompt.

 

A note on MSOL/Windows Azure AD cmdlets

You might be wondering why the MSOL cmdlets show “Windows Azure Active Directory..” in the shortcut title (full name is “Windows Azure Active Directory Module for Windows PowerShell”), despite everything else being labelled “MSOnline” or “MSOL”. The answer is that originally these cmdlets were known as the “Microsoft Online Services Module for Windows PowerShell cmdlets”, but since that time Microsoft have introduced Windows Azure Active Directory as a formal service offering. Every Office 365 tenancy is backed by Windows Azure Active Directory (WAAD) – and since the MSOL cmdlets always were focused around directory stuff (managing users/groups, managing synchronization with your Active Directory and so on), these have now been absorbed into the WAAD offering.

Getting started

If you’re a developer or administrator who will be working with Office 365 regularly, I recommend installing the the ‘shells’ for both the SharePoint Online and Office 365 PowerShell commands – you’ll probably need them at some point.

  1. Install PowerShell 3.0 if you don’t already have it. It’s included in the Windows Management Framework 3.0 - http://www.microsoft.com/en-us/download/details.aspx?id=34595
  2. Install the SPO cmdlets - http://office.microsoft.com/en-gb/sharepoint-help/redir/XT102919083.aspx?CTT=5&origin=HA102919087
  3. Install the MSOL cmdlets - http://technet.microsoft.com/en-us/library/jj151815.aspx#bkmk_installmodule

Once installed, you’re ready to start thinking about the “top of script” stuff (e.g. authenticating to Office 365). You’ll find that it’s very similar for both the SPO and MSOL scripts, but a different cmdlet must be run to start the session:

  • Connect-SPOService
  • Connect-MsolService

Script examples – SPO scripts

Authenticating to SharePoint Online to run SPO cmdlets:

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

List all site collections in SharePoint Online:

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

Recreate a site collection in SharePoint Online:

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

Script examples – MSOL/WAAD scripts

Authenticating to Office 365 to run MSOL/WAAD cmdlets:

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

Getting all users in in the directory

A simple MSOL example, just for completeness:

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

Further reading

Appendix – full lists of SPO and MSOL/WAAD cmdlets

To help you get a sense of the full range of commands in each family (in case you don’t already have them installed), I’m listing them below:

SPO cmdlets

Add-SPOUser                                       
Connect-SPOService                                
Disconnect-SPOService                             
Get-SPOAppErrors                                  
Get-SPOAppInfo                                    
Get-SPODeletedSite                                
Get-SPOExternalUser                               
Get-SPOSite                                       
Get-SPOSiteGroup                                  
Get-SPOTenant                                     
Get-SPOTenantLogEntry                             
Get-SPOTenantLogLastAvailableTimeInUtc            
Get-SPOUser                                       
Get-SPOWebTemplate                                
New-SPOSite                                       
New-SPOSiteGroup                                  
Remove-SPODeletedSite                             
Remove-SPOExternalUser                            
Remove-SPOSite                                    
Remove-SPOSiteGroup                               
Remove-SPOUser                                    
Repair-SPOSite                                    
Request-SPOUpgradeEvaluationSite                  
Restore-SPODeletedSite                            
Set-SPOSite                                       
Set-SPOSiteGroup                                  
Set-SPOTenant                                     
Set-SPOUser                                       
Test-SPOSite                                      
Upgrade-SPOSite          

MSOL/WAAD cmdlets

Add-MsolForeignGroupToRole   
Add-MsolGroupMember          
Add-MsolRoleMember           
Confirm-MsolDomain           
Confirm-MsolEmailVerifiedDomain   
Connect-MsolService          
Convert-MsolDomainToFederated     
Convert-MsolDomainToStandard      
Convert-MsolFederatedUser    
Get-MsolAccountSku           
Get-MsolCompanyInformation   
Get-MsolContact              
Get-MsolDomain               
Get-MsolDomainFederationSettings  
Get-MsolDomainVerificationDns     
Get-MsolFederationProperty   
Get-MsolGroup                
Get-MsolGroupMember          
Get-MsolPartnerContract      
Get-MsolPartnerInformation   
Get-MsolPasswordPolicy       
Get-MsolRole                 
Get-MsolRoleMember           
Get-MsolServicePrincipal     
Get-MsolServicePrincipalCredential   
Get-MsolSubscription         
Get-MsolUser                 
Get-MsolUserByStrongAuthentication
Get-MsolUserRole             
New-MsolDomain               
New-MsolFederatedDomain      
New-MsolGroup                
New-MsolLicenseOptions       
New-MsolServicePrincipal     
New-MsolServicePrincipalAddresses
New-MsolServicePrincipalCredential
New-MsolUser                 
New-MsolWellKnownGroup       
Redo-MsolProvisionContact    
Redo-MsolProvisionGroup      
Redo-MsolProvisionUser       
Remove-MsolApplicationPassword    
Remove-MsolContact           
Remove-MsolDomain            
Remove-MsolFederatedDomain   
Remove-MsolForeignGroupFromRole   
Remove-MsolGroup             
Remove-MsolGroupMember       
Remove-MsolRoleMember        
Remove-MsolServicePrincipal       
Remove-MsolServicePrincipalCredential  
Remove-MsolUser              
Reset-MsolStrongAuthenticationMethodByUpn
Restore-MsolUser             
Set-MsolADFSContext          
Set-MsolCompanyContactInformation
Set-MsolCompanySettings      
Set-MsolDirSyncEnabled       
Set-MsolDomain               
Set-MsolDomainAuthentication      
Set-MsolDomainFederationSettings  
Set-MsolGroup                
Set-MsolPartnerInformation   
Set-MsolPasswordPolicy       
Set-MsolServicePrincipal     
Set-MsolUser                 
Set-MsolUserLicense          
Set-MsolUserPassword         
Set-MsolUserPrincipalName    
Update-MsolFederatedDomain   

Wednesday, 13 November 2013

Slides from my “Office 365 – developer decisions, tips and tricks” talk published

Recently I gave a talk at SharePoint Saturday UK, following some work my team and I have done on a large Office 365 project. The project involves a reasonable amount of customisation, and we found that many of the techniques we were used to using on classic SharePoint projects cannot simply be applied. Personally I feel like I’ve learnt a lot over the last few months – at my current employer (Content and Code) we are on our 3rd or 4th “Office 365 project with SharePoint customisations”, and we were lucky to also have some time to prepare techniques/scripts etc. before the first one started.

I can’t share all this work, but if you’re starting a similar project you might find some useful info in the ground we have covered and decisions we made. I also point to some useful resources which might be helpful.

Office 365 – developer decisions, tips and tricks

The presentation is embedded below (along with a link to it on SlideShare if you don’t see it).

Contents:

  • Decision – how we deal with test environments in the cloud (e.g. do you need a separate Office 365 tenancy for test?)
  • Decision – do developers still need powerful desktops/laptops to run virtual machines?
  • Decision – should you use (server-side) code in the sandbox?
    • And should you worry about the “sandbox is deprecated” message?
    • What are the alternatives to server-side code?
  • Using the magic “PowerShell + CSOM” combination to write PowerShell scripts for Office 365
  • Dealing with Managed Metadata fields
    • Provisioning taxonomy (Term Sets) with CSOM, to ensure consistent IDs
    • Our approach - 100% declarative provisioning of Managed Metadata fields
  • The new way of working with Managed Properties – search schema XML
    • Using the SearchConfigurationPortability object in CSOM
  • Automated deployments to Office 365 – using PS/CSOM to:
    • Recreate site collections
    • Import taxonomy term sets and terms
    • Import search schema
    • Upload sandbox WSPs to the site’s Solution Gallery
    • Activate Features, apply custom WebTemplate to site
  • Wrapping the above in TFS build for Continuous Integration (nightly builds of latest packages to Office 365)

I’ll expand on some of these topics in future articles. Similarly I’m expecting to further develop this talk and incorporate new content.

View/download  link - https://www.slideshare.net/chrisobrien/chris-o-brien-office-365-decisions-tips-and-tricks-with-screenshots

View/download  link - https://www.slideshare.net/chrisobrien/chris-o-brien-office-365-decisions-tips-and-tricks-with-screenshots

Friday, 25 October 2013

Waiting for a search crawl in Office 365 – plan search-driven sites carefully

HourglassHere in autumn/fall 2013, if you’re working with Office 365 you might notice that content changes (such as new pages and documents) take some time to appear in search results. I spent a little time thinking about this recently, as my team and I finished building a search-driven news site. On this project, we are mainly developing against Office 365 – we use local virtual machines also, but since O365 is the target we are deploying our customisations there frequently as we develop.

We noticed that “index latency” – the time taken for new content to appear in the search index – was poorer than we expected on Office 365. We run several tenancies on different subscription levels (e.g. SharePoint P2, Office 365 E3 etc.), and we experience the problem across all of them. Some days are good, some days are bad. One memorable (read, stressful) time, we had a “end of sprint demo” - our solution was provisioned 2 days before the demo, giving us lots of time to create test content in order to make the demo to the business users go well. We completed adding our pages, documents, pictures and videos a full 24 hours before the demo, and waited for our home page to “light up” as content was crawled in Office 365.

Unfortunately, only some of the content was indexed in time. The demo itself went well, but perhaps only because a bit of narrative helped the business users imagine the ‘full’ picture. Overall, it’s difficult not to feel that 24 hours is a long time to wait for content to be indexed in SharePoint! Business users these days have higher expectations, and most on-premise environments I’ve worked with have used incremental crawls with a frequency of 15 or 30 minutes.

How long is normal in Office 365?

The poor performance surprised us somewhat. My colleagues and I thought that we had originally read that a delay of up to 15 minutes was expected in Office 365, perhaps suggesting that SharePoint 2013’s “Continuous Crawl” is used. The Office 365 Service Descriptions – Search page now suggests that isn’t the case, but however it is managed in the back-end, we certainly weren’t expecting such long delays. Some further digging will lead you to this KB article:

Search doesn't return all results in SharePoint Online – KB2008449

“Search crawls occur continuously to make sure that content changes are available through search results as soon as possible. Recently uploaded documents may not immediately be displayed in search results because of the time that's required to process them. SharePoint Online targets between 15 minutes and an hour for the time between upload and availability in search results (also known as index freshness). In cases of heavy environment use, this time can increase to six hours.”

OK, so at least that’s something official, even if it’s not necessarily what we wanted to hear. But why are we sometimes seeing longer delays than 6 hours even? I raised a Service Request with Microsoft to find out..

The support line

In short, I didn’t get a 100% satisfactory answer from Office 365 support. Ultimately it sounds like this kind of thing is fairly normal in Office 365 right now. I asked if other customers were reporting this issue, and the answer was “yes, but we just ask them to wait another day”. Hmm, OK then! Of course, if your site deals with time-sensitive content (or you are just looking for fresh content to be shown in search in a reasonable timeframe) this isn’t a great situation.

Working around the issue

So if you need to consider other alternatives:

  • If you are dealing with search-driven functionality, could the same thing be provided with query rather than search (e.g. if you do not need to aggregate across site collections)?
  • If you are in a hybrid situation, could the functionality be delivered by an on-premises environment?
  • Do you need a solution right now, or can you afford to wait for improvements? (I personally am hopeful that upgrades to Office 365 will improve the situation in the future.)

For us, in fact all three are options we could use. In our situation the 2nd option could be the simplest if we need an immediate solution - everything we are building for this client can work be deployed to Office 365 or on-premises SharePoint. This requires quite a lot of careful engineering (not only in terms of the solution, but also deployment scripts/processes etc.), but results in a nice position to be in for a hybrid deployment.

In general though, let’s hope that Microsoft work on this in Office 365. I’ll keep you posted if we see improvements - and if anyone has any useful information in this area, feel free to share in the comments below.

Sunday, 20 October 2013

Speaking at SharePoint Saturday UK 2013 – developing for Office 365

SharePoint Saturday UK

As usual, I’ll be speaking at this year’s SharePoint Saturday UK event – I think this is the 4th one, and also my 4th time speaking there. It’s a great event, and I’m looking forward to learning from the other sessions. For my part, I’ll be doing my best to share knowledge gained from recent Office 365 and SharePoint 2013 projects.

My session is mainly targeted towards developers and technical people, but hopefully there’s something in it for anyone looking at Office 365. Myself and some colleagues have spent an intense few weeks/months delivering a cloud project recently, and it feels like every day has been a learning day. My talk hopefully conveys some of this, and I’ll be evolving it for future conferences:

Developer decisions, tips and tricks - lessons learnt from Office 365 projects

As a developer or technical lead, your early Office 365 projects are likely to throw up some interesting questions. Should you avoid the sandbox? How should test environments be handled in the cloud? How should a site template be implemented? And just how do you provision Managed Metadata fields, when the on-premises techniques cannot be used?

This session walks through the “dev strategy” decisions we made at Content and Code, and why. Over the course of several demos, we’ll also discuss apps, automation scripts and also advanced techniques such as Continuous Integration for Office 365.

Event details

This year’s event is on 9th November 2013, and is held in Hinckley, near Leicester. If you’re interested, you can register here:

http://lanyrd.com/2013/spsuk/

 

Wednesday, 18 September 2013

Provisioning Managed Metadata fields in Office 365 – Part 2: building WSP packages for a specific environment/tenancy

In the previous post I talked about how provisioning Managed Metadata fields is tricky for Office 365 (since developers cannot use server-side code to “hook-up” the field to the Term Store, like we can on-premises). I talked about the way we approach this, and in this post I’ll show the Visual Studio/MSBuild customisation we use to build WSPs specific to an Office 365 tenancy. Here’s how the articles relate to each other:

  1. Provisioning Managed Metadata fields in Office 365 – dealing with multiple environments
  2. Provisioning Managed Metadata fields in Office 365 – building WSP packages for a specific environment/tenancy [this article]

Using MSBuild/custom Project Configurations to build packages per Office 365 tenancy

Here’s what I came up with – it took quite a few long nights in the murky hall-of-mirrors world of “batching” in MSBuild, roughly 5 million discarded approaches and several new gray hairs. But finally, it works great for us:

We now have some custom project configurations which can be selected in Visual Studio:

Custombuildconfigurations_thumb8 
So instead of just ‘Debug’ and ‘Release’ we are using:

  • “CandCVM” – Content and Code (name of my employer) virtual machine. Used for when you are developing against your local VM rather than the cloud
  • “DevTenancy” – the Office 365 tenancy we are using for DEV purposes
  • “TestTenancy” – the Office 365 tenancy we are using for TEST purposes

Those are all the environments we need to worry about for now, but of course others will be needed eventually.

We also have an XML file in the VS project, which defines the Managed Metadata IDs for each environment – since we now only have to worry about the SspId, that’s the only value the file contains:

SspIdreplacementsfileinsolution_thum

SspId replacements file_thumb[2]

Once the project (or solution) configuration has been switched, we just build/publish the WSP to the filesystem as usual:

Publishsandboxedsolutionfortesttenan

..and as you’d expect, we get the WSP(s) which will work against that environment:

PublishedWSPs_thumb2

What has happened, and how?

As the WSPs were being packaged, some custom MSBuild executed. What this does is:

  • Finds the SspId_Replacements.xml file
  • Reads the SspId value for the appropriate environment
  • Performs a find/replace across all the of the XML files about to go into the package(s), and replaces the SspId value with the one read from the ‘replacements’ file

Notes:

  1. Although it seems inefficient to look for an SspId and try to replace across *all* XML files (and it is), we do need to ensure that we catch:
    1. Managed Metadata field declarations (i.e. in elements.xml files)
    2. The section in schema.xml files (for list definitions) where the fields are duplicated

      I did look at trying to constrain the search beyond just the .xml extension, but found this difficult in MSBuild. I was also mindful of the fact that a developer could choose to have a Feature elements file NOT named elements.xml :) Fortunately the performance hit for us is negligible – the overall penalty in packaging for using this stuff (compared to a plain Debug or Release build) seems to be around 1-3 seconds – perfectly tolerable right now.
  2. The replacement is XML-based (using XPath rather than string manipulation), so if you have XML comments nearby, this won’t trip up the replacement.

Benefit: integrating with Continuous Integration/automated build

One reason I wanted to implement in MSBuild is because I knew that it would be painless to use in a CI process. When implementing the build in TFS, we select the solutions/projects to build, and then define any custom Configurations we wish to use there also (i.e. in addition to developer machines). In our case, our CI builds deploy to our test tenancy:

Continuous Integration - Office 365 - custom VS configuration_thumb[2]

We then make sure our build definition is using this Configuration (instead of Debug or Release):

Continuous Integration - Office 365 - Managed Metadata solution_thumb[2]

Want to use this? Here’s the MSBuild..

If you think this could be useful to you, here are the details – essentially you need to edit your .csproj file, add the SspId_Replacements.xml file to your project and finally define the custom Configuration in Visual Studio. The sequence doesn’t matter, so long as all pieces are in place before you try a build. In team development, these steps need to be performed just once per VS project (e.g. by the lead developer).

Step 1 – add the custom MSBuild to your project:

Edit your .csproj file (each of them if you have multiple – the solution is currently “project-scoped”) to include this at the bottom:

** N.B. My newer code samples do not show in RSS Readers - click here for full article **

Step 2 – add the XML file with your config values:

Add an XML file within your project at the path “_Replacements\SspId_Replacements.xml” (N.B. this is configurable, see the MSBuild above). Add in the XML shown above, substituting the relevant SspId(s) for your environment(s). If you don’t know where to find the SspId for your environment, my colleague Luis mentions that in his post.

Step 3 – define the custom Configurations in Visual Studio:

In Visual Studio, define a custom Configuration for each environment you need to build WSPs for. Start by going to Configuration Manager and selecting “New..”:

Define custom configuration_thumb[2]

Define custom configuration 2_thumb[2]
..then create the Configuration, ensuring the same name is used as specified in the XML file – these two need to match. You’ll generally want to copy the setting from “Release”:

Define custom configuration 3_thumb[2]

Now close Configuration Manager – the implementation is complete.

Building packages

To create WSPs, use the Configuration dropdown to switch to the “TestTenancy” (or whatever label you used) build type – be careful that the Platform stays as “Any CPU” here, you may need to change it back if not. Then just right-click on the project in Solution Explorer and click “Package” as usual – you should then get a WSP package in which the SspId find/replace has occured. You can now test deploying this to your Office 365 tenancy which corresponds to this build type.

A note on requirements

Note that the MSBuild used here is not compatible with SP2010/Visual Studio 2010 (but that’s OK because the entire technique is not needed there). There is a dependency on .NET 4.0 for the XmlPeek/XmlPoke MSBuild activities which are used to update the XML files.

Hopefully this is useful to some folks.

Tuesday, 17 September 2013

Provisioning Managed Metadata fields in Office 365 - Part 1: dealing with multiple environments

Managed Metadata fields have always been slightly painful for SharePoint developers, but if you did any kind of site templating or Feature development in SharePoint 2010, chances are that you did some research, read some blog articles and came to understand the solution. Here I’d like to talk about it for Office 365, and show a little customization I built to help with the process we currently use. This article became long, so I split it over two articles:

  1. Provisioning Managed Metadata fields in Office 365 – dealing with multiple environments [this article]
  2. Provisioning Managed Metadata fields in Office 365 – building WSP packages for a specific environment/tenancy

So, back on the SharePoint 2010 situation - the deal is that some Managed Metadata details change between SharePoint environments – so unlike other fields, the same provisioning XML could not be used across dev/test/UAT/production. To be specific, the IDs of the Term Store, Group and Term Set all change between environments. As a reminder, broadly the solution was to:

  • Use XML to define the “static” details of the field
  • Use server-side code to “finish the job” – i.e. use the API to ask SharePoint what the IDs are (for the current environment), and then update the field config with that value

Without the 2nd step, the field will be created but will be broken – it will be grayed out and users cannot use it (SP2010 example shown here):

sp2010-managed-metadata-field-disabled

Posts by Ari Bakker (whose image I’m using above, thanks Ari), Wictor Wilen and Andrew Connell were popular in discussing the steps to solve this.

It’s the same deal in SharePoint 2013/Office 365 – but it turns out we need different techniques.

Why the approach doesn’t work for Office 365/SharePoint Online

Well firstly, code in sandboxed solutions is deprecated. Full-stop. [RELATED - did you hear? Microsoft are starting to clarify that sandboxed solutions without code aren’t really deprecated after all (and hopefully MSDN will reflect this soon), but CODE in sandboxed solutions is deprecated and could be phased out in future versions. Clearly this is a very important distinction.]

But even if we were happy to use sandboxed code - in Office 365/SharePoint Online, we cannot use the Microsoft.SharePoint.Taxonomy namespace in server-side code anyway – the net result is that we are unable to “finish the job” in this way to ensure the field is correctly bound to the Term Store. This is a problem! Even worse, whilst it is possible in the CSOM API to bind the field, having this execute in the provisioning process (e.g. as a site is being created from the template) is challenging, maybe impossible. Maybe you could come up with some imaginative hack, but that’s probably what it would be. And what happens if this remote code (e.g. a Remote Event Receiver) fails?

Possible solutions

A colleague of mine, Luis Mañez, did some great research – I’ll give you a quick summary here, but I strongly recommend reading his article - Deploying Managed Metadata Fields declaratively in SharePoint 2013 Online (Office 365). Here’s a summary:

In fact, it IS possible to provision Managed Metadata fields without any code, if you are willing to accept a big trade-off – you can declaratively specify the key details (such as the Term Store ID (also known as the SspId), the Group ID, the Term Set ID etc.) into your XML field definitions. Wictor alluded to this possibility in his post. But remember, these details change between environments!

So in other words, the trade-off is that you would need to rebuild your WSPs for each environment.

This is tricky for us, because on this project we choose to run multiple Office 365 tenancies, for development/test/production (something I’ll talk about in future posts) – just like a traditional mature process. So at first we said “No way! That’s against all of our ALM principles!  The exact same packages MUST move between the environments!”. But then we rationally looked at the alternatives we could see:

  • Option 1 - Some elaborate “remote code” solution, perhaps involving code running separately AFTER the site has been provisioned. Until this code executed, it would not be possible to upload documents to libraries with MM fields within the sites (and similarly if this remote call actually fails for any reason,  these libraries would not function correctly until an administrator intervenes).
  • Option 2 - The client needs to fix-up any Managed Metadata fields manually – across all 5000 sites we were expecting. In every list and library. Knowing that some lists/libraries have up to 5 such fields. Yeah….

Since neither of these was attractive, we continued looking at this idea of a 100% declarative definition of Managed Metadata fields. And then we realized that..

..if you do things in a certain way, you can get to the point where ONLY THE TERM STORE ID (SspId) CHANGES BETWEEN ENVIRONMENTS. That’s kinda interesting. It means that just one find/replace operation is all that’s needed – assuming you’re happy to accept the overall trade-off. Of course, having to replace the SspId is still sub-optimal, error-prone and less than awesome. But maybe we could work on that too – and that’s what these posts are really about - to show a Visual Studio customization we made to simplify this process, and make it less prone to human-error. If you want to skip ahead to this, see Provisioning Managed Metadata fields in Office 365 – Part 2: building WSP packages for a specific environment/tenancy. 

But first, let’s talk about that “if you do things in a certain way” thing (which means that the only the SspId changes between environments)..

The full recipe for Managed Metadata fields

Taking a step back for a second, if you are in “development mode” (e.g. creating a template for SharePoint sites), then successful provisioning actually involves more than just provisioning the field itself in a certain way. Effectively you should seek to provision both the Term Sets AND the fields. Do not allow administrators to create new Term Sets in the admin interface. This is because:

  • This way, you can control the ID of all your Term Sets – rather than let SharePoint generate that GUID
  • Because this is a static “known” ID, we can reference it elsewhere

Here’s what needs to happen:

  • Term Sets are provisioned into the Term Store with “known” IDs
  • The “known IDs” are then used in the XML definition of the fields
    • The code sample below is an example of a Managed Metadata field being provisioned the 100% declarative way. Notice all the properties being specified in the ‘Customization’ section (something a field using the combined declarative + code approach does not have):
      ** N.B. My newer code samples do not show in RSS Readers - click here for full article **

If you do this, your Managed Metadata fields will work just fine:

Managed Metadata fields - working

Great. It’s certainly very valuable to know this is possible for Office 365. So now we have things so that only the SspId value needs to change between environments. But that’s still a nasty find/replace operation – how could we make this situation better?

I describe the mechanism we use in the next post - Provisioning Managed Metadata fields in Office 365 – Part 2: building WSP packages for a specific environment/tenancy.