demystifying User Profile picture sync in #Office365


User profile pictures is one of the key factor for collaboration with in Office365. User Pictures are surfaced on almost of the service with in Office 365 such as Exchange Online, SharePoint Online, Lync (Skype) Online as well their client applications such as Outlook, Office, Skype for business etc.

To provide seamless experience to the end users its important to understand how it pictures are synchronized internally with in Office 365, Some notable issues and possible ways of automation.

Typical User Profile Sync process:

Most common scenario is of user profile picture sync process is through DirSync. When Dirsync completes the Synchronization to Azure AD, EXO gets a copy from AzureAD then SPO gets a copy from EXO. Though Outlook/Lync online is updated instantly, SPO might take up to 72 hours to show the picture.  EXO uses single image throughout the application. But SPO online uses three different images of single single user profile. For an example SPO ribbon uses a small image where as MySite/Delve uses a larger image.  So the User profile Service takes extra time to scale the images.

SPO Image variations:
200px * 200 px
_layouts/15/userphoto.aspx?size=L&username=firstname.lastname@spbreed.com

72px * 72px
_layouts/15/userphoto.aspx?size=M&username=firstname.lastname@spbreed.com

48px * 48px
_layouts/15/userphoto.aspx?size=S&username=firstname.lastname@spbreed.com

Issues:

Its not always a smooth ride from DirSync to SPO. If the process fails at any of the three stages, user’s may not get a profile pic in SPO. Here are some of the scenarios

  • AD images greater than 10KB or with wrong dimensions
  • Licensed for SPO but not EXO
  • Poor picture resolution in SPO Delve/Mysites

Resolution:

I often faced scenarios where the customers would require their pics across all the services in Office 365 in the next day. In those cases PowerShell is your friend. Below script uses Set-UserPhoto to upload high resolution pictures to EXO and ProfilePictureUploader project from Office365 Developer Patterns and Practices (PNP) to upload the Profile pictures to SharePoint Online.

Features:

Now the only thing you needed is the high resolution images on your local file share in “Firstname Lastname.JPG” format and configure the variables. This script

  • Saves the credentials securely for future use
  • Generates the UPN values from the User profile picture names. (Eg: John Doe.jpg => jdoe@domain.com)
  • Uploads the image to Exchange online
  • Scales the source image small (48px), medium (72px), Large (200 PX) images and uploads to SharePoint online
  • Archive the processed images

How to run this:

Download the Zip file and Configure the below values in configuration.xml

Configuration values:

For details please refer ProfilePictureUploader project

  1. tenantName: eg: spbreed.onmicrosoft.com
  2. pictureSourceCsv: C:\Scripts\UpdateProfilePics\Release\userlist.csv
  3. thumbs upload3Thumbs: True
  4. additionalProfileProperties:
  5. logFile path:“C:\Scripts\UpdateProfilePics\Release\log.txt”
  6. uploadDelay:500
  7. credFile:Location to store the O365 credentials
  8. psLogfile: Location to store PS logs
  9. O365AdminAccount:o365admin@spbreed.com (Global admin)
  10. localPhotosFolder:\\fs.corp.local\Public\Employee Photos\O365\ready
  11. localPhotosArchiveFolder:\\fs.corp.local\Public\Employee Photos\O365\archive
  12. domainName:spbreed
  13. exeLocation:C:\Scripts\UpdateProfilePics\Release (Location of ProfilePictureUploader Binaries)

Troubleshooting tips:

  •  O365AdminAccount should be a Office 365 global administrator
  • SetExecutionPolicy RemoteSigned should be enabled
  • Powershell modules for Azure AD and MSOL Sign in assistant should be installed.

 

Powershell to change UPN/Sign-in names for Office 365 users


Issue:

In many cases after running the DirSync, Office 365 users are created with user@domain.onmicrosoft.com as Primary UPN.

WAAD_1

Anlaysis:

Internally MS maintains two domains for federated users. One is “user@domain.com” which is the replica of on premise AD and other with “user@domain.onmicrosoft.com” on Azure AD.

It seems if the Dirsync is ran without “E-Mail” attribute on AD, Azure assigns “onmicrosoft.com” as the default domain and primary UPN. Once the initial DirSync is complete, adding “Email” value to AD user object wont help.

