Wednesday, December 23, 2015

SharePoint-hosted apps: Add Fields (Columns) to SharePoint List in Host Web using JSOM



var onQuerySucceeded = function(sender, args) {
    alert("List Field Updated");
}

var onQueryFailed = function (sender, args) {
    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}

var createFields = function (listName) {
    var clientContext = new SP.ClientContext.get_current();
    var factory = new SP.ProxyWebRequestExecutorFactory(appWebUrl);
    context.set_webRequestExecutorFactory(factory);
    var parentContext = new SP.AppContextSite(clientContext, hostWebUrl);

    // Get List
    var list = parentContext.get_web().get_lists().getByTitle(listName);
    var fieldCollection = list.get_fields();

    /*
    $(fieldsCollection).each(function (index, fieldValue) {
        fieldCollection.addFieldAsXml(fieldValue, true, SP.AddFieldOptions.defaultValue);
    });*/
    
    fieldCollection.addFieldAsXml("", true, SP.AddFieldOptions.defaultValue);
    fieldCollection.addFieldAsXml("", true, SP.AddFieldOptions.defaultValue);
    clientContext.load(fieldCollection);

    clientContext.executeQueryAsync(onQuerySucceeded, onQueryFailed);

}

// Add custom columns to the SharePoint List in Host Web
createFields("Projects");


SharePoint-hosted apps: Create a Custom List in Host Web using SharePoint REST API



var getQueryStringParameters = function(qsPara) {
    var paramArray = document.URL.split("?")[1].split("&");

    for (var i = 0; i < paramArray.length; i++) {
        var paraName = paramArray[i].split("=");
        if (paraName[0] === qsPara) {
            return paraName[1];
        }
    }
}

var getHostWebUrl = function () {
    var hostWebUrl = decodeURIComponent(getQueryStringParameters("SPHostUrl"));
    return hostWebUrl;
}


var createList = function (listName, baseTemplate, description) {
    var deferred = $.Deferred();
    var appWebUrl = _spPageContextInfo.webAbsoluteUrl;
    var hostWebUrl = getHostWebUrl();
    var executor = new SP.RequestExecutor(appWebUrl);
    var httpRequestUrl = appWebUrl + "/_api/SP.AppContextSite(@target)/web/Lists?@target='" + hostWebUrl + "'";

    executor.executeAsync({
        method: "POST",
        url: httpRequestUrl,
        body: "{ '__metadata': { 'type': 'SP.List' }, 'AllowContentTypes': true, 'BaseTemplate': " + baseTemplate + ", 'ContentTypesEnabled': true, 'Description': '" + description + "', 'Title': '" + listName + "' }",
        headers: {
            "accept": "application/json;odata=verbose",
            "content-type": "application/json;odata=verbose"
        },
        success: function (data, status, jqXHR) {
            deferred.resolve();
        },
        error: function (data) {
            deferred.reject();
        }
    });


    return deferred.promise();
}

// Create a List named as 'Projects' in Host Web 
createList("Projects", "100", "This lists consist of projects used by SharePoint CV App")


Tuesday, December 1, 2015

SharePoint-hosted apps: Send Emails using SharePoint REST API


var sendEmails = function (emailCollection) {

    var oDeferred = $.Deferred(),
        email, iCounter = 0;
    // create an object for a http request
    var oHttpRequest = {
        url: "{0}/_api/SP.Utilities.Utility.SendEmail",
        type: "POST",
        contentType: "application/json; odata=verbose",
        headers: {
            "accept": "application/json; odata=verbose",
            "contentType": "application/json; odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val()
        }
    }

    oHttpRequest.url = String.format(oHttpRequest.url, _spPageContextInfo.siteAbsoluteUrl);

    // Iterate the email collections and send emails
    for (email in emailCollection) {
        oHttpRequest.data = JSON.stringify({
            'properties': {
                '__metadata': { 'type': 'SP.Utilities.EmailProperties' },
                'From': emailCollection[email].From,
                'To': { 'results': [emailCollection[email].To] },
                'Subject': emailCollection[email].Subject,
                'Body': emailCollection[email].Body
            }
        });

        try {
            return $.ajax(oHttpRequest)
                .done(function () {
                    iCounter += 1;
                    if (iCounter == emailCollection.length) // Once all the emails are send then resolve the promise object.
                        oDeferred.resolve();
                }).fail(function (xhr, textStatus, errorThrown) {
                    alert(textStatus);
                });
        }
        catch (err) {
            err.message;
        }
    }
    return oDeferred.promise();
}


