Remote Event Receivers debugging and Lists and asset creation

Quick Pattern to follow to debug Remote Event Receivers for List Events for lists in the Host Web. So far I have not been able to debug these successfully. I have been able to when the list and the RER’s are created in the App Web Project and attached to App Web Lists. So it seems to me we could create them in the App web to develop and test them and when working move them into the Host Web.

Also remember any object you what created in the Host web has to be created using code and of course will need the right permissions to do so. These assets can be created either when the app is first run, from a App install event (which makes the app minimally partly a Provider-Hosted App or provisioned from a non app client side application – eg a console application using SCOM.

Promoting Code and Sites from Development to QA to Production using PowerShell

Below is an example of a way to re-create Sites, Libraries, deploy custom code from a Development environment to QA to Staging and finally Production, in a repeatable manner without having to keep multiple versions of PowerShell scripts. It reduces the possiblity of introducing errors.

It consists on one powershell script (which could call on multiple function scripts), which pulls environment varables from a xml file. you would have a separate xml file for each environment.

Add-PSSnapin Microsoft.SharePoint.Powershell -ErrorAction "SilentlyContinue"

# use the following the determine location of this script file
$scriptPath = Split-Path -parent $MyInvocation.MyCommand.Path
$deploymentXml = $scriptPath + "\Xml\Deploy.xml"

# now load the deployment configuration data
[xml]$Data = get-content $deploymentXml
$iisRootPath = $Data.Deploy.Settings.IISRootPath
$Url = $Data.Deploy.Settings.Url
$Port = $Data.Deploy.Settings.Port
$AppPoolAccount = $Data.Deploy.Settings.AppPoolAccount
$Owner = $Data.Deploy.Settings.Owner
$WebAppName = $Data.Deploy.Settings.WebAppName
$SiteName = $Data.Deploy.Settings.SiteName
$SiteTemplate = $Data.Deploy.Settings.SiteTemplate

# Below is an example of Creating a Site Collection

if ($Port -ne "80")
{
	$Url = $Url + ":" + $port
}

Write-Host "`n Create Site Collection" -ForegroundColor Blue

New-SPSite $url -Template $SiteTemplate  -Name  $SiteName -OwnerAlias $Owner -Confirm:$false

Here is the sample XML file:

<?xml version="1.0"?>
<Deploy>
  <Settings>
    <IISRootPath>C:\inetpub\wwwroot\wss\VirtualDirectories\</IISRootPath>
    <Url>http://siteurl</Url>
    <Port>80</Port>
    <AppPoolAccount>AD\SVCACCOUNT</AppPoolAccount>
    <Owner>AD\SITEOWNER</Owner>
    <SiteName>Site Name</SiteName>
    <SiteTemplate>BICENTERSITE#0</SiteTemplate>
  </Settings>
</Deploy>

The folder / file stucture for each environment (DEV, QA, PROD etc) would look like this:

Deployment Folder Structure

Where the Code Solution (WSP’s) and other deployment files would be placed in the DeployFiles folder, PowerShell Function scripts in the Functions folder and the configuration Deploy.xml file in the the Xml folder. The Deployment.ps1 script (and any functions) would remain the same for each environment.

Web Config entries using PowerShell

The powershell script and xml below  can be used to make modifications to a Web Applications web config file across all SharePoint Servers.

It can add multiple sections / notes / attributes to the web config file using an XML file as a template to define what needs to be added / changed.

The script first cleans up any existing data in the web config matching an unique identifier that will be recorded for each modification.

Next the XML file is loaded and loops through each section of the xml, checking wither to add a new node (ie like an AppSettings node, or a change to an existing node attribute (ie say the Custom Error mode value).

Finally the changes at applied to the web config file.

Note: Remember to change the location and url variables to your environment and site url.

XML data file:

<?xml version="1.0" encoding="utf-8"?> 
<sections> 
  <section> 
    <skip>false</skip> 
    <path>configuration/system.web/customErrors</path> 
    <modifications> 
      <modification> 
        <type>EnsureAttribute</type> 
        <name>mode</name> 
        <value>Off</value> 
      </modification> 
    </modifications> 
  </section> 
  <section> 
    <skip>false</skip> 
    <path>configuration/appSettings</path> 
    <modifications> 
      <modification> 
        <type>EnsureChildNode</type> 
        <name>add[@key="SomeKeyName"][@value="SomeValueName"]</name> 
        <value>add key="SomeKeyName" value="SomeValueName"</value> 
      </modification> 
    </modifications> 
  </section> 
</sections>

PowerShell Script:


#=================================================================== 
# Web Config Modifications Script 
#=================================================================== 
 
Add-PSSnapin Microsoft.SharePoint.Powershell -ErrorAction "SilentlyContinue" 
 
#connect to the function library for this script 
$functionLocation = "C:\PowerShell\WebConfigModifications" 
. $functionLocation\Web_Config_Modifications_Functions.ps1 
 
#define the SPWebConfigModification constants 
$modificationOwner = "SomeUniqueIdentifier" 
$EnsureChildNode = 0 
$EnsureAttribute = 1 
 
#get the web configuration modifications xml file 
$webconfigLocation = "C:\PowerShell\WebConfigModifications" 
$webconfigData = $webconfigLocation + "\Web_Config_Modifications.xml" 
 
# get the Web Application for the given Url 
$url = "http://YOUR-WEB-APP-URL" 
$webapp = Get-SPWebApplication $url 
$webapp 
#=============================================================================================================== 
 
#Write-Host "`nCleaning up existing Nodes" 
 
#use this statement below to correct for any errors  
#when initially adding new sections / nodes / attributes  
#etc that may cause exceptions 
#$webapp.WebConfigModifications.Clear() 
 
DeleteSections $webapp $modificationOwner $false 
 
#=============================================================================================================== 
Write-Host "`nAdding Web Config Nodes" 
 
#load the xml data 
[xml]$Data = get-content $webconfigData 
 
foreach ($Section in $Data.Sections.Section) 
{  
    #Ignore sections marked to be skipped 
    if ($Section.Skip -eq "false") 
    { 
        $path = $Section.Path 
        foreach ($modification in $Section.modifications.ChildNodes) 
        { 
            if ($modification.type -eq "EnsureAttribute") 
            { 
                $type = $EnsureAttribute 
                $name = $modification.name 
                  $value =  $modification.value  
                 
                Write-Host "`nChanging $path -> $name to $value" 
            }             
            else 
            { 
                $type = $EnsureChildNode 
                $name = $modification.name 
                $value = "<" + $modification.value + "/>" 
                 
                Write-Host "`nAdding Modifications -> $path : $name, $value" 
            }         
             
            CreateConfigChildNode $modificationOwner $type $path $name $value 
        } 
    } 
} 
 
#=============================================================================================================== 
Write-Host "`nApplying Modifications to the Web.Config"         
$webapp.Update() 
$webapp.Parent.ApplyWebConfigModifications() 
Write-Host "`nCompleted Web.Config Modifications" 
 
#----- END OF FILE  -----# 
 
#----- START of FUNCTION FILE ----# 
 
#=================================================================== 
# Web Config Modifications Script Functions 
#=================================================================== 
 
#=================================================================== 
# function to Create Web Config nodes and or change attributes 
#=================================================================== 
function CreateConfigChildNode($Owner, $Type, $Path, $Name, $Value) 
{ 
    $childNode = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification  
    $childNode.Owner = $Owner 
    $childNode.Path = $Path 
    $childNode.Name = $Name 
    $childNode.Value = $Value 
    $childNode.Type = $Type 
 
    $webapp.WebConfigModifications.Add($childNode) 
} 
 
#=================================================================== 
# function to remove all existing node and changes to attributes matching the Owner name 
#=================================================================== 
function DeleteSections($webapp, $Owner, $removeOnly) 
{ 
    $count =  $webapp.WebConfigModifications.Count 
    $foundNodes = $false 
    for ($i=$count ;$i -gt -1; $i--) 
    { 
        if ($webapp.WebConfigModifications[$i].Owner -eq $Owner) 
        { 
            $foundNodes = $true 
            Write-Host "`n$i" 
            $webapp.WebConfigModifications.Remove($webapp.WebConfigModifications[$i]) 
        } 
    } 
 
    if ($foundNodes -and $removeOnly) 
    { 
        $webapp.Parent.ApplyWebConfigModifications() 
        $webapp.Update() 
    } 
} 
 
#----- END OF FILE  -----#

 

Entering Formulas for Calculated Fields in Lists

A few pointers to those creating calculated columns/fields in SharePoint 2010.

  1. When entering a formula when creating the field initially, it has to have no syntax errors otherwise you will get a nasty error page! If you get this error clicking the back button will take you back to where you were.
  2. Another way to to create the field with a dummy formula and edit the formula by displaying the list in the data sheet view mode. In SharePoint 2010 this is greatly improved! Its also a great way to debug your formula if it is complex.
  3. If you have a very complex formula – below is one I created – you could construct it in say NotePad in parts to help reduce errors while creating your formula.

=IF(ISERROR(SEARCH(” hrs”,Duration,1)), IF(ISERROR(SEARCH(” mins”,Duration,1)), TIME(HOUR(Duration),MINUTE(Duration),0), TIME(HOUR(0),MINUTE(“0:”&REPLACE(Duration, SEARCH(” mins”,Duration,1),5,””)),0)), TIME(HOUR(REPLACE(Duration, SEARCH(” hrs”,Duration,1),4,””)),MINUTE(REPLACE(Duration, SEARCH(” hrs”,Duration,1),4,””)),0))*24

PerformancePoint KPI’s from SharePoint Lists

So recently I started working on a new DashBoard project in SharePoint 2010. One of the requirements was to have KPI’s with trends driven of data stored in SharePoint lists.

While SharePoint provides some nice of the box KPI’s for data stored in Lists, it is not possible to create complex trend based metrics. fortunately PerformancePoint enables you to create KPI’s using SharePoint List data.

Below is an example of how this can be accomplished. This post assumes you have access to the enterprise license and have PerformancePoint and publishing features enabled, plus the PerformancePoint Service application has been created and setup.

  1. The first step is the create the lists with the required columns and some data. In order to have a trend like metric this means you will need two lists – one for the current data and one with older data to trend against.
  2. Next you need to have a Business Intelligence site created – so you can get to the DashBoard designer for PerformancePoint – I’ve not found a way yet to start this app from outside of  this site.  UPDATE: You can get to the designer from the Start Menu. It’s in the SharePoint folder.  A BI site is still has to be created so there is a place to store all the PerformancePoint Content created by the designer.
  3. When the designer is running the following steps are required:
  1. Create a new Data Connection, selecting a Tabular List and the SharePoint List template:

  2. Next you have provide the Url of the site containing your list, select “All Lists” and then the list name itself. NOTE: PerformancePoint will only pull data from the default (All Items) view of the list. Any data filtered on that view will not be available.
  3. Next select the “Properites” tab – give you new dataconnection a meaniful name!
  4. Now go to the “View” tab. Here you will see all of the available columns part of the view of the list. By default all non date fields are Fact Columns and all dates fields are Time Dimension. Data in the fact type columns are by default summed together; you can change this by selecting a new value from the Aggregation dropdown box to the right, to eg. Average.
  5. Save you chnages – click to little save button on the top left of the application – and you have your first SharePoint List Data Connection.

In my next post I will cover creating a KPI from this Data Connection.