WAAD_2

Resolution:

As usual PowerShell comes to rescue. Idea is to use Windows Azure AD Module for Powershell and change the UPN of all the objects with .onmicrosoft UPN.

Steps:

1) Download and Install Azure AD modules from http://technet.microsoft.com/library/jj151815.aspx

2) Connect to WAAD  service using Office 365 admin credentials

3) Filter all the users ending with .onmicrosoft.com  as their UPN

4) Change the UPN using Set-MsolUserPrincipalName

5) Generate reports before and after updates

Download the scripts here: Update-msolUpn.ps1 

Powershell:

#
#.SYNOPSIS ./Update-msolUpn.ps1
#PowerShell script to automate this task to change the all Office 365 user accounts with user@domain.onmicrosoft.com. to user@domain.com
#Install Azure AD modules from http://technet.microsoft.com/library/jj151815.aspx before running this.
#

#Get Modules
$env:PSModulePath=$env:PSModulePath+";"+"C:\Program Files (x86)\Microsoft SDKs\Windows Azure\PowerShell"
$env:PSModulePath=$env:PSModulePath+";"+"C:\Windows\System32\WindowsPowerShell\v1.0\Modules\"
Import-Module Azure
Import-Module MSOnline

Get-Credential "office365admin@GSI.com" | Export-Clixml C:\GSI\scripts\GSIcred.xml #Store Credentials

#$count = 1 #For Testing the first result

$cred = Import-Clixml C:\GSI\scripts\GSIcred.xml

Connect-MsolService -Credential $cred

Get-MsolUser -All | Select-Object UserPrincipalName, Title, DisplayName, IsLicensed | export-csv –path C:\GSI\scripts\GSI_MSOL_Users_BeforeUpdate.csv

Get-MsolUser -All |
 Where { $_.UserPrincipalName.ToLower().EndsWith("onmicrosoft.com") } |
 ForEach {
 #if($count -eq 1) #For Testing the first result
 # {
 $upnVal = $_.UserPrincipalName.Split("@")[0] + "@GSI.com"
 Write-Host "Changing UPN value from: "$_.UserPrincipalName" to: " $upnVal -ForegroundColor Magenta
 Set-MsolUserPrincipalName -ObjectId $_.ObjectId -NewUserPrincipalName ($upnVal)
 $count++
 # }
 }

Get-MsolUser -All | Select-Object UserPrincipalName, Title, DisplayName, IsLicensed | export-csv –path C:\GSI\scripts\GSI_MSOL_Users_AfterUpdate.csv

 

Powershell to Change Modified data for published documents


Issue:

Some of the documents are published or overwritten accidentally.  This made some of older documents show upfront in the ContentQuery or Content Search webparts which is configured sort latest.

Solution:

To update the modified date  to an older date (created date) of the published documents and make sure the published status is not changed.

Steps:

1) Identify the published date of accidentally overwritten documents

2) Disable any eventhandler associated with the document library

3) Use $listitem.UpdateOverwriteVersion() to change the modified date to created date

4) Enable event handler.

Script:


#
#.SYNOPSIS
#Resets the modified date to created date for list of items when created date is between
# Jan 1 2014 to feb 1 2014 and modified date is April 4 2014
#
#
Add-PSSnapin Microsoft.SharePoint.Powershell -ea SilentlyContinue

$web = Get-SPWeb -Identity "http://gsidev/sites/site"
$list = $web.GetList("http://gsidev/sites/list/")
$startDate = Get-Date "3/12/2014" #Select all the items with start date ranging from
$interval = [TimeSpan] "30.00:00:00" #Range in days
$setModifiedDate = Get-Date "5/2/2014" #with modified date
$Logfile = "C:\Scripts\ModifiedReport.log"

# End of variables

Function LogWrite
{
 Param ([string]$logstring)

 Add-content $Logfile -value $logstring
}