// Example Email Object
var emailCollection = [];
var oEmail = {};
oEmail["From"] = "salman.malik@de.sp.com";
oEmail["To"] = "salman.malik@de.sp.com";
oEmail["Subject"] = "Test Email From Sharepoint App";
oEmail["Body"] = "It is a test email generated from Sharepoint App";
emailCollection.push(oEmail);


sendEmails(emailCollection);

Thursday, November 19, 2015

SharePoint 2013: Install Solutions with PowerShell Remoting

Remoting Configurations

1. Check remoting service is running by executing get-service winrm
2. Enable the remoting by executing Enable-PSRemoting –force
3. Run the command on the server Enable-WSManCredSSP -Role Server
4. Run the following command on the client
set-item wsman:localhost\client\trustedhosts -value *

Enable-WSManCredSSP -Role Client –DelegateComputer *

 

$remoteMachine = "de-c-qs-ws.domain.de"
$userName = "domain\user";
$password = "Password";
$filePath = "C:\solutions\solution.wsp"


$pass =  $password | ConvertTo-SecureString -AsPlainText -Force>
$credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $userName, $pass
$session = New-PSSession $remoteMachine -Authentication Credssp -Credential $credentials

Write-Host "Loaded PowerShell Assembly" -f Green;
Invoke-Command -Session $session -ScriptBlock { Add-PSSnapin Microsoft.SharePoint.PowerShell; }

Invoke-Command -Session $session -ScriptBlock { Install-SPSolution -Identity $args[0] -GACDeployment } -ArgumentList $newSolution.SolutionId                                              
$newSolution = Invoke-Command -Session $session -ScriptBlock { Add-SPSolution -LiteralPath $args[0] } -ArgumentList $filePath
Write-Host "Added Solution: " $filePath -f Green;#>
                      
Remove-PSSession -Session $session
#Write-Host "Installed Solution: " $filePath -f Green;

Tuesday, September 22, 2015

SharePoint 2013: Find and Replace string in Calculated columns
// Replace '.' with '-'
=REPLACE([IP Adresse],FIND(".",[IP Adresse]),1,"-")

// Replace all the '.' to '-'. This means '192.168.191.51' becomes '192-168-191-51'

=REPLACE(REPLACE(REPLACE([IP Adresse],FIND(".",[IP Adresse]),1,"-"),FIND(".",REPLACE([IP Adresse],FIND(".",[IP Adresse]),1,"-")),1,"-"),FIND(".",REPLACE(REPLACE([IP Adresse],FIND(".",[IP Adresse]),1,"-"),FIND(".",REPLACE([IP Adresse],FIND(".",[IP Adresse]),1,"-")),1,"-")),1,"-")
SharePoint 2013: Get title, url and site owners of all site collections via PowerShell

Add-PSSnapin "Microsoft.SharePoint.PowerShell"

$path = 'D:\Power-Shell-Scripte\SolutionFarmSiteCollections.csv';
$sitesList = @()
foreach($webApp in Get-SPWebApplication) {
    # get all site collections of web applications except this one
    if($webApp.Url -ne "http://my-sp01Nintex:4711/"){   
        foreach($site in $webApp.Sites){
            $ps_obj = New-Object PSObject -Property @{
                "WebApplication" = $webApp.Url
                 "Site Title" = $site.RootWeb.Title
                 "Site Url" = $site.Url
                 "Primary Owner" = $site.Owner
                 "Secondary Owner" = $site.SecondaryContact
            }
           $sitesList += $ps_obj  
        }
    }
}

