Category: Microsoft

Azure SQL with AAD authentication

I though this had to be an easy task. Well, actually it is. If you find the right documentation and read it in the correct order 🙂

Basically I wanted to be able to login with my AAD (Azure Active Directory) user.

In the first step, the database needs to be configured for Azure Active Directory in order to add users in the second step.

Configure an Administrator

In the Azure portal go the the SQL server and search for “active directory” to add an Active Directory admin.

After you’ve added an admin and saved the value, you will be able to use SSMS (SQL Server Management Studio) to logon to the server. Probably SSMS will prompt you about a firewall exception.

Use SQL Management Studio to add users and grant permissions

For other users (not the administrator we configured above) to be able to logon, access has to be granted like with an on premises SQL Server.

Add a user to the master DB

Create a new query o


Next grant permissions to the user on the database itself.

Add user to database

Open another query on the database.

ALTER ROLE [db_owner] ADD MEMBER [];

That should be it.

Some documentation I used:

23 Jun

Two Hackathons in a week

What a week. Two hackathons (‘hack’+marathon) in a row. That was exhausting.

  • A three day hackathon with my colleges from Arvato Systems and a customer. We’ve used Cognitive services with 8 different programming languages and created great PoCs.









  • The second hackathon was about Azure Stack with Microsoft.

Thanks to all participants, the organisation. It has been fun and a great experience. Now I am looking forward on how the results will influence decisions for follow-up projects.

Besides the work, I enjoyed the opportunity to get to know  you all better and had some interesting networking. Let’s see what events the future brings 😉

No Default Subscription?

Set-AzureWebsite : No default subscription has been designated. Use Select-AzureSubscription -Default <subscriptionName> to set the default subscription.

*doh* Again I’ve used PowerShell comandlets for Azure classic instead of Resource Manager 🙁

Reminder: Always check for the magic “Rm” chars in the command, if a resource cannot be found.

HowTo use Azure cmdlets in Azure Schedule

A Runbook schedule can be triggered every hour. If you need a smaller interval, like every minute, you can use the Azure Scheduler to do so.
So I went to the Azure Portal, created an Azure Schedule instance (with a job collection tier of at least basic, to be able to create schedules that are triggered every minute) and called a Runbook via webhook.

The Runbook contains a cmdlet that results in an error 🙁
Get-AzureRmMetric : The term 'Get-AzureRmMetric' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try

Azure cmdlets can be made available through the Automation Account the Runbook is using. The “Browse Gallery” link will let you find and choose the necessary cmdlets.

The error message above appears, because a) the cmdlet was not installed and b) the referenced version of AzureRM.profile was to old. Fortunately the problem can be resolved easily by upgrading the Azure modules.

After all modules are up to date, I could add the desired module and my runbook wasn’t complaining anymore 🙂

Connection Problems to a Secure Service Fabric Cluster

To be able to connect to a secure Service Fabric Cluster via PowerShell, you need to import the certificate specified into your personal certificate store. Otherwise an Exception will be thrown. Unfortunately the Exception does not point into the right direction 🙁

So in case you get an Exception like this

Connect-ServiceFabricCluster : An error occurred during this operation. Please check the trace logs for more details.
At line:1 char:1
+ Connect-ServiceFabricCluster -ConnectionEndpoint xyz-sf-de …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Connect-ServiceFabricCluster], FabricException
+ FullyQualifiedErrorId : CreateClusterConnectionErrorId,Microsoft.ServiceFabric.Powershell.ConnectCluster

you need to import the certificate with its private key (*.pfx) into the personal certificate store of the PC you are running PowerShell on.


Specifying -verbose for PowerShell will print additional information, that does not help a lot.