function UpdateModifiedDate {
 param($folderUrl)
 $folder = $web.GetFolder($folderUrl)
 Write-Host(" ")
 Write-Host("**-- Updating Carry holder folder: " + $folder.Name +" --*")
 LogWrite(" ")
 LogWrite("**-- Updating Carry holder folder: " + $folder.Name +" --*")


 foreach ($file in $folder.Files) {
 
 $listItem = $file.Item
 $modifiedDate = ([DateTime]$listItem["Modified"]).Date
 $createdDateTime = ([DateTime]$listItem["Created"]).DateTime
 $createdDate = ([DateTime]$listItem["Created"]).Date
 $days = $createdDate - $startDate 
 
 if(($days -ge 0)-and($days -le $interval)-and ($modifiedDate -eq $setModifiedDate))
 #if(($days -ge 0)-and($days -le $interval))
 { 
 
 if( $listItem.File.Level -eq "Published")
 {
 
 Write-Host("--> Updating Carry holder file: " + $file.name +" <--")
 LogWrite("--> Updating Carry holder file: " + $file.name +" <--")
 
 #<#
 $web.AllowUnsafeUpdates = $true
 $listItem["Modified"]= $createdDateTime
 $listItem.UpdateOverwriteVersion()
 $listItem.File.Publish("Added carryholder Name");
 $web.AllowUnsafeUpdates = $false
 ##>
 
 
 }
 else
 {
 Write-Host("--> Updating Carry holder file: " + $file.name +" <--")
 LogWrite("--> Updating Carry holder file: " + $file.name +" <--")
 
 
 #<#
 $web.AllowUnsafeUpdates = $true
 $listItem["Modified"]= $createdDateTime
 $listItem.UpdateOverwriteVersion()
 $web.AllowUnsafeUpdates = $false
 ##>
 
 
 }
 }
 
 }
}

foreach ($folder in $list.Folders) {
 UpdateModifiedDate($folder.Url)
}

Sharepoint 2013 – Open file share search results in Non-IE Browsers & IPAD


Issue:

In SharePoint 2013, if non-IE browsers are used to open the file share results (eg: file://sp2012/Share/test.docx) it may not work as expected. Looks like this a known behavior to avoid security problems.

Resolution:

1) Deploy a HTTP handler at _layouts to download the data from the file share

2) Modify all the file-share HREF’s in the display template to call the handler

1) Deploy a HTTP -handler at _layouts to download the data from the file share:

Create a HTTP handler download.ashx and drop it at _Layouts folder

<%@ WebHandler Language="C#" Class="download" %>

using System;
using System.Web;
using System.IO;

public class download : IHttpHandler {

 public void ProcessRequest (HttpContext context) {
 string file = context.Request.QueryString["file"];
 // if (!string.IsNullOrEmpty(file) && File.Exists(context.Server.MapPath(file)))
 if (!string.IsNullOrEmpty(file) )
 {
try
 {
 Uri uri = new Uri(file);
 context.Response.ContentType = "application/octet-stream";
 //Set the ContentType to "application/octet-stream" which cover any type of file
 context.Response.AddHeader("content-disposition", "attachment;filename=" + Path.GetFileName(uri.LocalPath));
 context.Response.WriteFile(uri.LocalPath);
 context.Response.End();
 }
 catch (Exception ex)
 {
 context.Response.ContentType = "text/plain";
 context.Response.Write(ex);
 }
 }
 else
 {
 context.Response.ContentType = "text/plain";
 context.Response.Write("File cannot be found!");
 }
 }

 public bool IsReusable {
 get {
 return false;
 }
 }

}

This handler can be tested by using simple HTML  like this

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
 <title></title>
</head>
<body>
 <a href="Download.ashx?file=file://sp2012/Share/AddClickToDiv.docx">Download</a>
</body>
</html>

HTTPHandler accepts any query string passed with “file” parameter (Download.ashx?file=”file location”) and downloads the file.

2) Modify all the file-share HREF’s in the display template to call the handler

~sitecollection/_catalogs/masterpage/Display Templates/Search/Control_SearchResults.html is the display template used to render the search results.

Add new cutsom javascript file “replacehref.js” in the beginning of the body and call the function “setFileshareHandlerHrefs” using script on demand JS libraries.


</head>
<body>
 <script>
 $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Search/replacehref.js");
 </script>
 <div id="Control_SearchResults" >
<!--#_

 AddPostRenderCallback(ctx, function()
 {
SP.SOD.executeOrDelayUntilScriptLoaded(setFileshareHandlerHrefs, "sp.js");
});