# Export to csv file 
$sitesList | Export-Csv -path $path -Delimiter ";"

Wednesday, August 26, 2015

SharePoint 2013: Edit the layout of MySite Person.aspx via Delegate control

Problem: Hide the actity title on Person.aspx (mySite).

Person.aspx

Solution: Inject your code on Master Page(mysite.master) in a Delegate control i.e. AdditionalPageHead. The following series of steps will guide you how to proceed;


  • Create an Empty SharePoint Project using VS.Net.
  • Add a user control (.ascx) to your project.
  • In my case, it was a css class applied to the div on person.aspx and I have to hide it. So, I wrote the following inline style sheet in the user control(.ascx);


  • Now, add an empty Elements.xml and reference the delegate control by providing its id in it. In my case, I have decided to inject my code in 'AdditionalPageHead' delegate control that already exist in‘mysite.master’;


  • The following is how my test visual studio project looks like;
  • That’s it.. Deploy your solution and activate the webapplication scoped feature. Once the feature is activated, css added on the user control will be injected to the delegate control present on the mysite.master master page. The following is the result in my case.. :)





Wednesday, May 27, 2015

Call a custom RESTful WCF Web Service from SharePoint hosted App via CORS

Context: I was working on a SharePoint hosted app. During the development, I need to get the list of all web applications from SharePoint. Out of the box, JSOM and Restful web services doesn’t provide an interface to get a list of web application so I decided to write my own custom WCF Restful web service. Once, I am done writing the Webservice, I tried to access it via Javascript(Ajax call), but I recieved an error: 401 (Unauthorized). So, what was the issue? I was trying to call a cross domain restful webservice from my App domain and it also requires windows authentication. After doing some research, I found that I have manipulate Http headers to execute my cross domian calls and I did it via CORS (Cross Origin Resource Sharing)

Solution: In this context, the following is the code for my Restful WebService;


STEP 1: Create a RestFul WCF Service


// IFarmSolutions.cs

using Microsoft.Ajax.Samples;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace Company.FarmSolutionsWS
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    [ServiceContract]    
    interface IFarmSolutions
    {
        
        [WebGet(UriTemplate = "GetAllFarmSolutions",
            ResponseFormat = WebMessageFormat.Json)]
        //[JSONPBehavior(callback = "method")]
        [OperationContract]
        List GetAllFarmSolutions();

        [WebGet(UriTemplate = "GetAllWebApplications",
            ResponseFormat = WebMessageFormat.Json)]
        //[JSONPBehavior(callback = "method")]
        [OperationContract]
        List GetAllWebApplications();   
        // TODO: Add your service operations here
        
    }   
}

///////////////FarmSolutions.svc.cs/////////////
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Client.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;

namespace Company.FarmSolutionsWS
{

    //[BasicHttpBindingServiceMetadataExchangeEndpointAttribute]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class FarmSolutions : IFarmSolutions
    {
        public List GetAllFarmSolutions()
        {
            List strFarmSolution = new List();

            foreach (SPSolution solution in SPFarm.Local.Solutions)
            {
                strFarmSolution.Add(solution.Name);
            }
            return strFarmSolution;
        }

        public List GetAllWebApplications()
        {
            List list_webapplications = new List();

            SPServiceCollection services = SPFarm.Local.Services;
            foreach (SPService service in services)
            {
                if (service is SPWebService)
                {
                    SPWebService webService = (SPWebService)service;
                    foreach (SPWebApplication webApplication in webService.WebApplications)
                    {
                        if (webApplication.DisplayName != "SharePoint Central Administration v4")
                        {
                            WebApplication oWebApplication = new WebApplication();
                            oWebApplication.DisplayName = webApplication.DisplayName;
                            oWebApplication.Name = webApplication.Name;
                            oWebApplication.Url = webApplication.GetResponseUri(SPUrlZone.Default).ToString();
                            list_webapplications.Add(oWebApplication);
                        }
                    }
                }
            }
            return list_webapplications;
        }
    }
}
STEP 2: Create a Cross Domain Handler
Once I had my SharePoint Restful Web service, I need to access it via my SharePoint hosted App. Since SharePoint App is running in its own domain, I wrote a cross domain handler (HTTP Module) by following the link. The purpose of writing the handler(HTTP Module) is to solve the authentication problem by adding the same origin policy to the HTTP header response in the preflight phase at the server. In this regard, I created a console application and added the following lines to code into it.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;

