Install SharePoint 2013 development environment

08/31/2016

Today I tried to install a new development environment for SharePoint 2013 on a virtual machine. It turns out there are a few things to think about when doings this. First off I had to install the Windows Server 2012 R2 whitout installing any updates. This is beacuse if you do install all the updates first you will install newer versions of the .net framework for instance which will not be compatible with the installer for SharePoint 2013. You will get an error message saying .NET 4.5 is not installed when trying to run the installer. The prerequisites installer and everything will still run just fine. It might have been a bit much but after trying to uninstall the updates for .NET framework and still not being able to run the installer yielding the same error I decided to just reinstall Windows Server 2012 R2. After the installation I ran the prereq installer straight away before installing any windows updates. The prereq installer reboots the server a couple of times so I let it do it’s thing.

After all this I tried running the installer but got an error message saying something like “there was an error with the installer”. No other explanation to what the error might be or anything other than that it failed. I looked in the event log and found an application error there with the following text: Faulting application name: MsiExec.exe

After searching google for a few minutes I found these links:

http://expertsharepoint.blogspot.se/2014/08/sharepoint-2013-sp1-installation-failed.html

https://praveenix.wordpress.com/2014/08/04/sharepoint-2013-sp1-installation-failing-with-event-id-1000-faulting-application-name-msiexec-exe/

Which described the same problem. The issue was with a couple of registry keys and in my case one of them were present. I looked for HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations and HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\FileRenameOperations.

The latter was present in my case so I deleted it and the installation went off without a hitch.

 

UPDATE:

Apparently this was not the end of the story. When I tried to run the products and configuration wizard everything seemed to work until it was creating the sample data. Now the solution to this was in my oppinion even more wierd. I found this technet wiki post that described the same problem:

http://social.technet.microsoft.com/wiki/contents/articles/17933.sharepoint-2013-the-sddl-string-contains-an-invalid-sid-or-a-sid-that-cannot-be-translated.aspx

I am pasting the solution here aswell just in case the link doesn’t work:

  • Add the account you want to use for search service in WSS_Admin_WPG group. If you are going to use built in administrator account this should be present by default.
  •  Then execute this command from sharepoint powershell console:
  • $SearchService = Get-Credential Domain\UserName

In our scenario of standalone installation the Domain should be the machine name.

  • Then execute this command: New-SPManagedAccount -Credential $SearchService
  • Now Go to “C:\Program Files\Microsoft Office Servers\15.0\Data\Office Server” and find the folder that starts with Analytics with a postfix guid.
  • Note: If you selected a different location to store index files, check this path! 
  • Right-click –> Properties–>Sharing–>Advanced Sharing
  • Check the “Share this folder’ check box and click on Permissions
  • Add the Search Service account created in step 2 and select Full Control. Do the same for WSS_ADMIN_WPG
  • Run the SharePoint Configuration Wizard again. It should now complete successfully.

Restore from unattached content database

06/26/2013

This is a great way to restore data in SharePoint. Using powershell you can connect to an unattached content database that you restored from a database backup. Then export the site, web or list you want to restore from to the same site collection or web you want to place the items in.

This gives the posibility of doing granular restores in SharePoint which I found difficult or impossible in other tools.

 

I put the following script in a ps1 file and run it from the SharePoint Management Shell:
 
param (
   [string]$dbName = $(Read-Host -prompt “Name of content database”),
   [string]$dbServer = $(Read-Host -prompt “Database server name”),
   [string]$siteUrl = $(Read-Host -prompt “URL of site to restore (i.e. /sites/mytestsite)”),
   [string]$webUrl = $(Read-Host -prompt “URL of web to restore (i.e. Mysubweb/level2. Leave empty to restore site collection)”),
   [string]$exportPath = $(Read-Host -prompt “Path and filename for export file (use .cmp as extension)”),
   [string]$importUrl = $(Read-Host -prompt “URL to import site or web to. Note: this web must be created using the same template as the exported web”)
)
 
$db = Get-SPContentDatabase -ConnectAsUnattachedDatabase -DatabaseName $dbName -DatabaseServer $dbServer
$site = $db.Sites[$siteUrl]
$web = $site.RootWeb
 