PS C:\WINDOWS\system32> Connect-ServiceFabricCluster -ConnectionEndpoint -X509Credential -FindType FindByThumbprint -FindValue xyz -StoreLocation CurrentUser -StoreName My -ServerCertThumbprint xyz -Verbose
VERBOSE: System.Fabric.FabricException: An error occurred during this operation. Please check the trace logs for more
details. —> System.Runtime.InteropServices.COMException: Exception from HRESULT: 0x80071C57
at System.Fabric.Interop.NativeClient.IFabricClientSettings2.SetSecurityCredentials(IntPtr credentials)
at System.Fabric.FabricClient.SetSecurityCredentialsInternal(SecurityCredentials credentials)
at System.Fabric.Interop.Utility.<>c__DisplayClass25_0.<WrapNativeSyncInvoke>b__0()
at System.Fabric.Interop.Utility.WrapNativeSyncInvoke[TResult](Func`1 func, String functionTag, String
— End of inner exception stack trace —
at System.Fabric.Interop.Utility.RunInMTA(Action action)
at System.Fabric.FabricClient.InitializeFabricClient(SecurityCredentials credentialArg, FabricClientSettings
newSettings, String[] hostEndpointsArg)
at Microsoft.ServiceFabric.Powershell.ClusterConnection.FabricClientBuilder.Build()
at Microsoft.ServiceFabric.Powershell.ClusterConnection..ctor(FabricClientBuilder fabricClientBuilder, Boolean
at Microsoft.ServiceFabric.Powershell.ConnectCluster.ProcessRecord()
Connect-ServiceFabricCluster : An error occurred during this operation. Please check the trace logs for more details.
At line:1 char:1
+ Connect-ServiceFabricCluster -ConnectionEndpoint xyz-sf-de …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Connect-ServiceFabricCluster], FabricException
+ FullyQualifiedErrorId : CreateClusterConnectionErrorId,Microsoft.ServiceFabric.Powershell.ConnectCluster

Widgets instead of Add-Ins/Apps?

The concept of Add-Ins (formally knows as Apps) in SharePoint puts logic as HTML and CSS to another page. This page is then rendered as iFrame to another SharePoint page. This approach has advantages and disadvantages. You have to decide yourself.

A very promising way to put stuff (or WebParts) onto a SharePoint page is the Widget Wrangler.

More information can be found on

Conceptually Widget Wrangler implementation is based on similar thinking as PnP App Script Part implementation, which was released few years back as part of the PnP patterns (or at the time it was call App Model Samples). Advantages of this model is that you do not have deal with iFrame implementations and functionalities can be fully responsive, where needed. Also implementation of the capabilities is much simpler when your JavaScript is directly embedded to the page rendering logic without additional complexity.

In demo section Bob is showing following topics

  • How to use Widget Wrangler with plan JavaScript?
  • How to use Widget Wrangler with jQuery?
  • How to use Widget Wrangler with KnockoutJS?
  • How to use Widget Wrangler with Angular?
  • How does Widget Wrangler handle multiple instances of same widget in the SharePoint Pages?

I like that. As soon as I’ve some spare time, I will take a close look.

Fix “Access Denied” on Registry and Filesystem

Today I installed the May CU on a SharePoint 2013 farm hosted in Azure. After the Installation was done (with a PowerShell script that disables some services to speed up the process), there were Exceptions opening the User Profile Service (UPS) settings page.

So I investigated the logs and found many entries about “Access Denied”. Some directly pointed to the registry hive “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\15.0” with the message Requested registry access is not allowed. or Getting Error Message for Exception System.Security.SecurityException: Requested registry access is not allowed., others about access to directories Access to the path ‘C:\Program Files\Microsoft Office Servers\15.0\Data\Office Server\CanonicalResources\ProjectionModels\EN_EN.mdl’ is denied.

Well, the short answer to fix the problem is: You need to execute the SharePoint Configuration Wizard on each server of the farm after installing an update.

Need users in your dev environment?

Often, you’ll need some users with data like picture and manager in your new development environment. Since you usually recycle your dev AD, this doesn’t happen frequently. But if you have to set up a new domain, you’ll want testusers with data.

I don’t want to search again, because I found a great resource for creating users here:

Have fun with PowerShell

Create the default groups via PowerShell

If your site is missing the three default groups “Visitors”, “Members” and “Owners”, you can create them easily with PowerShell or the Object Model.

Add-PSSnapin Microsoft.SharePoint.PowerShell

$web = Get-SPWeb
if ($web.AssociatedVisitorGroup -eq $null) {
    Write-Host 'The Visitor Group does not exist. It will be created...' -ForegroundColor DarkYellow
    $currentLogin = $web.CurrentUser.LoginName

    if ($web.CurrentUser.IsSiteAdmin -eq $false){
        Write-Host ('The user '+$currentLogin+' needs to be a SiteCollection administrator, to create the default groups.') -ForegroundColor Red

    $web.CreateDefaultAssociatedGroups($currentLogin, $currentLogin, [System.String].Empty)
    Write-Host 'The default Groups have been created.' -ForegroundColor Green
} else {
    Write-Host 'The Visitor Group already exists.' -ForegroundColor Green


Update to the SharePoint Solution Deployer

A new version is out. If brings some great new extensions (two of them are from me 🙂 )

v5.0.4.6440 (2015-04-04)

  • New: All extensions added: Blocked file extensions, content type hub, custom crawl connector, features, logging configuration, managed metadata, re-ghost, search schema, secure store, site structure, CSOM extensions for files and 2013 workflows
  • Updated: SharePointVersions.xml
  • Updated: Typos in comments fixed and some code clean-up
  • First release based on GitHub repository

Grab your version from

The SharePoint Solution Deployer

Deploying Solutions can be a …. (fill in as you wish).

The SharePoint Solution Deployer offers a great opportunity to writing your own scripts. The existing functionality should match your needs to deploy SharePoint Solutions. If not, the “framework” can be extended with custom Extensions or simple PowerShell code.

I’ve written two Extensions, which let you enable and disable features upon deployments and reset files to their site definitions (aka ReGhost).

To be able to have different URLs for your dev-machine, staging and production farms, simply create additional XML-files and configure URLs there. The XML-file needs to be named with the hostname of the server, where you want start the deployment.


The example shows two files within the Environment subfolder.

Default XML Configuration file (Default.xml)

<?xml version="1.0" encoding="utf-8" ?>
<SPSD Version="">
	<Configuration ID="Default">

	<Environment ID="Default">

		<Variables ID="Default">
			<!-- Default values are for production. Change values in Hostname.xml file to your needs.-->
			<Variable Name="CentralAdministrationWebAppUrl">https://xxx:11111</Variable>
			<Variable Name="WebAppUrl">https://prod.sharepoint.local</Variable>

		<PreRequisiteSolutions ID="Default">

		<Solutions ID="Default" Force="false" Overwrite="true">


The script will look if there is any XML file with the name “hostname.xml”

<?xml version="1.0" encoding="utf-8" ?>
<SPSD Version="">
	<Environment ID="Default">

		<Variables ID="Default">
			<!-- Default values are for production. Change values in Hostname.xml file to your needs.-->
			<Variable Name="CentralAdministrationWebAppUrl">https://xxx:22222</Variable>
			<Variable Name="WebAppUrl">https://dev.sharepoint.local</Variable>

That’s it.

You can start the deployment with e.g. “Redeploy.bat” from the Rootfolder, no matter which farm you are on.

Use a XML-file for configuration in PowerShell scripts

Time for some PowerShell!

Almost every PowerShell script need some configuration parameters. With this post I want to show one way, there are others ;-), to parse a config file in XML format and use the values later.

The solution I’m going to show to you contains three files. A PowerShell script, a XML configuration file and a helper PowerShell file that contains a function to parse the config file.

PowerShell XML config files

The config file contains

	<hyperv dir="C:\Hyper-V\New_Server">

The helper function to parse the configuration file looks like this

# Parse Configuration file
function ParseConfig([string]$filename) {
	try {
		$file = Get-Item -Path $filename
		if ($file.Exists) {
			$root = "config"
			$cfg = [xml] ( Get-Content -Path $filename )
			return $cfg.config
		else {
			Write-Host "The configuration file "$filename" does not exist" -ForegroundColor Red
	catch {
		Write-Host "Cannot load configuration file "$filename -ForegroundColor Red
	return $null

And finally the main script, that will reference the helper function, call it and use the values.

# modify here
$cfgFile = "NewHyperVConfig.xml"
# stop modifying content below
# ----------------------------

# load functions from other files
. "$PSScriptRoot\helper\Configuration.ps1"

# load and parse config from xml file
$cfg = ParseConfig $PSScriptRoot"\"$cfgFile

# start doing something
Write-Host $cfg.hyperv.dir
Write-Host $cfg.hyperv.ram

Summary: Store configuration settings in a XML file and use the values in PowerShell script.

Getting the PageTitle

Getting the PageTitle of a page should be just a property away would you think. I would call Page.Title to get the title of the current page.

Unfortunately Page.Title contains “\r\n           ” and the title of the page is in a new line, like this:

	RH Test


The property will only return the first row, which is not very helpful 🙁

So what can we do? Since the title is set through a control within a ContentPlacehoder, my way was to get the control and take the value from it. And… it worked. An extension method will traverse all controls, to find the desired one.

public string GetPageTitle()
	var literal = Page.Header.FindControlsOfType<ContentPlaceHolder>().Single(p => p.ID == "PlaceHolderPageTitle").FindControlsOfType<EncodedLiteral>().FirstOrDefault();
	if (literal != null)
		string pageTitle = literal.Text;
		return pageTitle;
	return null;

// and an extension method (need to go to a static class!
public static IEnumerable<T> FindControlsOfType<T>(this Control control) where T : Control
	foreach (Control child in control.Controls)
		if (child is T)
			yield return (T)child;
			foreach (T grandChild in child.FindControlsOfType<T>())
				yield return grandChild;

Page.Title, I got you 😉

Updating the title within a SPItemEventReceiver with AfterProperties

Recently I had a problem setting the title field of a Page within the pages library. My requirement was to set the title with the value from the PageTitle field of the current item.

An ItemEventReceiver, which is executed synchronously to prevent save conflict exception or problems with published items, was supposed to do exactly that. But when I set the title property of the item via AfterProperties, the value did not get stored. I tried other fields, and they got written to the item just fine. After some trial-and-error and consulting the MSDN I found a solution.

The ItemEventReceiver needs to update the vti_title field instead. This field exists on a SPFile. And since a Page is a SPFile, you’ll need to modify that field instead.

public override void ItemAdding(SPItemEventProperties properties)

public override void ItemUpdating(SPItemEventProperties properties)

/// <summary>
/// Set title from PageTitle
/// </summary>
/// <param name="properties"></param>
private void UpdateTitleField(SPItemEventProperties properties)
	var title = Convert.ToString(properties.AfterProperties["PageTitle"]);
	if (!string.IsNullOrEmpty(title) && properties.List.Fields.ContainsFieldWithStaticName("vti_title"))
		properties.AfterProperties["vti_title"] = title;

With this code, the title of my page was changed as supposed to.

.NET goes OpenSource!

Das sind doch mal hervorragende Neuigkeiten!

Microsoft hat im Rahmen seiner Online-Konferenz connect(); am Mittwoch bekannt gegeben, dass das komplette .NET Framework zukünftig als Open-Source-Software unter der MIT-Lizenz stehen wird.


Das freut mich als Entwickler natürlich sehr. Dann können meine PI’s bald noch mehr durch Mono 🙂

Bisher wird per USB/RS232 der Stromzähler über die Infrarot-Schnittstelle ausgelesen 😉

Why I prefer WebApplication deployments over GAC deployments

This article is written with scope on SharePoint 2013. With SP 2013 the default TrustLevel in the web.config is set to “FullTrust”. On previous version the value is “WSS_Minimal”.

When you develop Farm-Solutions for SharePoint, you can deploy assemblies to the Global Assembly Cache (GAC) or configure the solution for a “bin-Deployment”.

The bin-way puts assemblies into the bin folder of the WebApplication, where the solution is deployed to.

You can switch the target of the assemblies by modifying the properties of a SharePoint project. The default value is GlobalAssemblyCache.

What does the changed property do to your solution?

Changing the value to WebApplication will deploy the assembly to the bin-directory of your IIS directory, as mentioned earlier. Because of the narrowed scope of the assembly, only the associated application pools needs to be recycled.

The classes you implemented, will be available only to your Website, which is fine in most cases. Assemblies within the GAC are available for all processes on the server.

In the past (prior SharePoint 2013) assemblies did not have FullControl permissions if they were deployed to the bin-directory. Instead Partial Trust was granted with the “WSS_Minimal” policy. A custom Code Access Security (CAS) had to be configured.

An advantage was the least privileges approach, a disadvantage the overhead of creating this CAS.

This is a list with advantages and disadvantages for bin-deployments. Pick your items and weight them the way you prefer.

My result was to deploy to bin, if possible. The faster development and deployment together with minimal impact on productive servers was worth it.


  • Faster Deployment – With a GAC Deployment all application pools (incl. CentralAdministration) will be recycled
  • Less impact on other components


  • TimerJobs need assemblies within the GAC
  • Using Feature Receivers, you’ll need to recycle the CentralAdministration application pool as well. Otherwise activating a Feature through the UI, could load the old assembly
  • Only one version of an assembly

What do you think? Why do you deploy to bin or to GAC?

Custom field and UpdateFieldValueInItem()

Recently I was developing a custom field. To store modified values, the UpdateFieldValueInItem method has to be overwritten.

In a normal way of clicking the submit/save button, the method is called and I can adjust the value for the field within the current item. The changes are submitted to the database later.

But what if you want to modify items outside of the current item? Sure, you can do so would you think. But you’ll need to consider the scenario that the user does not click submit/save. The method is called on every postback. The PeoplePicker will cause a postback, when it validates its values. There might be other controls as well, which behave this way.

My problem was that I could not modify items, other then the current, without checking if submit/save was clicked. I ended up checking the form for the control, that triggered the postback. If this value is “SaveItem”, I am good.

/// <summary>
/// Updates the underlying value of the field to the latest user-set value. 
/// </summary>
public override void UpdateFieldValueInItem()
	// do not trigger logic, if a post without submit occures. e.g. by PeoplePicker
	if (Context.Request.Form["__EVENTTARGET"].Contains("SaveItem"))

So if you need to know if the item is currently being saved or if you are within a regular postback, look at your form 🙂

Creating a lookup field via elements.xml

This is another post to help me remember. And as a reference for all of you, who cannot remember how to create a SPFieldLookup via XML.

<Field ID="{8b26ec41-b6c3-4327-0066-0c18c0768626}" Name="InternalName" StaticName="InternalName" DisplayName="Display Name" Type="Lookup" ShowField="Title" Mult="TRUE" List="Lists/LookupList" Overwrite="TRUE" />

When you provision a SPField via features, do not forget to add Overwrite=”TRUE”! Otherwise you’ll get an exception like this:

<nativehr>0x8107058a</nativehr><nativestack></nativestack>Fehler beim Binden des Inhaltstyps ‘0x010200C7A18EB120BB4A00892E9E1EE9481C9B0067E475B6FDD54048B347370871443CAD’ an die Liste ‘/sites/rhtest/Lists/LookupList’ für ‘http://rhdevsp2013/sites/rhtest’. Ausnahme ‘<nativehr>0x80070057</nativehr><nativestack></nativestack>’.

Unfortunately the MSDN is not very specific about the Overwrite property:

Optional Boolean. Specifies whether the field definition for a new field that is activated on a site (SPWeb) overwrites the field definition for an existing field, in cases where the new field has the same field ID as the existing field. True if the new field overwrites the existing field with the same field ID; otherwise false. The default is false.

Note, however, that if the existing field is read-only, or if it is sealed, then it will not be overwritten by the field that is being activated, even if this attribute is set to true

Hopefully I’ll think about this the next time a lookup field needs to be provisioned…

Migrate SharePoint Blog to WordPress

As promised here, this is a follow-up post with the tool I developed for the SharePoint to WordPress migration.

First, a screenshot:

Migrate SharePoint ot WordPress Screenshot

What is it, that we have to cover with a migration? Copying the posts is not enough. So I came up with this features:


  • Copy posts
  • Copy comments
  • Copy resources like images and downloads
  • Create needed tags and categories
  • Modify links to local resource
  • deal with https, if links are absolute on the source blog and mixed with http
  • Using web services to connect to source and destination
  • URL rewriting (covered by a WordPress Plugin)
  • Delete all content from the destination blog (for migration testing)
  • Replace strings (with Regex)
  • a nice (WPF) GUI


Originally I’ve build a plain console application. Then I thought that a console application would possibly scare some users. And after some time I wanted to do some WPF again. So I created a WPF application, to wrap all the functionality into a GUI. This way it will be easier to use for the folks out there, who do not like black console applications 😉 Since I am using web services to connect to both blogging platforms, the tool can be executed on any client computer. No access to a server session is required.

To start, you obviously need URLs to the source and destination blog, as well as credentials to the destination blog. Since most blogs are anonymous, you’ll probably not need to fill in the source credentials. The migration starts by hitting the “Migrate Content” button. That should be it for using the tool. It will remember the last entries for the URLs and login names, in case you need to perform multiple runs, which was the case for me. The passwords will need to be reentered for security reasons.

It’ll show the progress of all steps in a progress bar and text at the bottom of the application and tell you when it’s finished. Existing categories are mapped to new categories and used as tag, too. I’ve tested the tool with three blogs, one being my own with installed CKS:EBE. There really isn’t much more to configure, to have your blog being migrated to WordPress with this tool.

Some data needs to be modified, before the blog can go live on the new destination. In case of URLs this is necessary to generate valid links within the destination. Fortunately there is a plugin available to do some fancy rewriting. Since WordPress is showing its own smilies, I wanted to get rid of some strings within the posts, that reference smilies as images and replace them with, well, smilies. A txt file within the same directory with the name “replacestrings.txt” will take lines with strings for replacement.

<img.[^>]*/wlEmoticon-smile_2.png"(>| >|/>| />|</img>)*;#:-)
<img.[^>]*/wlEmoticon-sadsmile_2.png"(>| >|/>| />|</img>)*;#:-)
<img.[^>]*/wlEmoticon-winkingsmile_2.png"(>| >|/>| />|</img>)*;#:-);# 

The sample will replace all my old smilie images with plain string before posts are created on the destination blog. The images that were used as smilies in the source, won’t be copied to the destination, because they are not referenced anymore. Otherwise I got many images with smilies. I like smilies 😀

You can stop reading here, if you are a user and would like to migrate your blog and download the tool. As a developer you might be interested on how the tool works…

Technical stuff

The tool gives me a good opportunity to explain some programming tasks, I used for the migration tool. I will explain some of them.

SharePoint offers web services (_vti_bin/lists.asmx), WordPress an XML RPC interface (I used CookComputing.XmlRpc to connect). Those two are used to connect to the blogs. Since the SharePoint web services need Displaynames to connect to the posts and comments list, I first queried them by list template.

Querying SharePoint for List Titles

Use the SharePoint lists web service, to get all lists of a site and search for specific lists like the posts and comments. The lists are identified by the used template. That way I do not have a localization issue.

_lists = new Lists
	Url = string.Format("{0}/_vti_bin/lists.asmx", BlogUrl),
	Credentials = CredentialCache.DefaultNetworkCredentials
XDocument response = XDocument.Parse(_lists.GetListCollection().OuterXml);
IEnumerable<XElement> lists = response.Root.Descendants(XName.Get("List", _s.ToString()));
foreach (XElement list in lists)
	XAttribute listTemplate = list.Attribute(XName.Get("ServerTemplate"));
	if (listTemplate != null && listTemplate.Value == "301")
		// found Posts list
		PostListName = list.Attribute(XName.Get("Title")).Value;
		PostListServerRelativeUrl = list.Attribute(XName.Get("DefaultViewUrl")).Value.Replace("/AllPosts.aspx", string.Empty);
	else if (listTemplate != null && listTemplate.Value == "302")
		// found Comments list
		CommentListName = list.Attribute(XName.Get("Title")).Value;

With the list names retrieved, I can query the lists for data. The web services use display names to identify lists.

Get SharePoint items with paging via web service

XDocument response = GetListItems(postsConfig);
	XElement root = response.Root;
	foreach (XElement row in root.Descendants(XName.Get("row", _z.ToString())))
		// parse data here
	XElement node = root.Descendants(XName.Get("data", _rs.ToString())).First();
	XAttribute nextNode = node.Attribute("ListItemCollectionPositionNext");
	if (nextNode != null)
		postsConfig.ListItemCollectionPosition = nextNode.Value;
		if (!string.IsNullOrEmpty(postsConfig.ListItemCollectionPosition))
			postsConfig.PageSize = node.Attribute("ItemCount").Value;
			response = GetListItems(postsConfig);
		postsConfig.PageSize = null;
		postsConfig.ListItemCollectionPosition = null;
} while (!string.IsNullOrEmpty(postsConfig.PageSize));

The method to actually query the web service for listitems. Properties of the class SharePointListConfig for the list title, ListItemCollectionPosition and Pagesize are simple string properties. The fields are specified, to get only the data we need for the migration.

private XDocument GetListItems(SharePointListConfig config)
	var xmlDoc = new XmlDocument();

	XmlNode ndQuery = xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
	XmlNode ndViewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
	XmlNode ndQueryOptions = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");

	if (!string.IsNullOrEmpty(config.ListItemCollectionPosition))
		ndQueryOptions.InnerXml = string.Format("<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns><DateInUtc>TRUE</DateInUtc><Paging ListItemCollectionPositionNext=\"{0}\" />",
			config.ListItemCollectionPosition.Replace("&", "&amp;"));
		ndQueryOptions.InnerXml = "<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns><DateInUtc>TRUE</DateInUtc>";

	// get all comments and posts
	if (config.ListItemType == SharePointListConfig.ListType.Posts)
		// PostCatgory for SP Blog, BlogTitleForUrl and Categories for EBE Blogs
		ndViewFields.InnerXml = "<FieldRef Name='ID' /><FieldRef Name='Title'/><FieldRef Name='Body'/><FieldRef Name='PublishedDate'/><FieldRef Name='BlogTitleForUrl'/><FieldRef Name='Categories'/><FieldRef Name='PostCategory'/><FieldRef Name='Author'/>";
		ndViewFields.InnerXml = "<FieldRef Name='ID' /><FieldRef Name='Title'/><FieldRef Name='Body'/><FieldRef Name='PostTitle'/><FieldRef Name='CommentUrl'/><FieldRef Name='EmailAddress'/><FieldRef Name='Author'/><FieldRef Name='Created'/>";
		XmlNode ndListItems = _lists.GetListItems(config.GetListName(), null, ndQuery, ndViewFields, null, ndQueryOptions, null);
		XDocument response = XDocument.Parse(ndListItems.OuterXml);
		return response;
	catch (System.Web.Services.Protocols.SoapException ex)
		throw new Exception(ex.Message + Environment.NewLine + ex.Detail.InnerText, ex);

After all data has been read, local resources parsed and links replaced we move on to the destination side.

WordPress specific details

As stated above, I’ve use an existing library. There are plenty of samples out there, if you look for them. I’ve implemented the following methods.

public interface IWordpressXmlRpc
	WordpressFile newImage(string blogid, string username, string password, WordPressFile theImage, bool overwrite);

	MediaItem[] getMediaLibrary(string blogid, string username, string password, MediaFilter filter);

	bool deletePage(string blogid, string username, string password, int page_id);

	ExistingPostContent[] getRecentPosts(string blogID, string username, string password, int numberOfPosts);

	string newPost(string blogid, string username, string password, NewPostContent content, bool publish);

	bool editPost(string blogid, string username, string password, NewPostContent content, bool publish);

	bool deletePost(string blogid, string username, string password, int postid);

	int newComment(string blogid, string username, string password, int post_id, Comment comment);

	Comment[] getComments(string blogid, string username, string password, CommentFilter filter);

	bool editComment(string blogid, string username, string password, int comment_id, Comment comment);

	bool deleteComment(string blogid, string username, string password, int comment_id);

	string newTerm(string blogid, string username, string password, TaxonomyContent content);

	Term[] getTerms(string blogid, string username, string password, string taxonomy, TermFilter filter);

	bool deleteTerm(string blogid, string username, string password, string taxonomy, int term_id);

I would like to tell you some issues I had, so you don’t get the same problems I had programming with the WordPress XML RPC interface.

Post deletion

Just call the wp.deletePost method? Almost. You’ll have to call it twice to first move it to the recycle bin and then again to have posts being deleted permanently.

Media deletion

There is no method to delete items from the media gallery 🙁 Fortunately items within the gallery behave like pages. So if you implement an call the deprecated wp.deletePage interface, you can achieve what you want (remember to delete twice).

Categories and Tags

Both can be managed with the interface for terms the string for the parameter “taxonomy” will decide what to do. It can be “category” or “post_tag”.

Other than that, the WordPress API is pretty straight-forward and easy to use.


The download contains an executable, which is the tool itself, and a folder with the complete sourcecode.

Migrate SharePoint To WordPress

ChangePassword Webpart – new version available

The ChangePassword WebPart on CodePlex has been downloaded over 20.000 times. The new version has a couple of new features:

  • Easy Installation
  • SharePoint 2010 and 2013 (Foundation and Server)
  • Password strength indicator
  • Plugin support to extend functionality by custom code1
  • Warning if an unsecured connection is used
  • Copyright hint can be removed1
  • Auditing of password changes (and attempts)
  • Logging into the SharePoint logs

This is how it might look on your SharePoint:
ITaCS Password Changer
Documentation and downloads are available here.

TFS Migration from On-Premise to Visual Studio Online

Having a server at home that hosts a TFS is nice. But really necessary? Not really. So I decided to move all my sources to Visual Studio Online.

Visual Studio Online Basic is free for the first 5 users. That’s enough for me.

The migration process is straight forward easy with a tool that is installed on my computer. The process is described here. Another post can be found here.


During the pre migration steps a user mapping is performed, connections verified and a few other things. The process itself takes some time. I have 32MB in 4680 files and it took about half an hour. Another service on my server that isn’t needed anymore 🙂

Conclusion: Migration from On-Premise TFS (in my case 2012) to Visual Studio Online is very easy.