Tuesday 18 August 2015

Connect to Office 365 using PowerShell

Connect to Office 365 using PowerShell

Here are the high-level Steps to Connect to Office 365 using PowerShell :
2. Next, download SharePoint Online Management Shell 64-bit.
3. Next, open the SharePoint Online Management Shell as an administrator (right click run as an administrator).
4. Run Get-ExecutionPolicy and see what it is set to. If the execution policy is set to anything other than Unrestricted or RemoteSigned you’ll encounter an error when you try to import a module.
Use Set-ExecutionPolicy RemoteSigned.
5. Next, Run $credential = Get-Credential to create a PowerShell object. Add the admin Login e-mail and Password to build credential object.
6. Next, lets connect to Office 365.
a) Run Import-Module MsOnline – This is to import the Office 365 module.Run Get-Module to verify.
b) Next, connect to Office 365 Use Connect-MsolService -Credential $credential
By providing $credential element, Office 365 will automatically connect you to the correct domain.
Connect Office 365 PowerShell
7. Next we will Connect to SharePoint Online.
Connect-SPOService -Url https://learningwayinstitute-admin.sharepoint.com -credential $credential
Note : Make sure the SharePoint online site has – admin append to the url.
Connect to Office 365

Friday 8 May 2015

SharePoint 2013 Code Tips – Setting a Managed Metadata Field with the Client Object Model (CSOM and JSOM)

This blog give you insight how to tackling a problem most SharePoint developers have run across when using the client object model with SharePoint 2010. The problem is updating managed metadata fields. Fortunately, this has become easier in SP2013 with the new Microsoft.SharePoint.Taxonomy.Client and the SP.Taxonomy.js file in JSOM. There is a blog post about updating managed metadata fields in SP2010 and you can read it here SP2010 Managed Metadata . I explained how you had to update two fields when updating managed metadata. This was confusing and error prone. Now you no longer need to update the additional field. In this post I will show you how to do this using both the managed CSOM and JSOM in the app model. I will cover updating single and multi valued managed metadata fields and a few things about accessing lists outside of the application host in Office 365. The code for this article can be found here Managed Metadata Code Samples

Updating Managed Metadata using CSOM

In order to update a managed metadata field in SP2010 you had to update two fields. One was the managed metadata field itself and the other was it’s corresponding backing text field. This was very cumbersome. First you had to use the managed metadata’s SchemaXml property to parse out the ID of its backing field and then use this ID to set the backing field. Fortunately, the new Microsoft.SharePoint.Client.Taxonomy namespace in SP2013 has made this much easier. No longer do you need to update two fields. It is also much easier to lookup the GUID for a term. The GUID is needed to update managed metadata fields. In SP2010 you needed to call the Taxonomy web service to get these and parsing the returned xml was a nightmare. The following code uses the managed SharePoint 2013 client object model to either update a single managed metadata value field or a multi-valued metadata field. The method takes a site URL, list name, item ID, the name of the managed metadata field and the label of the term. The caller of the method does not have to know anything about the term or field since the code will do all the work to get the appropriate information.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public static void SetManagedMetaDataField(string siteUrl,
            string listName,
            string itemID,
            string fieldName,
            string term)
        {
 
            ClientContext clientContext = new ClientContext(siteUrl);
            List list = clientContext.Web.Lists.GetByTitle(listName);
            FieldCollection fields = list.Fields;
            Field field = fields.GetByInternalNameOrTitle(fieldName);
                                  
            CamlQuery camlQueryForItem = new CamlQuery();
            string queryXml = @"<view>
                                <query>
                                    <where>
                                        <eq>
                                            <fieldref name="ID">
                                            <value type="Counter">!@itemid</value>
                                        </fieldref></eq>
                                    </where>
                                </query>
                            </view>";
 
            camlQueryForItem.ViewXml = queryXml.Replace("!@itemid", itemID);
 
            ListItemCollection listItems = list.GetItems(camlQueryForItem);
 
 
            clientContext.Load(listItems, items =>; items.Include(i =>; i[fieldName]));
            clientContext.Load(fields);
            clientContext.Load(field);
            clientContext.ExecuteQuery();
             
            TaxonomyField txField = clientContext.CastTo<taxonomyfield>(field);
            string termId = GetTermIdForTerm(term, txField.TermSetId, clientContext);
 
            ListItem item = listItems[0];
                       
            TaxonomyFieldValueCollection termValues = null;
            TaxonomyFieldValue termValue = null;
 
            string termValueString = string.Empty;
 
            if (txField.AllowMultipleValues)
            {
 
                termValues = item[fieldName] as TaxonomyFieldValueCollection;
                foreach (TaxonomyFieldValue tv in termValues)
                {
                    termValueString += tv.WssId + ";#" + tv.Label + "|" + tv.TermGuid + ";#";              
                }
 
                termValueString += "-1;#" + term + "|" + termId;
                termValues = new TaxonomyFieldValueCollection(clientContext, termValueString, txField);
                txField.SetFieldValueByValueCollection(item,termValues);
                 
            }
            else
            {
                termValue = new TaxonomyFieldValue();
                termValue.Label = term;
                termValue.TermGuid = termId;
                termValue.WssId = -1;
                txField.SetFieldValueByValue(item, termValue);
            }
 
            item.Update();          
            clientContext.Load(item);
            clientContext.ExecuteQuery();
        }</taxonomyfield>