namespace ns_SPCrossDomainHandler
{
    public class SPCrossDomainHandler : IHttpModule
    {

        public void Dispose()
        {
            throw new NotImplementedException();
        }


        public void Init(HttpApplication context)
        {
            context.PreSendRequestHeaders += (sender, e) =>
            {
                var response = context.Response;

                if (!string.IsNullOrEmpty(context.Request.Headers["Origin"]) &&
                    context.Request.Headers["Origin"].IndexOf("app") != -1)
                {
                    response.AddHeader("Access-Control-Allow-Origin", context.Request.Headers["Origin"]);
                    response.AddHeader("Access-Control-Allow-Methods", "*");
                    response.AddHeader("Access-Control-Allow-Credentials", "true");
                    if (context.Request.HttpMethod.ToUpperInvariant() == "OPTIONS")
                    {

                        response.StatusCode = (int)HttpStatusCode.OK;
                    }
                }
            };
        }    

    }
}


Compile the SPCrossDomainHandler project and place the dlls in the BIN folder of your webapplication. In my case the path was: C:\inetpub\wwwroot\wss\VirtualDirectories\test.spsite.group80\bin. Now open the web.config and add the following entry under modules tag


STEP 3: Call your custom RestFul WCF service via Javascript
Now you can ready to execute cross domain calls since our cross domain handler is deployed and it will take care of your calls by adding necessary headers in the request. The following function I used to execute cross domain calls from my SharePoint hosted app to my custom Restful service;

function getWebMethodViaCORS(serviceUri) {
            var serviceUri = "https://test.mysite/sites/spApps/_vti_bin/FarmSolutionsWS/FarmSolutions.svc/GetAllWebApplications";
            var deferred = $.Deferred();

            $.ajax({
                crossDomain: true,
                xhrFields: {
                    'withCredentials': true
                },
                url: serviceUri,
                success: function (data, status) {
                    deferred.resolve(data);
                },
                failure: function (xhr, status, error) {
                    console.log(xhr);                    
                    deferred.reject(xhr);
                }
            });

            return deferred.promise();
        }

cheers.. :)

Friday, May 8, 2015

Upload and Download File(s) from Document Library via PowerShell


# UPLOAD FILES TO DOCUMENT LIBRARY

cls

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

$docLibrary = "Document library name"
$localFolderPath = "folder path"
$webUrl = "web url"
$web = Get-SPWeb -Identity $webUrl

$docLibrary = $web.Lists[$docLibraryName] 
$files = ([System.IO.DirectoryInfo] (Get-Item $localFolderPath)).GetFiles() | ForEach-Object { 

    #Create file stream object from file
    $fileStream = ([System.IO.FileInfo] (Get-Item $_.FullName)).OpenRead()
    $contents = new-object byte[] $fileStream.Length
    $fileStream.Read($contents, 0, [int]$fileStream.Length);
    $fileStream.Close(); 

    write-host "Uploading " $_.Name "to" $docLibrary.Title "in" $web.Title "..." 

    #Add file
    $folder = $web.getfolder($docLibrary.Title) 
    $spFile = $folder.Files.Add($folder.Url + "/" + $_.Name, $contents, $true)
    $spItem = $spFile.Item 
}