if($webUrl -ne “”)
{
   $web = $site.AllWebs[$webUrl]
}
 
Export-SPWeb $web -Path $exportPath -IncludeUserSecurity -IncludeVersions All -NoFileCompression
Import-SPWeb $importUrl -Path $exportPath -IncludeUserSecurity -NoFileCompression
 

Read programmatically rendered SharePoint fields postback data

10/19/2012

In my prevoius post I had examples of how to render SharePoint fields on a form. This is a followup on that subject and explains by code example how to read the data sent through postback from those fields.

To make it easier I added the code to a series of pages.

I also added my class files if you’d like to try the code.
HttpFormManager
SPPostbackDataManager

Add documentset welcomepage fields using powershell

10/19/2012

Recently I came across the problem of adding the contenttype of a created documentset to the welcomepage fields. This could not be done through documentset settings on the content type in the GUI. After a few minutes tinkering I got a powershell script to add the field I needed.

Here’s the powershell script I ended up using:


[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.DocumentManagement")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$weburl = "http://myweburl"
$web = Get-SPWeb $weburl
$lib = $web.Lists["Listname"]
$ctfield = $null
foreach($item in $lib.Items | Where-Object {$_.Folder -eq $null})
{
    Write-Host "Fields of " $item.Name
    foreach($field in $item.Fields)
    {
        if($field.Title -eq "Content Type")
        {
            Write-Host "Found field " $field.Title
            $ctfield = $field
        }
    }
    Write-Host ""
}
foreach($item in $lib.Items | Where-Object {$_.Folder -ne $null})
{
    Write-Host "Adding content type field to " $item.Name
    $ds =  [Microsoft.Office.DocumentManagement.DocumentSets.DocumentSet]::GetDocumentSet($item.Folder)
    $dst = $ds.ContentTypeTemplate
    $dst.WelcomePageFields.Add($ctfield)
    $dst.Update($true)
    Write-Host ""
}

Since I’m updating the content type template I assume it would be possible to just update the first documentset found in the collection, however I couldn’t get the break to work properly for these loops so I just ignored that fact for now.

Render fields on form programmatically

07/08/2012

For a recent project I was faced with the problem of having to render fields programmatically in a dynamic fashion and then save the posted values of these fields in a listitem.

Rendering the fields where pretty trivial once you figure out how the BaseFieldRenderingControl property works.

I ended up with the following code for rendering a user field and returning the validation script of the user control. The only thing the validation script covers is the required field option. It does not take the validity of users into account!


/// <summary>
/// Renders a SharePoint User or UserMulti field.
/// </summary>
/// <param name="Title">HtmlTableCell for title element</param>
/// <param name="Body">HtmlTableCell for control and description element</param>
/// <param name="Field">SPField object to render</param>
/// <returns>Validation script as string</returns>
public static string RenderUserField(HtmlTableCell Title, HtmlTableCell Body, SPField Field)
{
string validationScript = string.Empty;

if ((Field != null) && (Field.FieldRenderingControl != null))
{
Title.Attributes.Add("class", "ms-formlabel");
Title.Attributes.Add("nowrap", "true");
Title.Controls.Add(new LiteralControl("<h3>" + Field.Title));

Body.Attributes.Add("class", "ms-formbody");
Body.EnableViewState = true;

if ((Field.TypeAsString == "User") || (Field.TypeAsString == "UserMulti"))
{
PeopleEditor pplEdit = new PeopleEditor();
pplEdit.ID = Field.InternalName;
pplEdit.AllowTypeIn = false;
pplEdit.ValidatorEnabled = true;
pplEdit.PlaceButtonsUnderEntityEditor = false;
pplEdit.MultiSelect = (Field.TypeAsString == "UserMulti");
pplEdit.Rows = 1;
pplEdit.PreferContentEditableDiv = true;
pplEdit.EnableViewState = true;
pplEdit.AllowEmpty = !Field.Required;

Body.Controls.Add(pplEdit);

validationScript = "var obj_" + Field.InternalName + " = document.getElementById('ctl00_PlaceHolderMain_" + Field.InternalName + "_checkNames'); if(obj_" + Field.InternalName + " != null) { obj_" + Field.InternalName + ".style.display = 'none'; }";

if (Field.Required)
{
Title.Controls.Add(new LiteralControl("<span style='color:red;'> *</span>"));
Body.Attributes.Add("req", "user");
}
}
Title.Controls.Add(new LiteralControl("</h3>"));

if (!string.IsNullOrEmpty(Field.Description))
{
Body.Controls.Add(new LiteralControl("<br /><span>" + Field.Description + "</span>"));
}
}

return validationScript;
}

And the following code for rendering all other fields including taxonomy fields. Same this here with the validation of course. If the field is required, the javascript checks the field for an empty value before posting.


/// <summary>
/// Renders a SharePoint field.
/// </summary>
/// <param name="Title">HtmlTableCell for title element</param>
/// <param name="Body">HtmlTableCell for control and description element</param>
/// <param name="Field">SPField object to render</param>
/// <param name="currentContext">SPContext object based on item context</param>
/// <returns>Validation script as string</returns>
public static string RenderBaseField(HtmlTableCell Title, HtmlTableCell Body, SPField Field, SPContext currentContext)
{
string validationScript = string.Empty;

if ((Field != null) && (Field.FieldRenderingControl != null))
{
Title.Attributes.Add("class", "ms-formlabel");
Title.Attributes.Add("nowrap", "true");
Title.Controls.Add(new LiteralControl("<h3>" + Field.Title));

Body.Attributes.Add("class", "ms-formbody");
Body.EnableViewState = true;

BaseFieldControl fldCtrl = Field.FieldRenderingControl;
fldCtrl.ListId = Field.ParentList.ID;
fldCtrl.ControlMode = SPControlMode.New;
fldCtrl.ID = Field.InternalName;
fldCtrl.ItemId = 0;
fldCtrl.FieldName = Field.InternalName;
fldCtrl.EnableViewState = true;
fldCtrl.RenderContext = currentContext;
fldCtrl.ItemContext = currentContext;

Body.Controls.Add(fldCtrl);

if (Field.TypeAsString == "Choice")
{
SPFieldChoice fldChoice = new SPFieldChoice(Field.ParentList.Fields, Field.InternalName, Field.Title);

if (fldChoice.EditFormat == SPChoiceFormatType.Dropdown)
{
validationScript = "var obj_" + Field.InternalName + " = document.getElementById('ctl00_PlaceHolderMain_" + Field.InternalName + "_DropDownChoice'); if(obj_" + Field.InternalName + " != null) { insertEmptyOption(obj_" + Field.InternalName + "); }";
}
}

if (Field.Required)
{
Title.Controls.Add(new LiteralControl("<span style='color:red;'> *</span>"));

if (Field.TypeAsString == "URL")
Body.Attributes.Add("req", "url");
else if (Field.TypeAsString == "MultiChoice")
Body.Attributes.Add("req", "multichoice");
else if (Field.TypeAsString == "Choice")
Body.Attributes.Add("req", "choice");
else if (Field.TypeAsString == "LookupMulti")
Body.Attributes.Add("req", "lookupmulti");
else if (Field.TypeAsString == "Number")
Body.Attributes.Add("req", "number");
else if (Field.TypeAsString == "Currency")
Body.Attributes.Add("req", "currency");
else
Body.Attributes.Add("req", "field");
}

Title.Controls.Add(new LiteralControl("</h3>"));

if (!string.IsNullOrEmpty(Field.Description))
{
Body.Controls.Add(new LiteralControl("<br /><span>" + Field.Description + "</span>"));
}
}

return validationScript;
}

Since I’m adding these values to a non existing list item I need to send a context object that isn’t based on the item ID. Here’s how i call the functions:


/// <summary>
/// Render form fields for a list or content type.
/// </summary>
/// <param name="List">SPList to render fields for.</param>
/// <param name="ContentType">Selected contenttype to render fields for or null.</param>
/// <param name="FormControls">asp:Panel to contain fields table.</param>
/// <param name="Scripts">asp:Panel to contain validation scripts.</param>
public static void RenderFormFields(SPList List, SPContentType ContentType, Panel FormControls, Panel Scripts)
{
SPContext ctx = SPContext.GetContext(HttpContext.Current, List.DefaultView.ID, List.ID, List.ParentWeb);
ctx.FormContext.FormMode = SPControlMode.New;
SPFieldCollection FieldsToRender = List.Fields;
FormControls.Controls.Clear();
Scripts.Controls.Clear();

if (ContentType != null)
{
FieldsToRender = List.ContentTypes[ContentType.Id].Fields;
}
foreach (SPField fld in FieldsToRender)
{
if (!fld.Hidden)
{
if (
(!Constants.ExcludedFieldTypes.Contains(fld.TypeAsString)) &&
(!Constants.ExcludedFieldInternalNames.Contains(fld.InternalName))
)
{
HtmlTableRow row = new HtmlTableRow();
HtmlTableCell cellTitle = new HtmlTableCell();
HtmlTableCell cellControl = new HtmlTableCell();

if ((fld.TypeAsString == "User") || (fld.TypeAsString == "UserMulti"))
{
Scripts.Controls.Add(new LiteralControl(SharePointManager.RenderUserField(cellTitle, cellControl, fld)));
}
else
{
Scripts.Controls.Add(new LiteralControl(SharePointManager.RenderBaseField(cellTitle, cellControl, fld, ctx)));
}

row.Cells.Add(cellTitle);
row.Cells.Add(cellControl);

FormControls.Controls.Add(row);
}
}
}
}

Programmatically write to a taxonomy field

11/08/2011

After several beginner mistakes it turns out it’s quite easy to write to a taxonomy field. Finding the solution took a while though.
The code below writes a term to MyField provided the term is known and the list item is known.

TaxonomyField txField = listItem.Fields["MyField"] as TaxonomyField;
if (txField != null)
{
txField.SetFieldValue(itm, myTerm);
}

SharePoint 2010 SyncDB keeps growing out of control

09/18/2011

I’m sure there are several others that’s had this problem so I thougt I’d share a solution I found recently.
The SyncDB is filled with instance data for every sync that is made. If you run on an SQL Server Express as many propably are you will sooner or later run out of space for this database. In case you’re not running SQL Express you might want to implement this anyway. Since a database growing out of control is never good.

The link below contains a stored procedure that cleans the instance data that is no longer usable from the database. Something that should have been included oob in SharePoint but I guess Microsoft forgot about.
http://paulliebrand.com/2011/05/26/user-profile-synchronization-database-growing-out-of-control/

For my own sake I’ll include the script in this post aswell.

USE [Sync DB]
GO

/****** Object: StoredProcedure [fim].[TruncateInstanceData] Script Date: 08/10/2011 14:09:11 *****/

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [fim].[TruncateInstanceData]
AS
BEGIN

--************************************************************
--* * *
--* Copyright (C) Microsoft. All rights reserved. *
--* *
--************************************************************
SET NOCOUNT ON;
DECLARE @truncationTime datetime;
SET @truncationTime = DATEADD(day, -1, GETUTCDATE());
DELETE FROM [dbo].[InstanceData]
WHERE ([created] < @truncationTime)
END

Before running this script you need to create a schema called FIM and change the DB name to match your own database.
and to quote Paul:

DISCLAIMER: Microsoft has told me that this script cannot be altered in anyway or I run the risk of being unsupported. Please use this at your own discretion.

First look at Google App Engine

11/26/2010

I tried walking through the Python overview of Google app engine today. So easy to learn and use even if you’re not a Python developer.
Using the django templates is a must. So far I havent tried using eclipse since i started with Python but I found a plugin (pyDev) which supposedly adds Python support to eclipse. Using the app engine Windows application makes it really easy to run your solution but I would personally like a debuger and not having to rely on response.out.write for debug messages.
Database support is basically just writing another class and you don’t even need to know SQL. I suppose it helps though if you want to use GQL for querying the database.
The preferences with Google hosting the solution, providing api’s for just about anything you want far outweighs the disadvantage of not being in total control of the data. The tight integration with Google apps services that even works locally is really impressive. No need for login controls, account handling pages or anything like that anymore. Google does it all for you!