The code uses the CSOM taxonomy classes TaxonomyFieldValueCollection and TaxonomyFieldValue. These make it easier for setting the different properties that are required for managed metadata values. Also the new TaxonomyField class enables the code to check whether the field accepts multiple values by using the AllowMultipleValues property. Also, these new classes expose methods for updating the field. You no longer set the field value directly on the item. The example above shows how you can append a new term to an existing group of terms. Finally, below is the code for the GetTermIdForTerm method which uses the new CSOM capabilities to search for a term’s unique ID based on a given term label using the new LabelMatchInformation class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static string GetTermIdForTerm(string term,
            Guid termSetId, ClientContext clientContext)
{
            string termId = string.Empty;
             
            TaxonomySession tSession = TaxonomySession.GetTaxonomySession(clientContext);
            TermStore ts = tSession.GetDefaultSiteCollectionTermStore();
            TermSet tset = ts.GetTermSet(termSetId);
 
            LabelMatchInformation lmi = new LabelMatchInformation(clientContext);
 
            lmi.Lcid = 1033;        
            lmi.TrimUnavailable = true;          
            lmi.TermLabel = term;
             
            TermCollection termMatches = tset.GetTerms(lmi);
            clientContext.Load(tSession);
            clientContext.Load(ts);
            clientContext.Load(tset);
            clientContext.Load(termMatches);
            
            clientContext.ExecuteQuery();
 
            if (termMatches != null && termMatches.Count() > 0)
                termId = termMatches.First().Id.ToString();
 
            return termId;
          
 }

What about Office 365 and JSOM

Implementing the same CSOM code in JSOM to run in Office 365 proved to be much more complex. For example, the code needs to lookup the term’s GUID before you can update the field.The CSOM is easier since it is synchronous and the calling thread waits until the lookup is completed. However when using JSOM you must make all your calls asynchronously. So in the code below subsequent calls must be made in the success call back functions. This of course makes the code hard to follow. The asynchronous requirement of JSOM also forced me to make the GetTermIdForTerm method asynchronous. In Office 365  to access lists residing in the hosting web you must set up a new SP.AppContextSite object in order to get the host web and list. All the same classes that are available in CSOM are also available in JSOM.  The Taxonomy classes are contained in the SP.Taxonomy.js file and is not loaded by default. So you must make sure this is loaded.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
function SetManagedMetaDataField(listName,
            itemID,
            fieldName,
            term) {
 
    appweburl = decodeURIComponent(getQueryStringParameter('SPAppWebUrl'));
    hostweburl = decodeURIComponent(getQueryStringParameter('SPHostUrl'));
    context = new SP.ClientContext(appweburl);
    factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
    context.set_webRequestExecutorFactory(factory);
    appContextSite = new SP.AppContextSite(context, hostweburl);
 
    var list = appContextSite.get_web().get_lists().getByTitle(listName);
    var item = list.getItemById(itemID);
    var field = list.get_fields().getByInternalNameOrTitle(fieldName);
    var txField = context.castTo(field, SP.Taxonomy.TaxonomyField);
     
     
    context.load(field);
    context.load(txField);
    context.load(item);
     
 
    context.executeQueryAsync(
       function () {
 
           var termSetId = txField.get_termSetId().toString();
           var termId;
 
           getTermIdForTerm(function success(id) {
               termId = id;
               var value = item.get_item(fieldName);
               var terms = new Array();
 
               if (txField.get_allowMultipleValues()) {
 
                   var enumerator = value.getEnumerator();
                   while (enumerator.moveNext()) {
                       var tv = enumerator.get_current();                    
                       terms.push(tv.get_wssId() + ";#" + tv.get_label() + "|" + tv.get_termGuid());
                   }
 
                   terms.push("-1;#" + term + "|" + termId);
                   termValueString = terms.join(";#");
                   termValues = new SP.Taxonomy.TaxonomyFieldValueCollection(context, termValueString, txField);
                   txField.setFieldValueByValueCollection(item, termValues);
               }
               else {
                   var termValue = new SP.Taxonomy.TaxonomyFieldValue();
                   termValue.set_label(term);
                   termValue.set_termGuid(termId);
                   termValue.set_wssId(-1);
                   txField.setFieldValueByValue(item, termValue);
               }
 
               item.update();
               context.executeQueryAsync(
                  function () {
                      alert('field updated');
                  }, function (sender, args) {
                      alert(args.get_message() + '\n' + args.get_stackTrace());
                  });
           }, function (sender, args) {
               alert(args.get_message() + '\n' + args.get_stackTrace());
           },context, term, termSetId);
 
           }, function error(err) {
               alert(err.get_message());
           });
        
}
 