Write-Host "Uploaded File(s) to library..." -f Green


# GET FILES FROM DOCUMENT LIBRARY USING CAML AND DOWNLOAD THOSE FILES

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

$site_url = "site url";
$docLibrary = "Document Library Title"
$downloadFolder = "Local Folder Path";

$site = Get-SPSite -Identity $site_url
$docLibrary = $site.RootWeb.Lists.TryGetList($docLibrary);

$query = New-Object Microsoft.SharePoint.SPQuery
# Get All the files from DocLib where Status =  New. _Status is the internal name of the column.
$camlQuery ="New"                          
$query.ViewAttributes = "Scope=Recursive";
$query.Query = $camlQuery

if(Test-Path $downloadFolder)
{
    $list_Items = $list_farm_solutions.GetItems($query);        


    Write-Host "List Title: " $docLibrary.title -f Green
    Write-Host "Total items found: " + $list_Items.Count -f Green

    foreach($list_item in $list_Items) 
    {
       # Download a File from Document Library
       $file = $web.GetFile($list_item.Url)
       $binary = $file.OpenBinary()
       $filePath = Join-Path $downloadFolder $file.Name
       $stream = New-Object System.IO.FileStream($filePath,[System.IO.FileMode]'Create', [System.IO.FileAccess]'Write')
       $writer = New-Object System.IO.BinaryWriter($stream)
       $writer.write($binary)
       $writer.Close()


    }
}
else
{
    Write-Host "Incorrect download Path: " $downloadFolder -f Cyan
}

Wednesday, May 6, 2015

Find last modified date, size of certain site collections in SharePoint via PowerShell

cls
Add-PSSnapIn "Microsoft.SharePoint.PowerShell"
$webApplication = "web application url"
$splitString = "sites"
$csvFile = Import-Csv -path "csv file path" -Delimiter ";" | select site # The csv file contains list of all sites. In my case it was around 650 sites
$sites = Get-SPSite -WebApplication http://portal.tuv.net -Limit ALL

[string]$content = "" 

foreach($csv_site in $csvFile)
{
     Write-Host "Site Title from Csv: " $csv_site.Site -f Blue
     #$found_site = $sites | Where-Object{ $_.Url -like "*" + $csv_site.Site + "*"}
     foreach($site in $sites)
     {
        $siteurl = $site.Url.ToString().split("/")[$site.Url.ToString().split("/").length -1]
        if($siteurl -eq $csv_site.Site)
        {             
             [int]$size = $site.Usage.Storage /1024 /1024
          $content += $site.LastContentModifiedDate.ToLocalTime().toString("dd.MM.yyyy") + "`t" + $size + "`t" + $site.Url + "`t" + $site.RootWeb.Title + "`n"
             Write-Host "Found: " $csv_site.Site -f Green
        }
     }      
}

Set-Content -Path .\GetAllSitesSize.txt -Value $content 

Tuesday, April 14, 2015

Move Folder from one Document Library to another via PowerShell

$site_urL = "https://sp.group/sites/08544/"
$dest_doclib = "https://sp.group/sites/08544/Products%20old/"
$src_doc_name = "IT Documentation"
$folder_to_move = "Products";

$site = Get-SPSite $site_url
$web = $site.RootWeb
$src_doc = $web.lists[$src_doc_name]
$subfolders = $src_doc.RootFolder.SubFolders["$folder_to_move"]

foreach ($fl in $subfolders.SubFolders)
{    
    #$dest_doc + $fl.Name
    $fl.MoveTo($dest_doclib + $fl.Name)
} 

Wednesday, March 25, 2015

Create Site Columns in SharePoint Online (Office 365) using CSOM

cls

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")

# Create a context and return the context object.
function getContext()
{
    $context = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
    $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $password)
    $context.Credentials = $credentials

    return $context;
}

