Office 365, unable to sync email. Error 86000C27

I received this error on a mobile phone after a remote wipe.
When setting up the account on the phone again, I got this message saying that the phone was not compliant to the security policy.
The only policy that applied to this phone was set from Microsoft intune and we double checked that the phone was compliant to this.

policy

Searching the internet with the error code I found this article from Microsoft that lists the Exchange mailbox policy’s.
Another strange thing we found was that this happened only with the specific user on this phone. We were able to configure the users account on another phone without any problems.

When we used another account, the phone was syncing the email perfectly.
So after a remote wipe, you cannot use the same account on the device anymore hmmm.

After a long search we found that there are also policy’s defined per user that are restricted to the specific device.

intune-policy

The best way here is to delete the entry, when adding the account to the phone again this entry is automatically created again.

If you click on this entry you’ll see that this policy is restricting the phone itself by the ID and the IMEI number.
So that is why the it is no problem to use another phone with the users account.

mobile details

Setting an BDC external list field with PowerShell and retrieving the bcdid

In a migration scenario I needed to have the value of an external bdc field (from SQL server) set from a text field.
Since the migration software failed at this point I started using PowerShell to do this.
It’s not very difficult to set a field in a normal list but when working with external lists you first need to get the Service Context by using ‘Get-SPServiceContext’


$ctx = Get-SPServiceContext http://domainx.nl
$scope = new-object Microsoft.SharePoint.SPServiceContextScope $ctx

While working on the script I think I ran into the same problem the migration software did.
Even when the Service Context is set you can set the external field simply by setting $listitem[“Contract Party B”]

If the field is set this way then you can see the update in the list, but when editing the item this value is not retrieved and shows up empty.
This is because each external field has a second field _ID
The field needs to contain the bdcid, which is the encoded value used in the profile page of your external content type.

So if you look at the URL of your external content type http://domainx.nl:80/Businessprofiles/_bdc/http___domainx.nl/product.aspx?ProductNr={0} you need to set this field to the product number field.
To encode this field you need to use I used a console application because I could not find a way to call EntityInstanceIdEncoder.EncodeEntityInstanceId(new object[] { “ ” }) in PowerShell.

The console application:


using System;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.Office.Server.ApplicationRegistry.Administration;
using Microsoft.SharePoint.BusinessData.Infrastructure;

namespace Microsoft.SDK.SharePoint.Samples.Bdc.ExternalList
{
    class Program
    {
        static void Main(string[] args)
        {
            var input = args[0];
            var encoded = EntityInstanceIdEncoder.EncodeEntityInstanceId(new object[] { input });

            Console.WriteLine(encoded);
        }
    }
}

If the input is 809159460 then the returned encoded value is __bk4200830003009300130053009300430063000300
The PowerShell script that calls the console application:


Add-PsSnapin Microsoft.SharePoint.PowerShell

#variables
$site = "http://domainx"
$exList = "ExternalDocuments"

#set service context
$ctx = Get-SPServiceContext http://domainx.nl
$scope = new-object Microsoft.SharePoint.SPServiceContextScope $ctx
$web = get-spweb $site
$elist = $web.Lists[$exList]

#iterating thru external list items
foreach ($elistitem in $elist.Items)
    {
              #calling console application to generate the encoded profile id.
              $code = & D:\Temp\GetBcdEntityId.exe $row.productnr
              $elistitem["ExProductField"] = $elistitem["MigratedTextField"]
              $elistitem["ExProductField_ID"] = $code
              $elistitem.Update()

              write-host "Updated ExProductField with: " $elistitem["MigratedTextField "] "and profile ID: " $code
    }

.

Subscribe to MailChimp from SharePoint

The reason for this blog is that I needed to implement a subscription for MailChimp onto a SharePoint 2010 website.

You can’t use the signup embed code from MailChimp because in .NET you can’t use form tags.

Unfortunately there are no add-ons available for SharePoint, so I decided to look at the API that is available from MailChimp.

The best way to do so is using a wrapper for the language of your choice, in the API documentation there are several options mentioned for .NET