function getTermIdForTerm(success, error, clientContext, term, termSetId)
{
    var termId = "";
       
    var tSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(clientContext);
    var ts = tSession.getDefaultSiteCollectionTermStore();
    var tset = ts.getTermSet(termSetId);
    var lmi = new SP.Taxonomy.LabelMatchInformation(clientContext);
     
    lmi.set_lcid(1033);
    lmi.set_trimUnavailable(true);
    lmi.set_termLabel(term);
               
    var termMatches = tset.getTerms(lmi);
     
    clientContext.load(tSession);
    clientContext.load(ts);
    clientContext.load(tset);
    clientContext.load(termMatches);
              
    context.executeQueryAsync(
      function () {
           
          if (termMatches && termMatches.get_count() > 0)
              termId = termMatches.get_item(0).get_id().toString();
          success(termId);
          
      }, function (sender, args) {
          error(args);
      });
 
 
}
 
function getQueryStringParameter(p) {
    var params =
            document.URL.split("?")[1].split("&");
    var strParams = "";
    for (var i = 0; i < params.length; i = i + 1) {
        var singleParam = params[i].split("=");
        if (singleParam[0] == p)
            return singleParam[1];
    }
 
}

Managed Metadata and SharePoint 2013

Managed metadata remote API has become a full citizen in SharePoint 2013. The taxonomy web service has been deprecated and replaced with a CSOM and JSOM client API allowing you to standardize on one remote api. Unfortunately, there is no support for manage metadata manipulation in the SharePoint 2013 REST api. So you will be forced to mix in JSOM into your REST applications for managed metadata.





Tuesday 7 April 2015

Claims Based Authentication in SharePoint 2013, SharePoint 2010 and SharePoint Online

What is SharePoint Claims Authentication?

The claims-based identity is an identity model in Microsoft SharePoint that includes features such as authentication across users of Windows-based systems and systems that are not Windows-based, multiple authentication types, stronger real-time authentication, a wider set of principal types, and delegation of user identity between applications.
Claims-based identity is based on the user obtaining a security token that is digitally signed by a commonly trusted identity provider and contains a set of claims. Each claim represents a specific item of data about the user such as his or her name, group memberships, and role on the network. Claims-based authentication is user authentication that utilizes claims-based identity technologies and infrastructure. Applications that support claims-based authentication obtain the security token from the user and use the information within the claims to determine access to resources. No separate query to a directory service like Active Directory is needed.
In a simple analogy:
You check in at the Airport (Authentication)
– present credentials (Passport)
– credentials are validated by security guard
You receive a boarding pass (Signed Claims)
– Seat, Frequent Flyer, Gate etc.
Think of a claim as a piece of identity information (for example, name, e-mail address, age, or membership in the Sales role). The more claims your application receives, the more you know about your user. These are called “claims” rather than “attributes,” as is commonly used in describing enterprise directories, because of the delivery method. In this model, your application does not look up user attributes in a directory. Instead, the user delivers claims to your application, and your application examines them. Each claim is made by an issuer, and you trust the claim only as much as you trust the issuer. For example, you trust a claim made by your company’s domain controller more than you trust a claim made by the user.
Claims-based authentication in Windows is built on Windows Identity Foundation (WIF), which was formerly known as the Security Token Service, or STS. Many areas of SharePoint still refer to the name STS so it’s important to understand that it and WIF are one in the same. The Security Token Service comes pre-baked into the standard SharePoint 2010 install:
The Security Token Service Application in Central Administration:


The Security Token Service Application in IIS:




WIF is a set of .NET Framework classes that is used to implement claims-based identity. Claims-based authentication relies on standards such as WS-Federation, WS-Trust, and protocols such as SAML.
Microsoft recommends Claims-based authentication as the preferred provider to use on fresh SharePoint 2010 installs. You can configure this on a per-Web Application basis in SharePoint via the following dialog in Central Admin > Web Applications > Manage Web Applications > Ribbon Bar – New

If you select Classic-Mode Authentication, you configure the Web application to use Windows authentication and the user accounts are treated by SharePoint Server 2010 as Active Directory Domain Services (AD DS) accounts.
If you select Claims-Based Authentication, SharePoint Server automatically changes all user accounts to claims identities, resulting in a claims token for each user. The claims token contains the claims pertaining to the user. Windows accounts are converted into Windows claims. Forms-based membership users are transformed into forms-based authentication claims. Claims that are included in SAML-based tokens can be used by SharePoint. Additionally, SharePoint developers and administrators can augment user tokens with additional claims. For example, Windows user accounts and forms-based accounts can be augmented with additional claims that are used by SharePoint Server 2010.
Claims Based Authentication (Tokens) Classic Mode Authentication
-Windows Authentication: NTLM/Kerberos, Basic-Forms-based Authentication (ASP.NET Membership provider and Role Manager)
-Trusted Identity Providers-Custom Sign-in page
-Windows Authentication (NTLM/Kerberos) only
*Both map authenticated users to the same SPUser object (security principles)

What does Claims look like/feel like?

The core process of Claims is illustrated as follows:

The core currency of Claims is the identity token.
 
EXAMPLE 1:

i:0#.w|contosojsmith
EXAMPLE 2:
i:0#.w|jsmith@contoso.com
i = Identity Claim all other claims will use “c” as opposed to “i”
: = Colon separator
0 = Reserved to support future Claims
#/? = Claim Type Encoded Value. The out of the box claim types will have a hardcoded encoded value, this will enable parity across farms.
E.g. Key: ? Value: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
./0 = Claim Value Type. The out of the box claim value types will have a hardcoded encoded value, this will enable parity across farms.
            E.g. Key: . Value: urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name
            Key: 0 Value: http://www.w3.org/2001/XMLSchema#string
w/m/r/t/p/s = Original Issuer Type -> w = windows, m = membership, r = role, t = trusted STS, p = personal card, s= local sts claim

Why do I want to use Claims?

1. Decouples Authentication logic from Authorization and Personalization logic – this means speed and flexibility
2. Provides a common way for applications to acquire the identity information the need about users
3. Cloud-ready – lays the foundation to be able to Authenticate against Azure, Facebook, Google, Windows Live ID etc.
4. Federation – Partner networks, business to business, subsidiaries can all interact in the same sphere of authentication, cross machine and cross-farm
5. Supports existing identity infrastructure (Active Directory, LDAP, SQL, WebSSO etc.)
6. Standards-based and interoperable
Bonus Prize:
7. In SP 2010 we can have a single Web Application configured to use multiple authentication types which allows different auth types to be served from one URL:

Claims Gotchas

General issues for all Claims implementations
– Search crawler requires NTLM in the zone it uses
– Office Client Integration (2007 SP2+, 2010 are minimum requirements in order to maintain Client integration e.g. fluid editing of Word Document)
– SharePoint Designer does not support working with Claims Enabled Endpoints for Web Services
Migration issues when moving from Classic to Claims
– When upgrading from Classic to Claims, you will need to migrate users and Test & re-work customizations (Web parts, workflows etc.)
– After you move to Windows claims, you cannot go back to Windows classic. Ensure that you have good backups before you start and try your migration in a lab first before moving into production.
– Existing alerts may not fire, if this occurs the only workaround may be to delete and recreate the alerts
– Search crawl may not function, double-check the web application policies and ensure that the search crawl account shows the new converted account name. If it does not, you must manually create a new policy for the crawl account.