During various SharePoint 2013 projects, I came across requirements which involve some bulk operations on existing SharePoint site. Here are some examples:

In these requirements, the major challenges are – (1) ‘No Access to Farm servers’; so we cannot write all logic in PowerShell script. (2) Long running bulk operations; so we cannot completely rely on client side java script.

The best approach is to create a hybrid solution and use PowerShell to connect to the site and then write logic using CSOM in script.

To use CSOM, we need to refer SharePoint client DLLs. So if we are running this script from a SharePoint 2013 machine, we can just refer from ISAPI folder. If running from a non-SharePoint machine, you need to copy these DLLs to machine and refer it in script.

In this example, script only covers connecting to a SharePoint site and reading list items. You can further add functions based on your requirement. The following are the steps to create this PowerShell Solution:

  1. Open Visual Studio and create a PowerShell project (refer my previous article for creating PowerShell projects in Visual Studio). Alternatively, you can use other PS editors like Power GUI.



  2. Rename the default script file to “ScriptMain.ps1”. Add a new script file “ConnectHelper.ps1”.



  3. Open “ConnectHelper.ps1” and copy the following code. There are generic methods to allow connection for both SharePoint 2013 on premises site and Online.
    1. ##Name: ConnectHelper.ps1#
    2. function Connect - SPClient { < #.This creates a Microsoft.SharePoint.Client.ClientContext object
    3. for a SharePoint site using the given credentials..Parameters - site, isSPOnline, user, password, requestTimeOutSec, formsBased, outputs.Example
    4. To create a ClientContext
    5. for an on - premises SharePoint using username and password
    6. $context = Connect - SPClient - site $site - user "domain\user" - password(ConvertTo - SecureString "password"–AsPlainText–Force) - isSPOnline: $false# > [CmdletBinding()]
    7. Param(
    8. [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String] $site, [Parameter(Mandatory = $false)][Boolean] $isSPOnline = $true, [Parameter(Mandatory = $false)][String] $user, [Parameter(Mandatory = $false)][SecureString] $password, [Parameter(Mandatory = $false)][int] $requestTimeoutSec = 180, [Parameter(Mandatory = $false)][Boolean] $formsBased = $false)
    9. Write - Host "$($MyInvocation.MyCommand.Name): Begin"
    10. Write - Verbose "$($MyInvocation.MyCommand.Name): Getting client connection to "
    11. "$site"
    12. " - $((Get-Date).toString())"
    13. #Ensure required combination of user / password or sssSite / sssTargetAppId.
    14. if ([string]::IsNullOrEmpty($user) - or $password - eq $null) {
    15. throw "Invalid parameters. Provide both User and Password parameters. " + $user + " Password " + $password
    16. }
    17. [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {
    18. $true
    19. }
    20. $context = New - Object Microsoft.SharePoint.Client.ClientContext($site) - Verbose: $false
    21. if ($isSPOnline) {
    22. Write - Verbose "$($MyInvocation.MyCommand.Name): Generating SharePoint Online client credential"
    23. Write - Verbose "$($MyInvocation.MyCommand.Name): Creating credential from login/password"
    24. $context.Credentials = New - Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($user, $password) - Verbose: $false
    25. } else {
    26. Write - Verbose "$($MyInvocation.MyCommand.Name): Generating Windows client credential"
    27. if ($formsBased) {
    28. Write - Verbose "$($MyInvocation.MyCommand.Name): Creating credential from login/password for forms based authentication"
    29. $context.AuthenticationMode = [Microsoft.SharePoint.Client.ClientAuthenticationMode]::FormsAuthentication
    30. $context.FormsAuthenticationLoginInfo = New - Object Microsoft.SharePoint.Client.NetworkCredential FormsAuthenticationLoginInfo($user, $password) - Verbose: $false
    31. } else {
    32. Write - Verbose "$($MyInvocation.MyCommand.Name): Creating credential from login/password for default authentication"
    33. $context.AuthenticationMode = [Microsoft.SharePoint.Client.ClientAuthenticationMode]::Default
    34. $context.Credentials = New - Object System.Net.NetworkCredential($user, $password) - Verbose: $false
    35. $context.add_ExecutingWebRequest($ {
    36. function: ExecutingWebRequestEventHandler_NoFormsAuth
    37. })
    38. }
    39. }
    40. #Set the timeout
    41. $context.RequestTimeout = ($requestTimeoutSec * 1000)
    42. Write - Verbose "$($MyInvocation.MyCommand.Name): Done"
    43. Write - Verbose "$($MyInvocation.MyCommand.Name): End"
    44. return $context
    45. }
    46. function ExecutingWebRequestEventHandler_NoFormsAuth { < #.Synopsis
    47. This EventHandler must be used
    48. if authenticating against an on premise environment with mixed authentication(forms based + something differnt) to ensure that not forms based authentication is used.# > [CmdletBinding()]
    49. Param(#object sender, WebRequestEventArgs e[Parameter(Mandatory = $true)][object] $sender, [Parameter(Mandatory = $true)][Microsoft.SharePoint.Client.WebRequestEventArgs] $e)#Write - Host "$($MyInvocation.MyCommand.Name): ExecutingWebRequestEventHandler_NoFormsAuth"
    50. Write - Verbose "$($MyInvocation.MyCommand.Name): ExecutingWebRequestEventHandler_NoFormsAuth"
    51. $e.WebRequestExecutor.WebRequest.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f")
    52. }
  4. Open “ScriptMain.js” and copy this code. This define calling the connect methods with parameters and using CSOM, reading from list.
    1. < #.Synopsis
    2. All main functions.Notes
    3. Name: ScriptMain.ps1# >
    4. #Add references to SharePoint client assemblies - this is required
    5. for CSOM
    6. Add - Type - Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Taxonomy.dll"
    7. Add - Type - Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
    8. Add - Type - Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
    9. #Load connecthelper.
    10. "$PSScriptRoot\ConnectHelper.ps1"
    11. #Global variables
    12. $global: siteUrl = $null
    13. $global: user = $null
    14. $global: pass = $null
    15. $global: isOnline = $null
    16. function SetCredentials() {
    17. $global: siteUrl = read - host "Enter Url"
    18. $global: user = read - host "Enter Username"
    19. $global: pass = read - host "Enter Password" - AsSecureString
    20. $global: isOnline = read - host "Is SPOnline(True/False)"
    21. }
    22. #
    23. function used to connect to SP Site
    24. function GetClientContext {
    25. [CmdletBinding()]
    26. Param(
    27. [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String] $siteUrl, [Parameter(Mandatory = $true)][String] $user, [Parameter(Mandatory = $true)][SecureString] $pass, [Parameter(Mandatory = $true)][String] $isOnline)
    28. if ($isOnline - eq 'False') {
    29. $clientContext = Connect - SPClient - site $siteUrl - isSPOnline $false - user $user - password $pass
    30. } else {
    31. $clientContext = Connect - SPClient - site $siteUrl - isSPOnline $true - user $user - password $pass
    32. }
    33. Try {
    34. $clientContext.Load($clientContext.Web);
    35. $clientContext.ExecuteQuery();
    36. Write - Host 'Connect to site:'
    37. $siteUrl - foregroundcolor green
    38. return $clientContext;
    39. } Catch[System.Exception] {
    40. Write - Host 'Unable to connect. Either invalid url or user and pass combination'
    41. return $null
    42. }
    43. }
    44. function Main() {
    45. Write - Host 'Main Starts'
    46. $context = GetClientContext - siteUrl $global: siteUrl - isOnline $global: isOnline - user $global: user - pass $global: pass
    47. if ($context - eq $null) {
    48. return
    49. }
    50. Write - Host 'Load Shared Documets library';
    51. $list = $context.Web.Lists.GetByTitle('Documents')
    52. $context.Load($list)
    53. $context.ExecuteQuery()
    54. if ($list.ItemCount - le 0) {
    55. Write - Host 'There are no items inside Documents' - foregroundcolor red
    56. return
    57. } else {
    58. Write - Host 'Total Documents = '
    59. $list.ItemCount - foregroundcolor green
    60. return
    61. }
    62. }
    63. ###Script Execution starts here#####Call Functions##
    64. SetCredentials
    65. Main
  5. All the functions in both the scripts are self-explanatory. Please feel free to contact me if you have any doubts.

  6. Now, open the PowerShell console and change to the script directory. Call “ScriptMain.ps1” and hit Enter. It will ask for various parameters.



  7. Provide parameters: Site Url, User Name (domain\user), Password and IsSPOnline (True/False). Hit Enter.



  8. It will take few seconds to load SharePoint DLLs, and then will connect to the given site, read “Shared Documents” library item count and display.


I hope this will help.

Thanks!