I used the PerceptiveMCAPI wrapper because it was the most descriptive.

The code itself is not very special and is mostly coming from the manual.

Then why are you writing this blog you might think. Well first all the information I used was found all over the internet so it saves you the search, second when integrating the whole thing into SharePoint I ran into a few problems.

A great help was the blog from Matt J Roden for the wrapper and the one from Ian Picknell that helped me with the signing process of the wrapper, because in when deploying to SharePoint you need strong named assembly’s and the PerceptiveMCAPI is not by default.

There is one thing to mention when using the guidance of Ian, SharePoint 2010 uses .NET 3.5 and on my machine I had also 4 installed. Which means that if you use the tool ilasm directly from the startmenu, you’re going to run into the following error when deploying:

Error occurred in deployment step ‘Add Solution’: Could not load file or assembly ‘C:/Windows/Temp/solution-c4d0571a-f4d5-44d1-b6a9-58dee513aa1a/PerceptiveMCAPI.dll’ or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.

To fix this you need to use the .NET 2 version of the ilasm tool which in my case was found here: C:WindowsMicrosoft.NETFramework64v2.0.50727

To make it very simple for you and to save you some work, I attached the dll’s. I also attached the .NET 4 version for those who want to use it in SharePoint 2013.

Download file

Next a description of the steps to setup the project in Visual Studio 2010.

The experienced developers can stop reading here, but for those who are not … read on.

Create an empty SharePoint project and choose to deploy it as a farm solution.

Then add a User Control to your page. (I choose a User Control because I could not use a webpart in the spot where I wanted to use it).

If all goes well you’ll end up with a structure like below.

Next add a reference to the PerceptiveMCAPI.

Contents of the files:

Ascx:

<code>

<asp:TextBox ID=”Email” runat=”server” onclick=”this.value=”;”>Type hier je e-mail adres</asp:TextBox>

<asp:Button ID=”Subscribe” runat=”server” Text=”Verzenden” type=”button”

onclick=”Subscribe_Click” CssClass=”nb-button” />

<div id=”social” runat=”server”></div>

</code>

Ascx.cs:

<code>

using System;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using PerceptiveMCAPI;

using PerceptiveMCAPI.Types;

using PerceptiveMCAPI.Methods;

namespace MailChimp.ControlTemplates.MailChimp

{

public partial class SubscribeMaillist : UserControl

{

protected void Page_Load(object sender, EventArgs e)

{

}

protected void Subscribe_Click(object sender, EventArgs e)

{

listSubscribe cmd = new listSubscribe();

listSubscribeParms newlistSubscribeParms = new listSubscribeParms

{

apikey = “Enter your MailChimp API key here”,

id = “Here comes your list id”,

email_address = Email.Text,

double_optin = false,

email_type = EnumValues.emailType.html,

replace_interests = true,

send_welcome = true,

update_existing = true

};

listSubscribeInput newlistSubscribeInput = new listSubscribeInput(newlistSubscribeParms);

var subscribeSuccess = cmd.Execute(newlistSubscribeInput);

if (subscribeSuccess.api_ErrorMessages.Count > 0)

{

social.InnerHtml = “<span>” + subscribeSuccess.api_Request + subscribeSuccess.api_Response +

subscribeSuccess.api_ErrorMessages + subscribeSuccess.api_ValidatorMessages + “</span>”;

}

else

{

social.InnerHtml = “<span>Inschrijving voltooid<br>u ontvangt een bevestiging per e-mail.</span>”;

Email.Text = “Type hier je e-mail adres”;

}

}

}

}

</code>

To make sure that the dll’s are also deployed you need to open the package in Visual Studio, go to the advanced tab and add the dll’s.

All there is left is to modify the web.config

You can find this also in the manual of the PerceptiveMCAPI.

In the configSections

<section name=”MailChimpAPIconfig” type=”PerceptiveMCAPI.MCAPISettings, PerceptiveMCAPI” />

And somewhere else (I’d put mine behind </system.webserver>)