Now in the replacehref.js select all the HREF elements from the display template (var selectors = [‘.ms-srch-result a’]) and replace all the URL’s with handler and file parameter


/// <reference path="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" />

function setFileshareHandlerHrefs() {
var fileshareHandler = "/_layouts/15/download.ashx?file=";
var filePrefix = "file://";
var selectors = ['.ms-srch-result a'];
$.each(selectors, function (i, selector) {
$(selector).each(function (e) {
var hrf = $(this).attr('href');
if (hrf.indexOf(filePrefix) > -1 && $(this).attr('FileHandlerSet') == null) {
hrf = _spPageContextInfo.siteAbsoluteUrl + fileshareHandler + hrf;
$(this).attr('FileHandlerSet', true);
}
$(this).attr('href', hrf);
});
});
}

Now when the file share link in the search result page is clicked, it calls the handler and file will be downloaded.
This is tested in IPAD and other major browsers.

Note:

This work around may not work with the kerberos enabled sites due to “double hop” issue. Since the /_layouts folder is registered under apppool account, impersonating the http handler with context user on kerberos enabled site causes conflicts in accessing file share. To resolve this issue

  1. Add a new folder “handler” on C:\inetpub and copy the Download.ashx, test.html and web.config files.
  2. Right click portal site from IIS -> Add Application and set physical path to C:\Inetpub\handler
  3. Select portal app pool as application app pool
  4. Now set “Connect As” to your file share crawl account
  5. Reset IIS
  6. Change the following line from var fileshareHandler = “/_layouts/15/download.ashx?file=”; to var fileshareHandler = “/handler/download.ashx?file=”;

This will resolve the double-hop issue.

SharePoint webpart with HTTP session timeouts and authentication popups


Requirement:

Though SharePoint sites are windows authenticated, I had a requirement to implement a webpart to pull data from confidential data source which mandated end users to authenticate every 15 minutes.

Design:

After some brainstorming the design is finalized to set authentication timeout on SP webpart such that there wont be any data leak even if the user leaves the desktop unlocked.

OOTB SharePoint webpages doesn’t support Session. But session objects can be used in code behind by creating “session state service application” and authentication popups can be called from Page_Load event of webpart using SP.UI.ModalDialog

Implementation:

Step 1: Create Session state service application

Run the below powershell script as a Farm Admin to create Session State Service application. (This Service app is not available from Central Admin GUI)

C:\PS>Enable-SPSessionStateService -DatabaseName "Session State Database" -DatabaseServer "localhost" -SessionTimeout 30

Session values can be changed by running

Get-SPSessionStateService

Set-SPSessionStateService –SessionTimeout 1

For testing purposes session values are reset to 1 min. This will create session database and new values are updated on creation of each session

Session_DB

Step 2: Add authentication page on the layout folder

Now create an application page for authentication under _layouts folder. This will have two controls for username and password. Now this page will be called from the webpart when the authentication is needed. Make sure EnableSessionState=”True” is added to page.


<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SignInPage.aspx.cs" Inherits="SignInPage.Components.SignInPage" DynamicMasterPageFile="~masterurl/default.master" EnableSessionState="True" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormSection" Src="/_controltemplates/15/InputFormSection.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormControl" Src="/_controltemplates/15/InputFormControl.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ButtonSection" Src="/_controltemplates/15/ButtonSection.ascx" %>

<asp:Content ID="Content1" ContentPlaceHolderId="PlaceHolderPageTitle" runat="server">
 <SharePoint:EncodedLiteral ID="EncodedLiteral1" runat="server" text="Signin Page" EncodeMethod='HtmlEncode'/>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderId="PlaceHolderPageTitleInTitleArea" runat="server">
 <SharePoint:EncodedLiteral ID="EncodedLiteral2" runat="server" text="Signin Page" EncodeMethod='HtmlEncode'/>
</asp:Content>
<asp:Content ID="PageDescription" ContentPlaceHolderID="PlaceHolderPageDescription" runat="server">
 <SharePoint:EncodedLiteral ID="EncodedLiteral3" runat="server" text="Page Description" EncodeMethod='HtmlEncode'/>
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">