# Check if you are able to connect to SharePoint online.
function validateSPOnline()
{
    try
    {
        
        $ctx = getContext;
        $web = $ctx.Web;
        $ctx.Load($web);
        $ctx.ExecuteQuery();

         return $true;
     }
     catch
     {
         Write-Host "Unable to connect with SharePoint online site. Error description: " $_.Exception.Message -ForegroundColor Yellow;
         break;
     }
}

# Create Site Columns by reading a xml file: sitecolumns.xml
function createAllSiteColumns()
{
    $ctx = getContext;
    $web = $ctx.Web;

    # Read Fields from Xml Template
    $siteColumnsXml = [xml](get-content $file_SiteColumns)

    Write-Host "Creating site column(s)..." -f Cyan
 foreach ($node in $siteColumnsXml.Template.Field) 
    {
        $fieldName = $node| Select DisplayName
        $web.Fields.AddFieldAsXml($node.OuterXml, $false, [Microsoft.SharePoint.Client.AddFieldOptions]::DefaultValue);
        $ctx.ExecuteQuery();
    }

    $ctx.Dispose();
    $ctx = $null;
}

function main()
{
    if (validateSPOnline)
    {
        createAllSiteColumns;
    }
}

#SharePoint Online Settings
#$siteUrl = Read-Host 'Please enter the SharePoint online site url'
#$username = Read-Host 'Please enter the username'
#$password = Read-Host "Enter password" -AsSecureString
$siteUrl = “https://spapps.sharepoint.com”
$username = "muhammadsalman@SPApps.onmicrosoft.com"
[string]$pwd = “Passwort123456“
$password = $pwd | ConvertTo-SecureString -AsPlainText -Force

# File Paths
$file_SiteColumns = "C:\Users\Projects\SPApp-Zeiterfassung\List Creation\SiteColumns.xml"

main


Site Columns XML file


Friday, March 6, 2015

Hide Fields (columns) from SharePoint List Forms based on Permission (Groups) using JSOM

Context: Customer wants to hide some fields on the new (NewForm.aspx), edit (EditForm.aspx) and display (DispForm.aspx) forms of the SharePoint list from the members based on their permissions.

Solution: Since the customer is using SharePoint online site, I wrote a small JSOM script to fulfill their requirements. I placed the name of the site groups along with the fields in a hash table (array). In this way, I knew which fields I need to hide from the members of group. Furthermore, if a user belongs to two groups then permissions from the group with higher permissions should apply to the user. So, i placed the groups in a separate array which means that one can find group with hishest permssion at index 0.
The following lines of code that I wrote and then later added a Script Editor Webpart and placed the code in it;



Note: The above code will work on DispForm.aspx. But, if you want to make it work for edit or new forms then you have to find the html controls on the forms. For instance; for edit form, you have to make changes in the hideHtmlElements function as shown below and rest of the code will work for edit form;
function hideHtmlElements(elementsArray)
{
     $(elementsArray).each(function(index, value){
         if(value != "")
         {
       var elementFound = $("nobr:contains(" + value + ")");
       var parentTr = elementFound.closest("tr");
       parentTr.hide();
         }
     });  
}

Thursday, January 22, 2015

Set Managed Metadata Field using CSOM via PowerShell in SharePoint online (Office 365)

Context: I was working on a project to migrate data from Lotus notes to SharePoint online. In this context, I had to use Client object model to create list items and set the values of the fields in the list. One of the challenge that I came across was how to set a managed metadata field value using CSOM and PowerShell.

Solution: The following is the code that I wrote to achieve this task. I used an example that was using JSOM to set the Managed metadata field. I converted the same logic using CSOM and PowerShell.
cls

#Your SharwPoint online Credentials
$siteUrl = “https://test.sharepoint.com/sites/dev3”
$username = "testAccount@test.onmicrosoft.com"
[string]$pwd = “Password“
$password = $pwd | ConvertTo-SecureString -AsPlainText -Force
$listName = "Taxonomy List";