<MailChimpAPIconfig>

<MCAPI SecureAccess=”False” Validate=”False” DataCenter=”auto” apikey=”your API key” />

</MailChimpAPIconfig>

And you need to modify the trust of your webapplication to Full trust (Yeah I know, but in my case this was already a fact so I did not look into CAS policy’s)

<trust level=”Full” originUrl=”” />

If you can’t modify the trust level then here’s a good explanation about them by Tyler Holmes

And then after deployment all you need to do is edit your pagelayout or masterpage to use the User Control.

On top of the page:

<%@ Register TagPrefix=”portiva” src=”~/_controltemplates/MailChimp/SubscribeMaillist.ascx” TagName=”MailChimp” %>

And where you want the control to appear:

<portiva:MailChimp id=”nieuwsbrief” runat=”server”/>

And then there it is:

Error encrypting or decrypting credentials

I ran into this error description when running the configuration wizard and according to the search engines I’m not the first one.

However I couldn’t find the solution in what was already written about this so I decided to write this blog.

How it started:
The portal I was working on had a failing application server which was no longer able to boot again. So we decided to install a new one and after installing the server we had to join it to the farm again. That’s where we ran into the problem that eventually generated the error message.

When you want to join a server to an existing farm you need the passphrase, well in this case nobody knew the passphrase anymore thinking you only need this when installing the farm right? And if there really is a problem you can change it on the fly, so what’s the problem?

Well read on.

We started changing the passphrase using powershell.

$passphrase = ConvertTo-SecureString -asPlainText –Force
Set-SPPassPhrase -PassPhrase $passphrase –Confirm

Ok, no errors. That should work right?

The next step was to run the configuration wizard again and, yes run into the error.
From the event viewer:

Source: SharePoint 2010 Products Configuration Wizard
EventID: 104

Failed to connect to the configuration database.
An exception of type System.InvalidOperationException was thrown.  Additional exception information: There was an error encrypting or decrypting credentials. Either a credential update is currently being performed, or you must update the farm account credentials on this server before you can perform this task.

The psconfig logs shows about the same error.

INF          Openning configdb so that I can join it at server sql01 database SharePoint_Config in farm mode
INF          Now joining to farm at server sql01 database SharePoint_Config
ERR         Task configdb has failed with an unknown exception
ERR         Exception: System.InvalidOperationException: There was an error encrypting or decrypting credentials. Either a credential update is currently being performed, or you must update the farm account credentials on this server before you can perform this task.

When searching for the most obvious “Cannot connect to the configuration database” you end up with checking the common things described here: http://social.technet.microsoft.com/wiki/contents/articles/6545.sharepoint-2010-cannot-connect-to-the-configuration-database-en-us.aspx

After a lot of searching I came to the conclusion that something must have gone wrong when changing the passphrase, although we did not get an error when doing so.
So I tried to change it again using the same commands as before.

$passphrase = ConvertTo-SecureString -asPlainText –Force
Set-SPPassPhrase -PassPhrase $passphrase –Confirm

Interesting, so the job was scheduled and not executed immediately.

And this is of course exactly the problem I ran into, because Central Administration is running on the application server and that is the server that crashed and we were trying to replace.

Which means that the job is never executed.

Next I tried to install Central Admin to the WFE server and ran into the exact same error.
Apparently you can’t do anything when this job is scheduled.
Because we can’t do anything using the config wizard we need to remove this job.

First let’s look if we can find this job.

Get-SPTimerJob -Identity job-admin-passphrase-change | Format-Table -Property DisplayName,Id,LastRunTime,Status

Let’s remove some information because to delete it we need the full GUID.

Get-SPTimerJob -Identity job-admin-passphrase-change | Format-Table -Property DisplayName,Id

Set job to a variable

$job = Get-SPTimerJob -id <GUID>

And delete it.

$job.Delete()

Now with the job no longer in the way we installed Central Admin to the WFE server successfully and changed the passphrase again.

This time the job was executed nicely because Central Admin was running.