<table id="maintable" border="0" cellspacing="0" cellpadding="0" class="ms-propertysheet" width="100%">
 <wssuc:InputFormSection runat="server">
 <Template_Description>
 <SharePoint:EncodedLiteral ID="EncodedLiteral4" runat="server" text="Please enter your Windows password to continue" EncodeMethod="HtmlEncode"/>
 </Template_Description>
 <Template_InputFormControls>
 <wssuc:InputFormControl runat="server">
 <Template_Control>
 <table border="0" cellspacing="1">
 <tr>
 <td class="ms-authoringcontrols" colspan="2" nowrap="nowrap">
 <SharePoint:EncodedLiteral ID="userName" runat="server" text="Windows User" EncodeMethod="HtmlEncode"/>
 <font size="4"> </font><br />
 </td>
 </tr>
 <tr>
 <td dir="ltr">
 <SharePoint:InputFormTextBox title="FormSection1Input" class="ms-input" ID="passwordBox" Columns="35" Runat="server" maxlength="255" size="60" width="100%" TextMode="Password" />
 </td>
 </tr>
 <tr>
 <td style="line-height:10px">&nbsp;</td>
 </tr>
 <tr>
 <td style="line-height:10px">&nbsp;</td>
 </tr>
 <tr>
 <td>
 <asp:Button runat="server" class="ms-ButtonHeightWidth" ID="BtnOk" Text="Ok" style="margin-left:0px" />
 </td>
 </tr>
 <tr>
 <td>
 <SharePoint:EncodedLiteral ID="errorMessage" runat="server" text="" EncodeMethod="HtmlEncode" />
 <font size="4"> </font><br />
 </td>
 </tr>
 </table>
 </Template_Control>
 </wssuc:InputFormControl>
 </Template_InputFormControls>
 </wssuc:InputFormSection>

 </table>

 <SharePoint:FormDigest ID="FormDigest1" runat="server" />
</asp:Content>

Popup

Since this authentication page is loaded as Modal popup, register CloseForm() script on the page to close the popup when the password matches.


namespace SignInPage.Components
{
 using System;
 using System.Security.Permissions;
 using System.Web;
 using Microsoft.SharePoint;
 using Microsoft.SharePoint.Security;
 using Microsoft.SharePoint.WebControls;
 using Microsoft.SharePoint.Administration.Claims;
 using Microsoft.Office.Server.Diagnostics;
 using Microsoft.IdentityModel.Claims;
 using System.DirectoryServices.AccountManagement;

/// <summary>
 /// TODO: Add comment for SignInPage
 /// </summary>
 [SharePointPermission(SecurityAction.InheritanceDemand, ObjectModel = true)]
 public partial class SignInPage : LayoutsPageBase
 {
 private const string SESSION_STATUS_KEY = "{7CF253B3-6C3C-4B7A-A77B-D20736A74F25}";

/// <summary>
 /// Initializes a new instance of the SignInPage class
 /// </summary>

// Get current user claims
protected IClaimsIdentity claimsIdentity =
 HttpContext.Current.User.Identity as IClaimsIdentity;

public SignInPage()
 {
 }

/// <summary>
 /// Sets the inital values of controls
 /// </summary>
 /// <param name="e">Event arguments</param>
 protected override void OnLoad(EventArgs e)
 {
 passwordBox.Focus();

if (Session[SESSION_STATUS_KEY] == null)
 {
 SPSite siteCollection = this.Site;
 SPWeb site = this.Web;
 string[] windowsLogin = claimsIdentity.GetDisplayName().ToString().Split(':');
 userName.Text = windowsLogin[0];
 BtnOk.Click += new EventHandler(BtnOk_Click);
 errorMessage.Text = "";
 string script = @"
 <script type=text/javascript>
 function CloseForm() {
 window.frameElement.cancelPopUp();
 return false;}
 </script>";
 ClientScript.RegisterClientScriptBlock(this.GetType(), ClientID, script);
 }
 else
 {
 PortalLog.LogString("session true " + DateTime.Now.ToString());
 string script = @"
 <script type=text/javascript>
 function CloseForm() {
 window.frameElement.cancelPopUp();
 return false;}
 </script>";
 ClientScript.RegisterClientScriptBlock(this.GetType(), ClientID, script);
 ClientScript.RegisterStartupScript(this.GetType(), ClientID, "CloseForm();", true);
 PortalLog.LogString(" form closed " + DateTime.Now.ToString());
 }
 }

/// <summary>
 /// TODO: Add comment
 /// </summary>
 /// <param name="sender">Sender of the event</param>
 /// <param name="e">Arguments of the event</param>
 private void BtnOk_Click(object sender, EventArgs e)
 {

if (IsPostBack)
 {
 try
 {
 string passwordText = passwordBox.Text;
 if (passwordText != "")
 {
 string[] username = claimsIdentity.Claims[0].ToString().Split('\\');
 bool valid = false;
 using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
 {
 valid = context.ValidateCredentials(username[1], passwordText);
 }

if (valid)
 {
 errorMessage.Text = "Password is right";
 PortalLog.LogString("Signin Current Time Is " + DateTime.Now.ToString());
 Session[SESSION_STATUS_KEY] = DateTime.Now.ToString(); // Use current time
 PortalLog.LogString("Signin Updated Session Status :" + Session[SESSION_STATUS_KEY]);
 ClientScript.RegisterStartupScript(this.GetType(), ClientID, "CloseForm();", true);
 PortalLog.LogString("Signin Reg Close Script OK");

 }
 else
 {
 errorMessage.Text = "Incorrect Password please try again";
 }
 }
 else
 {
 errorMessage.Text = "Please enter your password";
 }

}
 catch (Exception ex)
 {
 PortalLog.LogString("Signin Exception:" + ex.ToString());
 }

}
 }

}
}

