Azure AD Integration

This year I’ve been working a lot more with Azure. On of my tasks has been to integrate other application to each other using Azure AD. Here are some of my finding and good to know things in case someone else runs into them:

  • Create a new MVC Application in Visual Studio
  • When this is done, press the second mouse button on the project and go to “Add” > “Connected Services”. This will allow you to create an O365 connection.
  • Select Office 365 API Services.
  • In the new Window select or type in your domain.
  • Next, create new Azure AD application configuration or use an existing one by providing the GUID for the application.
    • Make sure you select the “Configure Single Sign-On using Azure AD” option
    • Make sure that your application is multi-tenant:
      • This works so that you register your app with you own Azure AD domain, then after that external Azure AD tenants and their users are registered through an “onboarding” process. The process will the user or admin user for privileges to use certain information from the AD or other resources. These are defined in the Azure AD application settings.
      • Notice you are using an application ID and key to connect to your own organization Azure AD then the users are only onboarding using the multi-tenant option in the Azure AD application configuration.
    • Next select what kind of privileges your application needs from the Azure AD and O365.
    • You need onboarding functionality from here: https://azure.microsoft.com/en-us/documentation/samples/active-directory-dotnet-webapp-multitenant-openidconnect/
    • In Global.asax.cs application_start function add the following: AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
      • If this is missing, then you claim will not work properly.
    • If you are using a SQL Server database and Entity Framework remember to update you model from the database and remember primary key connections. If the Entity Framework update does not work then removing and adding the database tables should force an update. Also remember to clean and build your project if nothing else helps.
    • If you get this error: Error: {“error”:”invalid_grant”,”error_description”:”AADSTS70002: Error validating credentials. AADSTS70000: The provided access grant is invalid or malformed…..
    • Doing a redirect the proper way in an MVC apllication using the following piece of code in your contoller: return Redirect(returnUrl);
      • If you use the normal way in ASP .NET: Response.Redirect(returnUrl); you will run into trouble. The error message might look something like this:
        • Server Cannot Append Header After HTTP headers have been sent Exception at @Html.AntiForgery
        • You could set the AntiForgeryConfig.SuppressXFrameOptionsHeader = true; in the Application_start, but this will lower your security and not advisable.

 

Upgrading/Migrating from an older SharePoint version to a newer SharePoint

This is my checklist for when I am upgrading content from an older SharePoint to a newer one. Like from SharePoint 2010 to SharePoint 2013.

  • Make sure that you disable the outgoing Email address from the Central Administration in the web applications own settings. This is if you have events or other functionality that is to send emails based on some logic. You do not want to send emails confusing end users about emails which should not be send.
  • Install you needed packages for the migration process. This is important. If you do not do this the content database upgrade will have multiple errors and you might not be able to retrieve them.
    1. Notice another important reason why this is important is that lists and libraries are feature dependent. If there is a missing feature your lists or libraries will show empty views or will not function. Even if there is an access point through a URL, SharePoint will not be able to show you the content.
  • Next take a database backup in SQL Server from your old environment. You do this by: Pressing the secondary mouse button on a database > Tasks > Back Up… . Make sure that you check the checkbox named “Copy-only backup”. This is important, if you do not do this this will cause problems for the current database being used by the old SharePoint farm.
  • Next start the process of upgrading the content. More details here: https://technet.microsoft.com/en-us/library/cc303436.aspx
    • For a SharePoint 2010 upgrade, you might need to create a classic authentication application. More details here: https://technet.microsoft.com/en-us/library/gg251985.aspx
    • Sample command: New-SPWebApplication -name “ClassicAuthApp2” -Port 100 -ApplicationPool “ClassicAuthAppPool” -ApplicationPoolAccount (Get-SPManagedAccount “<domainname>\<user>”)
    • Before you perform the actual upgrade test the database with the following command: Test-SPContentDatabase -Name DatabaseName -WebApplication URL > TestLog.txt
      1. This will output a log file in the same folder where you are in the SharePoint management shell. Look at the log file and fix the errors found. It may not be necessary to fix them all if the errors do not affect the content you need.
      2. Notice: The WebApplication URL is the same as the classic application URL created earlier if you created it.
    • The next step is to mount the database. This is the actual upgrade process.
      1. Sample Command: Mount-SPContentDatabase -Name DatabaseName -DatabaseServer ServerName -WebApplication URL
        1. Notice: If your SharePoint farm is using SQL Aliases then open the following program and see your SQL Server database name: C:\Windows\System32\cliconfg.exe
        2. Notice: The WebApplication URL is the same as the classic application URL created earlier if you created it.
      2. If you created the classic authentication application then the next step is to convert it to a claims application.
        1. Sample command: Convert-SPWebApplication -Identity <yourWebAppUrl> -To Claims -RetainPermissions [ -Force]
      3. Moving the needed content from one content database to the other. More details here: https://technet.microsoft.com/en-us/library/cc825328.aspx
        1. Create new a content database (or multiple ones if needed) and use the Move-SPSite command to move them from one location to the other. Notice: The new content database(s) must be in the same application for the command to work.
        2. Sample command: Move-SPSite <http://ServerName/Sites/SiteName> -DestinationDatabase <DestinationContentDb>
        3. When ready with the move operation of content, then detach your new content database(s) and attach it to the new location.
  • Check that if you have XSLT based list or library field customizations that they work. If not consider using JSLink functionality in webparts of by defining it in a field through a powershell script like the one below. There is also a sample how to do it in the JavaScript file
  • Check that you calculated columns are working in your new environment.
  • If you are having problems with you quick edit functionality try this script:
    1. https://lionadi.wordpress.com/2016/06/02/fix-quick-edit-for-sharepoint-lists-after-migration-from-sharepoint-2010-to-sharepoint-2013/
  • If you have different threshold definitions in the old environment check that your old content and functionality behaves correctly in the new environment.
  • Next step upgrade your SharePoint sites look. This is offered automatically by the new version of SharePoint but if not then:
    1. /_layouts/siteupgrade.aspx ja /_layouts/siteupgradestatus.aspx
  • Next configure your search:
    1. Make sure that your new content is in one of your content sources.
    2. Run a full crawl.
  • Feature installation problems:
    1. “Check that the feature has been installed. For example, if you are performing Update-SPSolution and a new feature has been added between solution deployments then the feature is not installed by default.
    2. To check do the following:-
    3. Run SharePoint 2010 Management Shell from one of the SharePoint servers Type Install-SPFeature -ScanForFeatures
      1. This will show you any features that are available in the SharePoint Root but have not been installed. You can install any missing features using the command :-
    4. Install-SPFeature -AllExistingFeatures
      1. See the following TechNet Article for more information:
        1. http://technet.microsoft.com/en-us/library/ff607825(v=office.14).aspx
    5. Get-SPFeature| Sort -Property Scope,DisplayName | FT -GroupBy Scope DisplayName,ID
  1. If you have problems with some of your views in a list or library while others views work, then a work around is to create the view using the problem view as the base view.
</pre>
param (

[string]$SPSiteFilter = "app url"

)

&nbsp;

if ((Get-PSSnapin 'Microsoft.SharePoint.PowerShell' -ErrorAction SilentlyContinue) -eq $null){Add-PSSnapin 'Microsoft.SharePoint.PowerShell'}

&nbsp;

&nbsp;

&nbsp;

$spWebApp = Get-SPWebApplication $SPSiteFilter

foreach($site in $spWebApp.Sites)

{

$ddField = $site.rootweb.Fields["field name"]

Write-Host $site.Url

if($ddField -ne $null)

{

&nbsp;

$ddField.JSLink = "~sitecollection/Style Library/JSLinkFix.js"

$ddField.Update($true)

Write-Host "Updated"

&nbsp;

}

&nbsp;

&nbsp;

&nbsp;

&nbsp;

$site.Dispose();

}

 

 

SharePoint site collection access 404 page not found error

If you encounter some of the errors below and especially when trying to access a page or the front page of a site collection or site then the problem might be related to missing page layout or master page references.

This may be due to the fact that you have migrated content from an older SharePoint version and the content database is referencing an older hive version.

So check that you solution packages are installed using compatibility mode:

install-spsolution -identity solution.wsp -webapplication “site url” -gacdeployment -CompatibilityLevel All

Relying on fallback logic in VghostPageManager::getGhostDocument() for document: ‘C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\Template\SiteTemplates\somesite\default.aspx’

This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.

Fix deleted AD users from SharePoint

This is a small PowerShell script that will fix issues with removed SharePoint users. You may encounter problems if you remove an AD user but the later re-create it with the same AD user login. If such cases this script might help you with possible SharePoint issues. If this does not help then try to remove the user profile and run a full user profile synchronization and run the script again.


$sites = Get-SPSite http://portal.spdev.com

foreach ($site in $sites) {
$groups = $site.RootWeb.sitegroups
foreach ($group in $groups) {
foreach ($user in $group.users) {
# Skip All Authenticated Users, General groups
if ($user.userlogin -eq "c:0(.s|true" -or $user.userlogin -eq "c:0!.s|windows") {
continue;
}
if ($user.IsDomainGroup) {
# Skip Security Groups
}
else {
# Get user login
$splitline = $user.userlogin.split("\");
$samid = $splitline[1];
if ($user.userlogin.contains("AD domain name"))
{
if ($user.userlogin.contains("part of your login name")) {
Write-Host "user Found" $user.userlogin
$group.removeuser($user);
$site.RootWeb.SiteUsers.Remove($user.userlogin);
}
else {
Write-Host $user.userlogin
}
}
}
}
}
}

How to Fix Quick Edit for SharePoint lists after migration from SharePoint 2010 to Sharepoint 2013

Once again with annoying problem in SharePoint. The problem will most likely occur after you have migrated a content database from SP2010 to SP2013. Thanks to the internet the solution is to make sure that list views have in ther JSLink property the following file in them: clienttemplates.js

Thanks to the following site for the tip on how to fix it:

http://www.rickvanrousselt.com/updating/

Here is a sample C# code that will fix the problem. Using powershell I was unable to get a hold of views in lists after the migration.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;

using Microsoft.SharePoint;
namespace SP2013MigrationListFix
{
class Program
{
static void Main(string[] args)
{
using(var site = new SPSite(ConfigurationManager.AppSettings["site"]))
{
for (int siteCount = site.WebApplication.Sites.Count - 1; siteCount >= 0; siteCount--)
{
Console.WriteLine();
Console.WriteLine("----------------------------------------------------------------------");
SPSite innerSite = site.WebApplication.Sites[siteCount];
Console.Write("Site: " + innerSite.RootWeb.Title);
try
{
for (int webCount = innerSite.AllWebs.Count - 1; webCount >= 0; webCount--)
{

SPWeb web = innerSite.AllWebs[webCount];
Console.WriteLine();
Console.WriteLine("Web: " + web.Title);
try
{

for (int listCount = web.Lists.Count - 1; listCount >= 0; listCount--)
{
SPList list = web.Lists[listCount];
Console.WriteLine("Web: " + list.Title);
if (list != null)
{
Console.WriteLine("View count: " + list.Views.Count);
for (int x = list.Views.Count - 1; x >= 0; x--)
{
SPView view = list.Views[x];
Console.WriteLine("View name: " + view.Title);
Console.WriteLine("JSLink before fix: " + view.JSLink);
if (String.IsNullOrWhiteSpace(view.JSLink))
{
view.JSLink = "clienttemplates.js";
view.Update();
Console.WriteLine("JSLink after fix: " + view.JSLink);
}

}
}
else
{
Console.WriteLine("List not found");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + " " + ex.StackTrace);
}
finally
{
if (web != null)
web.Dispose();
}
}
}
finally
{
if (innerSite != null)
innerSite.Dispose();
}
}

}
Console.ReadLine();
}
}
}

SharePoint change document set and items content type to a new content type

I’ll put it simply:

This is a PowerShell script that you can use to change a content type of a library or list to another one. This script can identify between Document Sets and library or list items.


param (
[string]$WebsiteUrl = "http://portal.spdev.com/",
[string]$OldCTName = "DSTestCT",
[string]$NewCTName = "DSTestCT"
)

if ( (Get-PSSnapin -Name MicroSoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null )
{
Add-PsSnapin MicroSoft.SharePoint.PowerShell
}

function Reset-ListContentType ($WebUrl, $ListName, $OldCTName, $NewCTName)
{
$web = $null
try
{
$web = Get-SPWeb $WebUrl

$list = $web.Lists.TryGetList($ListName)
$oldCT = $list.ContentTypes[$OldCTName]

$isChildOfCT = $list.ContentTypes.BestMatch($rootNewCT.ID).IsChildOf($rootNewCT.ID);
if($oldCT -ne $null -and $isChildOfCT -eq $false)
{
$hasOldCT = $true
$isFoldersCTReseted = Reset-SPFolderContentType –web $web -list $list –OldCTName $OldCTName –NewCTName $NewCTName
Reset-SPFileContentType –web $web -list $list –OldCTName $OldCTName –NewCTName $NewCTName
Remove-ListContentType –web $web -list $list –OldCTName $OldCTName –NewCTName $NewCTName
if($hasOldCT -eq $true)
{
Add-ListContentType –web $web -list $list –OldCTName $OldCTName –NewCTName $NewCTName
if($isFoldersCTReseted -eq $true)
{
Set-SPFolderContentType –web $web -list $list –OldCTName $OldCTName –NewCTName $NewCTName
}
}
}


}catch
{

}
finally
{
if($web)
{
$web.Dispose()
}
}

}

function Remove-ListContentType ($web, $list, $OldCTName, $NewCTName)
{


$oldCT = $list.ContentTypes[$OldCTName]

$isChildOfCT = $list.ContentTypes.BestMatch($oldCT.ID).IsChildOf($oldCT.ID);

if($isChildOfCT -eq $true)
{
$list.ContentTypes.Delete($oldCT.ID)
}
$web.Dispose()

return $isChildOfCT
}

function Add-ListContentType ($web, $list, $OldCTName, $NewCTName)
{



$list.ContentTypes.Add($rootNewCT)

$web.Dispose()
}

function Reset-SPFolderContentType ($web, $list, $OldCTName, $NewCTName)
{
#Get web, list and content type objects

$isFoldersCTReseted = $false


$isChildOfCT = $list.ContentTypes.BestMatch($rootNewCT.ID).IsChildOf($rootNewCT.ID);

$oldCT = $list.ContentTypes[$OldCTName]
$folderCT = $list.ContentTypes["Folder"]
$newCT = $rootNewCT

$newCTID = $newCT.ID

#Check if the values specified for the content types actually exist on the list
if (($oldCT -ne $null) -and ($newCT -ne $null))
{
$list.Folders | ForEach-Object {

if ($_.ContentType.ID.IsChildOf($rootNewCT.ID) -eq $false -and $_.ContentType.ID.IsChildOf($oldCT.ID) -eq $true -and $_.Folder.ProgID -eq "Sharepoint.DocumentSet")
{
Write-Host "Found a document set: " $_.Name "Processing document set"
$item = $list.GetItemById($_.ID);
$item["ContentTypeId"] = $folderCT.Id
$item.Update()
$isFoldersCTReseted = $true
}
}
}

$web.Dispose()

return $isFoldersCTReseted
}

function Set-SPFolderContentType ($web, $list, $OldCTName, $NewCTName)
{
#Get web, list and content type objects



$folderCT = $list.ContentTypes["Folder"]
$newCT = $list.ContentTypes[$NewCTName]

#Check if the values specified for the content types actually exist on the list
if (($newCT -ne $null))
{
$list.Folders | ForEach-Object {
if ($_.ContentType.ID.IsChildOf($newCT.ID) -eq $false -and $_.ContentType.ID.IsChildOf($folderCT.ID) -eq $true -and $_.Folder.ProgID -eq "Sharepoint.DocumentSet")
{
$item = $list.GetItemById($_.ID);
$item["ContentTypeId"] = $newCT.Id
$item.Update()
}
}
}

$web.Dispose()
}


function Reset-SPFileContentType ($web, $list, $OldCTName, $NewCTName)
{
#Get web, list and content type objects



$isChildOfCT = $list.ContentTypes.BestMatch($rootNewCT.ID).IsChildOf($rootNewCT.ID);

$oldCT = $list.ContentTypes[$OldCTName]
$folderCT = $list.ContentTypes["Folder"]
$newCT = $rootNewCT

$newCTID = $newCT.ID

#Check if the values specified for the content types actually exist on the list
if (($oldCT -ne $null) -and ($newCT -ne $null))
{
$list.Folders | ForEach-Object {
if ($_.ContentType.ID.IsChildOf($rootNewCT.ID) -eq $false -and $_.ContentType.ID.IsChildOf($oldCT.ID) -eq $true)
{
$_["ContentTypeId"] = $folderCT.Id
$_.Update()
}
}
#Go through each item in the list
$list.Items | ForEach-Object {
Write-Host "Item present CT ID :" $_.ContentType.ID
Write-Host "CT ID To change from :" $oldCT.ID
Write-Host "NEW CT ID to change to:" $rootNewCT.ID

#Check if the item content type currently equals the old content type specified
if ($_.ContentType.ID.IsChildOf($rootNewCT.ID) -eq $false -and $_.ContentType.ID.IsChildOf($oldCT.ID) -eq $true)
{
#Check the check out status of the file
if ($_.File.CheckOutType -eq "None")
{
Change the content type association for the item
$item = $list.GetItemById($_.ID);
$item.File.CheckOut()
write-host "Resetting content type for file: " $_.Name "from: " $oldCT.Name "to: " $newCT.Name

$item["ContentTypeId"] = $newCTID
$item.UpdateOverwriteVersion()
Write-Host "Item changed CT ID :" $item.ContentType.ID
$item.File.CheckIn("Content type changed to " + $newCT.Name, 1)
}
else
{
write-host "File" $_.Name "is checked out to" $_.File.CheckedOutByUser.ToString() "and cannot be modified"
}
}
else
{
write-host "File" $_.Name "is associated with the content type" $_.ContentType.Name "and shall not be modified"
}
}
}
else
{
write-host "One of the content types specified has not been attached to the list"$list.Title
return
}

$web.Dispose()
}

$web = Get-SPWeb $WebsiteUrl
$rootWeb = $web.Site.RootWeb;
$rootNewCT = $rootWeb.AvailableContentTypes[$NewCTName]

Foreach ($list in $web.Lists) {
Write-Host $list.BaseType
if($list.Hidden -eq $false -and $list.BaseType -eq "DocumentLibrary")
{
Write-Host "Processing list: " $list.Title
Reset-ListContentType –WebUrl $WebsiteUrl –ListName $list.Title –OldCTName $OldCTName –NewCTName $NewCTName
}
}

$web.Dispose()