Joining the new application server to the farm was running smoothly this time.

Duet Enterprise – Embed extended business properties in your workflow. Part 2

Like I said in Part 1 of this blog we will now modify the InfoPath form.
By default the form looks something like this:
clip_image002

As I already said the details section will not display the business data, so I removed that section.
To do this you need to open SharePoint Designer and edit the WrkTaskIP.aspx file in SitePages.

Find the tag Workflow:TaskDetailsWP and comment it until the closing tag Workflow:TaskDetailsWP

Save and you will get the warning that the page is no longer based on the site definition, well that was the intention. Choose yes.

Next we will edit the InfoPath form to display the business data.
You’ll find the InfoPath form in the workflow you created, browse there with SPD.

clip_image003

Right click and choose edit in advanced mode.

InfoPath will now open so you can edit the form.
For everyone who has experience with InfoPath the next will not show you any new stuff except for maybe the properties to use.

Click the tab data and choose Data Connections.
Add and create a new connection to receive data.
Choose SharePoint list and enter the URL to the workflow site.
Select the Workflow Business Data Document Library and the field you need (be sure to select the title field, we need it to select the correct xml data).

Next we will define a field to display the data.

Insert a new textbox.
Create a field to store the data in the form. Click on the arrow next to myFields and select Add.

clip_image005

Enter a name and choose OK.

Right click the textbox and select properties.
Click on the FX button.

Insert the field you need from the Business library data connection (in this example remaining leave) and filter the data.
Select title from the same connection which contains @Description from the main datasource.

clip_image007

Enter OK a few times and after you did the same for all the other fields that you want in your form you can re-publish the form to SharePoint. Choose File from the menu and then quick publish.

The end result can then look like this, depending on what item you leave in the form:

clip_image009

There is probably also a way to get the extended business data in the details webpart, but I did not find the options yet, if someone does then let me know.

If you want some more information on Duet Enterprise, my collegue Maarten Eekels gave a presentation at the SharePoint Connections 2011 in Amsterdam. You can download this presentation here.

Duet Enterprise – Embed extended business properties in your workflow. Part 1

When working with SAP workflow in SharePoint 2010, you’ll probably want to see the corresponding business data of the SAP workflow in your dialog forms.
In the first part of this blog I will show you were the data is stored.

It took me a while to find this data and I finally found this blog: http://sharepoint.microsoft.com/blog/Pages/BlogPost.aspx?pID=965 by Kiki Shuxteau where he mentions the SharePoint business data document library where the XML payload should be dropped.

This document library is created with the workflow site and you will find the business data there.

clip_image001

If you did not define any business data when setting up the site then the xml in this document library will be pretty empty.
clip_image002

So before there is any data, you will have to enter the extended business properties when creating the workflow site.
You’ll have to ask your SAP administrator what properties the workflow sends to SharePoint.
In the SAP Workflow Configuration section in the site settings of your tasks center you can configure a new SAP workflow task type.
Then in the section for the extended business properties you need to enter the properties separated by commas.
clip_image004

If you configured these properties and you use the Diagnose configuration problems option in the same section, you can see the defined properties:

clip_image006

If we now have a look at the library, we can see that the business data is included in the XML.
clip_image007

The data in de xml is also set as metadata in the same library, so this we can use this data in the workflow form.

You would expect that this business data is automatically displayed in the detailed section of your workflow … well assumption is ….. you may fill out the rest yourself. J

In Part 2, I will show you how to modify the InfoPath form to include this data..

Move SharePoint files to folders

Recently I ran into a WSS environment containing over 2 million documents.
The problem here was that the crawler was not able to index all these documents.
In the crawl logs there were a lot of out-of-memory errors, while the server had 8Gb of internal memory which should be enough.
Searching for the source of this problem was that there were 10 sites with only 1 document library and with over 2 million documents …..

I decided to move the documents to folders to avoid the out-of-memory problems of the crawler.

To do this I used powershell.

Initially I started with the script from Chris Rumel fond here.
Since I could not get this working I stripped the script leaving the basics.