Here ClientScript.RegisterClientScriptBlock registers the javascript on page load and ClientScript.RegisterStartupScript calls CloseForm() function from the registered script. context.ValidateCredentials(username[1], passwordText) validates the password.

Step 3: Call authentication page fron “Page_Load” event

Now call the authentication script on Page_Load event of the webpart.


protected void Page_Load(object sender, EventArgs e)
{
System.Web.SessionState.HttpSessionState session = System.Web.HttpContext.Current.Session;
AllowDocumentRetreival = session != null ? session[SESSION_STATUS_KEY] != null : false;

if(AllowDocumentRetreival)
	{
string script =
                   @"
                    function dialogCallback(dialogResult, returnValue){window.location.reload();}
                    function ShowModal() {
                   ExecuteOrDelayUntilScriptLoaded(function () {
                    var options = {
                        url: '/_layouts/15/signinpage/signinpage.aspx',
                        title: 'Signin',
                        width: 500,
                        height: 210,
                        allowMaximize: true,
                        showClose: false,
                        dialogReturnValueCallback: dialogCallback
                    };
                 SP.UI.ModalDialog.showModalDialog(options);
                }, 'sp.js');}";

            ScriptManager.RegisterClientScriptBlock(this, this.GetType(), ClientID, script, true);
            ScriptManager.RegisterStartupScript(this, this.GetType(), ClientID, "ShowModal();", true);
	}

}

SP.UI.ModalDialog.showModalDialog(options) calls the signin page created in the last step. On successful authentication closeform() function calls  window.frameElement.cancelPopUp() to close the popup.

Session state troubleshooting tips:

In few scenarios Session object always return null though session value exists in the database. This could be cache. To resolve this issue navigate to C:\ProgramData\Microsoft\SharePoint\Config and delete all the files in the GUID named folders except the .INI file and restart the SharePoint timer service.

Analysing network traffic – troubleshooting


Many occasions while configuring the FAST SSA’s with custom pipelines, crawl rate will be very less.

Sometimes, the issues might be due to network settings. Follow these steps to debug these issues.

Please see the steps below in order to configure Network Monitor:

1a. Turn off TCP Chimney if any of the machines are Windows 2003
Option 1) Bring up a command prompt and execute the following:
Netsh int ip set chimney DISABLED
Option 2) Apply the Scalable Networking Patch – http://support.microsoft.com/default.aspx?scid=kb;EN-US;936594

1b. Confirm that TCP Chimney is turned off if any of the machines are Windows 2008 and the driver is older than January 2010 (see http://support.microsoft.com/default.aspx/kb/951037 for more details)
a) bring up a command prompt and execute the following:
netsh int tcp show global
b) if it turns out TCP Chimney is on disable it
netsh int tcp set global chimney=disabled