# Load the Client object Model Assemblies

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Taxonomy")

function getContext()
{
    $context = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
    $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $password)
    $context.Credentials = $credentials

    return $context;
}
$context = getContext;

# load the List
$mainList = $context.Web.Lists.GetByTitle($listName);
$context.Load($mainList);
$context.ExecuteQuery();

# load the Taxonomy Field
$TaxonomyKategorieFld = $mainList.Fields.GetByInternalNameOrTitle($taxonomyField) 
$context.Load($TaxonomyKategorieFld)
$context.ExecuteQuery();

# Create the item object in the Taxonomy List
$itemCreationInfo = New-Object Microsoft.SharePoint.Client.ListItemCreationInformation;
$item = $mainList.AddItem($itemCreationInfo);
$item.set_item("Title","Test Taxonomy Item");
$item.Update();

# Create Taxonomy Session
$sTaxonomySession = [Microsoft.SharePoint.Client.Taxonomy.TaxonomySession]::GetTaxonomySession($context);
$sTaxonomySession.UpdateCache();
$context.Load($sTaxonomySession);
$context.ExecuteQuery();

# Load Default Term Store (Site Settings --> Term Store Management) 
$sTermStore = $sTaxonomySession.GetDefaultSiteCollectionTermStore();
$context.Load($sTermStore);
$context.ExecuteQuery();


if($sTermStore.IsOnline)
{
    $sGroup = $sTermStore.Groups.GetByName($sGroupName); # Get the Term Group
    $sTermSet = $sGroup.TermSets.GetByName($tsName); # Get the Term Set
    $context.Load($sTermSet);    
    $context.ExecuteQuery();
    $terms = $sTermSet.GetAllTerms(); # Load all the Terms in the TermSet
    $context.Load($terms);
    $context.ExecuteQuery();
            
    $txField = [Microsoft.SharePoint.Client.ClientContext].GetMethod("CastTo").
               MakeGenericMethod([Microsoft.SharePoint.Client.Taxonomy.TaxonomyField]).
               Invoke($context, $TaxonomyKategorieFld)    
    $termQuery = "Kunden";
    $termQuery1 = "Acme";
    $termValues = @();
    foreach($term in $terms)
    {
        # When Kunden or Aceme Terms found, add to the Taxonomy Field
        if(($term.Name -eq $termQuery) -or ($term.Name -eq $termQuery1)) 
        {
            $termValues +=  "-1;#" + $term.Name + "|" + $term.Id;
            $termValuesString = $termValues -join ";#"
        }    
    }    
        
    $termValues = new-object Microsoft.SharePoint.Client.Taxonomy.TaxonomyFieldValueCollection($context, $termValuesString, $txField)
    $txField.SetFieldValueByValueCollection($item, $termValues);
    $item.Update();
    $context.Load($item);
    $context.ExecuteQuery();
}

$context = $null;
Reference: http://sharepoint.stackexchange.com/questions/113146/how-do-you-properly-write-to-a-managed-metadata-column-from-jsom-sharepoint-20

Cheers.. :)

Friday, January 16, 2015

Recover and Restore SharePoint Group Users

Context: SharePoint Owner of a site accidently deleted the ‘Members’ group and wanted the group with all users back.

Solution: First I restored the backup of the Content database in the Test environment and mounted it to the Web Application. 
Once the Site collection is available, I wrote a PowerShell Script to export the Users of the ‘members’ Group into Csv file. The following is the code that I wrote;

clear

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

$siteUrl = "https://test.sharepoint.group/sites/1112"
$csvPath = "C:\Users\salman\Desktop\Export Csv\UsersRetrieved.csv"

$site = Get-SPSite $siteUrl

$group = $site.RootWeb.SiteGroups.GetByName("Site_Member");