$WebURL = "http://siteURL";             
$ListDisplayName = "Documents";             
$ArchiveFolderName = "001";             

function LoadWSSAssembly             
{             
write-host "Loading WSS Assembly..."               
[System.Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")              
write-host "Done..."               
}             

function moveItems()            
{             
    trap             
    {             
        #make sure we dispose of these in the event of an error to avoid memory leaks:             
        write-host "Error - disposing of objects...";             
        $Web.Dispose();             
        $Site.Dispose();             
    }             

    [Microsoft.SharePoint.SPSite] $Site = New-Object Microsoft.SharePoint.SPSite($WebURL);             
    [Microsoft.SharePoint.SPWeb] $Web = $Site.OpenWeb();             
    [Microsoft.SharePoint.SPList] $List = $Web.Lists[$ListDisplayName];              

    $FolderToMoveTo = $List.RootFolder.Url + "/" + $ArchiveFolderName;            

    $ItemMoveCount=0;             

     $Query = New-Object Microsoft.SharePoint.SPQuery;             
     $Query.Folder = $list.RootFolder;             
     $Query.RowLimit = 2200; #limit query because of large foldr            
     $List.GetItems($Query)  |              
     Where {$_.ContentType.Name -ne "Folder"}  |              
    foreach-object {              
        if ($ItemMoveCount -le "1999") {            
        #Line below will simply output to console and demonstrates another .NET call             
        [System.String]::format("Moving Item {0} with ID {1}...",$_.Name, $_.ID.ToString());             
        $Web.GetFile($_.Url).MoveTo([System.String]::format("{0}/{1}",$FolderToMoveTo,$_.Name)); #$FolderToMoveTo.Url            
       # $_.SystemUpdate($false);             
        write-host "Success...";             
        $ItemMoveCount++;             
        }            
    };             

    write-host "==============================================================================";             
    write-host "Complete! -> Moved " $ItemMoveCount " Items to directory " $ArchiveFolderName;             
    write-host "==============================================================================";             

    #dispose:             
    $Web.Dispose();             
    $Site.Dispose();             

}             

function go             
{             
loadWSSAssembly;             
moveItems;             
}             

go;

The next problem was creating the folders, the original script had some functions to do this but again it didn’t work correctly in my situation.
Again I used parts of it to create a script that created the folders.

$WebURL = "http://webURL";             
$ListDisplayName = "Documents";             
$foldernr = 001;            

function LoadWSSAssembly             
{             
write-host "Loading WSS Assembly..."               
[System.Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")              
write-host "Done..."               
}             

function createFolder             
{             
While ($foldernr -le 200)             
         {            
            [Microsoft.SharePoint.SPSite] $Site = New-Object Microsoft.SharePoint.SPSite($WebURL);             
            [Microsoft.SharePoint.SPWeb] $Web = $Site.OpenWeb();             
            [Microsoft.SharePoint.SPList] $List = $Web.Lists[$ListDisplayName];              

            $FolderName = "{0:D3}" -f $foldernr; #number should always contain 3 digits            

            $folderItem = $list.Items.Add($Folder.ServerRelativeUrl, [Microsoft.SharePoint.SPFileSystemObjectType]::Folder,$folderName);             
            $folderItem.SystemUpdate();             
            $list.Update();             

         #increase foldernr.            
         $foldernr++;            
         }            
}             

function go             
{             
LoadWSSAssembly            
createFolder;             
}             

go;

This script creates the number of folder that you want starting with the number in the variable $foldernr until the number reached in the while loop.
Next I didn’t want to change the values in the script after every 2000 items I added the variable $ArchiveFolderName to the function and increased the variable after every 2000 items so it could be used in a loop.

function moveItems([string]$ArchiveFolderName)            
 {              

    $int = [int]$ArchiveFolderName;            
    $int++;            
    $int = "{0:D3}" -f $int;            
    $ArchiveFolderName = $int.ToString();            

    if ($ArchiveFolderName -le "050")            
    {            
    moveItems $ArchiveFolderName;            
    }            
 }            

function go             
{             
loadWSSAssembly;             
moveItems "001";             
}

This worked fine until it had done about 10.000 documents, then powershell ran out of memory.
To fix this I added the following to the script, perhaps not the best way but it worked.

#garbage collection            
    [GC]::Collect()

Now the script wil run endlessly until the values in the script are reached.

Finally I this related in 2 separate scripts.
The first script creates the directories and the second script moves the actual documents.
Complete script to create directories

$WebURL = "http://webURL";             
$ListDisplayName = "Documents";             
$foldernr = 001;            

function LoadWSSAssembly             
{             
write-host "Loading WSS Assembly..."               
[System.Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")              
write-host "Done..."               
}             

function createFolder             
{             
While ($foldernr -le 200)             
         {            
            [Microsoft.SharePoint.SPSite] $Site = New-Object Microsoft.SharePoint.SPSite($WebURL);             
            [Microsoft.SharePoint.SPWeb] $Web = $Site.OpenWeb();             
            [Microsoft.SharePoint.SPList] $List = $Web.Lists[$ListDisplayName];              

            $FolderName = "{0:D3}" -f $foldernr; #number should always contain 3 digits            

            $folderItem = $list.Items.Add($Folder.ServerRelativeUrl, [Microsoft.SharePoint.SPFileSystemObjectType]::Folder,$folderName);             
            $folderItem.SystemUpdate();             
            $list.Update();             

         #increase foldernr.            
         $foldernr++;            
         }            
}             

function go             
{             
LoadWSSAssembly            
createFolder;             
}             

go;

Complete script to move the files.

$WebURL = "http://webUrl";             
$ListDisplayName = "test";             

function LoadWSSAssembly             
{             
write-host "Loading WSS Assembly..."               
[System.Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")              
write-host "Done..."               
}             

function moveItems([string]$ArchiveFolderName)            
{             
    trap             
    {             
        #make sure we dispose of these in the event of an error to avoid memory leaks:             
        write-host "Error - disposing of objects...";             
        $Web.Dispose();             
        $Site.Dispose();             
    }             

    [Microsoft.SharePoint.SPSite] $Site = New-Object Microsoft.SharePoint.SPSite($WebURL);             
    [Microsoft.SharePoint.SPWeb] $Web = $Site.OpenWeb();             
    [Microsoft.SharePoint.SPList] $List = $Web.Lists[$ListDisplayName];            

    $FolderToMoveTo = $List.RootFolder.Url + "/" + $ArchiveFolderName;            

    $ItemMoveCount=0;             

     $Query = New-Object Microsoft.SharePoint.SPQuery;             
     $Query.Folder = $list.RootFolder;             
     $Query.RowLimit = 2200; #limit query because of large foldr            
     $List.GetItems($Query)  |              
     Where {$_.ContentType.Name -ne "Folder"}  |              
    foreach-object {              
        if ($ItemMoveCount -le "2") {            
        #Line below will simply output to console and demonstrates another .NET call             
        [System.String]::format("Moving Item {0} with ID {1}...",$_.Name, $_.ID.ToString());             
        $Web.GetFile($_.Url).MoveTo([System.String]::format("{0}/{1}",$FolderToMoveTo,$_.Name));            
        write-host "Success...";             
        $ItemMoveCount++;             
        }            
    };             

    write-host "==============================================================================";             
    write-host "Complete! -> Moved " $ItemMoveCount " Items to directory " $ArchiveFolderName;             
    write-host "==============================================================================";             

    #dispose:             
    $Web.Dispose();             
    $Site.Dispose();             

    #garbage collection            
    [GC]::Collect()             

    $int = [int]$ArchiveFolderName;            
    $int++;            
    $int = "{0:D3}" -f $int;            
    $ArchiveFolderName = $int.ToString();            

    if ($ArchiveFolderName -le "050")            
    {            
    moveItems $ArchiveFolderName;            
    }            

}             

function go             
{             
loadWSSAssembly;             
moveItems "001";             
}             

go;