2.  Turn off TCP Offloading/Receive Side-Scaling/TCP Large Send Offload at the NIC driver level

3.  Retry your application.  Don’t laugh – many, many problems are resolved by the above changes.

4.  Download Network Monitor
(http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=983b941d-06cb-4658-b7f6-3088333d062f)

5. Install Network Monitor on both the client and server experiencing the problem.  If you are not able to install it on the server you can install it on another machine that is connected to the same hub as the server or to the admin port of the switch that the server is on.  If you go this route you must synchronize the time between the client, server, and this third machine.

6.  Synchronize the clocks on the Client and SQL machines
a)  At one of the machines bring up a command prompt and execute the following:
Net time <\\machinenamewewanttosynchwith> /set /yes

7. Using the NMCap command-line utility, start the chained trace (chained = create a new capture file after reaching the “Temporary capture file size” rather than overwriting the current capture)
a) [Netmon 3 installation folder]\NMCap /network * /capture /captureprocesses /file test.chn:25M /UseProfile 45c7af5a-d264-4243-90df-fb97082c52ac (creates 25 MB chained files)
b) NOTE:  YOU MUST USE THE .CHN EXTENSION TO CAPTURE CHAINED TRACES
c) NOTE:  The target folder must exist for NMCap to create the trace file

8. Flush DNS
a) ipconfig /flushdns

9) If dealing with an authentication failure, you will now want to purge the Kerberos tickets
a) klist tickets tgt purge

10. Get the IP addresses of the client and the server
a)  ipconfig /all on the client > client.txt
b)  ipconfig /all on the server > server.txt

11. Reproduce the problem, please note the exact time the problem reproduces.  Also, please note the exact error message.

12. Stop the trace by hitting Ctrl-c in the command-line window

IMPORTANT: Please remember to let me know the IP addresses of the server and client as well as the time that the problem occurred.

More information can be found at:

http://blogs.technet.com/netmon/archive/2006/10/24/nmcap-the-easy-way-to-automate-capturing.aspx

OR

by running the command-line switch /examples

OR

by running the command-line switch /?

Powershell script to update masterpage:


Param(
 $csvOutPutName = "masterPageOutput-ts.csv"
 )
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SharePoint')
#SCRIPT VARIABLES
 [string]$siteUrl = $args[0]
function GetMissingParameter {
 $script:siteUrl = read-host "Enter Site URL"
 }
function ProcessDirectory($directory, $spfolder) {
 foreach ($file in $directory.GetFiles()) {
 $docUrl = $spfolder.Url + "/" + (Split-Path $file -Leaf)
 $fileToUpdate = $spfolder.ParentWeb.GetFile($docUrl)
if ($fileToUpdate.Exists) {
 $fileToUpdate.CheckOut()
 $newfile = $spfolder.Files.Add($file.Name, $file.OpenRead(), $true)
 $newfile.Update()
 $newfile.CheckIn("Checked-in file via PowerShell script.")
if ($newfile.Level -eq "Draft") {
 $newfile.Publish("Published file via PowerShell script.")
 if ($newfile.Level -ne "Published") {
 $newfile.Approve("Approved file via PowerShell script.")
 }
 }
Write-Host Uploaded file $file.Name to $spfolder.Name
 }
 }
 }
############
 # MAIN
 ############
#IF MISSING PARAM FOR SITE URL OR MANAGED PATH, ASK FOR INPUT TO FILL
 if($args.length -eq 0) {
 GetMissingParameter
 }
$site = New-Object Microsoft.SharePoint.SPSite($siteUrl)
 $impactedSites = @()
cd Masterpages
 $currentfolder = get-item .
Write-Host "Copying masterpage files to $($site.Url)..." -foregroundcolor Yellow
foreach($web in $site.AllWebs) {
 $obj = New-Object PSObject -property @{ Url = $web.Url; OldCustomMasterPage = $web.CustomMasterUrl; OldMasterPage = $web.MasterUrl; SiteType = "Web"; }
 $obj | fl
$masterpageGallery = $web.GetCatalog(116).RootFolder
 ProcessDirectory $currentfolder $masterpageGallery
$impactedSites += $obj }
cd ..
$site.Dispose()
$impactedSites | ft
 $impactedSites | Export-Csv -Path $csvOutPutName -NoTypeInformation