$userList = @()
foreach($user in $group.Users)
{
    $psUser = New-Object PSObject -Property @{
        "ID" = $user.ID
        "Display Name" = $user.DisplayName
        "Login Name" = $user.LoginName
        
    }
    $userList += $psUser;
}

if($userList.length -gt 0)
{
    $userList | Export-Csv -Path $csvPath
    Write-Host "Total Users exported: " $group.Users.Count;
}

$site.Dispose();



Then, I created a group named as Site_Members manually by looking at the settings from the testing environment site group.

Once the group is ready, I copied the csv file created with the Import script in the Production environment and ran the following PS script in the production environment.

clear

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

$siteUrl = "https://sharepoint.group/sites/1112"
$csvPath = "C:\Users\salman\Desktop\Export Csv\UsersRetrieved.csv";
$groupName = "Site_Member";

$site = Get-SPSite $siteUrl

$group = $site.RootWeb.Groups.GetByName("$groupName");
if(Test-Path $csvPath)
{
    $usersList = Import-Csv -Path $csvPath
    foreach($user in $usersList)
    {
        $name = $user."Login Name";        
        $user = $site.RootWeb.EnsureUser($name)        
        $group.AddUser($user);
    }    
}

Thursday, January 15, 2015

Publish a List as Catalog and consume it in Search Results WebPart

Context: I wanted to publish a list as Catalog and later wanted to consume list’s data in a ‘Search Results’ webpart. The following diagram shows bird’s eye view of my problem;



 Solution: The figure shows that Site Collection A is publishing and B is consuming. So, first we are going to publish a list as Catalog. The following series of steps should be followed to make a list as Catalog.

  • Publish List as Catalog
  1. First create Site Columns as those will later be used as managed properties in the Search schema and will be consumed in the Results Search web part. Go to (Site Settings -> Site Columns). 
  2. Create a custom list named a ‘Cars’.
  3. Add the Site Columns into the Cars list. Add also some dummy data in the list.
  4. Now go to the (Site Settings-> Site Collection Features-> Enable ‘Cross-Site Collection Publishing).
  5. Now enable the Catalog Settings by going to (List (Cars)-> List Settings-> Catalog Settings). On the Catalog Setting page, select ‘Enable this library as catalog’ as shown below; 
  6. Now the Site Collection A with a list ‘Cars’ is ready to be consumed into the Site Collection B. Let’s now go to the Site Collection B and add ‘Search Results webpart’.

  • Setup Site Collection to Consume list catalog
  1. Before you add the webpart, first go to your Search Service and add the ‘Site Collection A’ url in the Content Sources (Search Service Application-> Content Sources) and start a full crawl by right clicking the content source.
  2. Go to the Site Collection B and activate a Site Collection feature ‘SharePoint Server Publishing Infrastructure’.
  3. Now go to (Site Settings -> Manage site features -> Activate ‘SharePoint Server Publishing’).
  4.  Once it is activated, you will find ‘Manage catalog connection’ option added into the Site Administration group.
  5. Go to ‘Manage catalog connections’, click catalog ‘connect to catalog’. SharePoint will show number of catalogs to be consumed as shown in the figure. Click connect on your publishing catalog list.
Your Site collection is now ready to consume the List catalog ‘Cars.
  • Attach list with Search Results WebPart
Follow the following series of steps to add a list catalog ‘Cars’ to Search Results webpart.

  1. Before you add the webpart, first go to your Search Service and add the ‘Site Collection A’ url in the Content Sources (Search Service Application --> Content Sources) and start a full crawl by right clicking the content source.
  2. Go to the webpart properties and click change query.
  3. Select the list and click ‘Test query’ button. You will immediately get a preview of the search results as shown below;
  4. Click Apply button to finalize the changes and Save your page to see the ‘Search Result’ webpart working.
That's it enjoy working with List catalog and Search Results webpart in SharePoint...