Get Available PowerShell Commands for SharePoint on Client-Side

Needless to say, that on Client Side, we get a limited scope of running various SharePoint commands. As a result there aren’t much cmdlets for the Client Side. So how do you know what are the available commands that might come handy while executing cmdlets remotely? Simply run the following command in PowerShell or SharePoint Online Management Shell.
get-command | Where-Object { $_.ModuleName -eq "Microsoft.Online.SharePoint.PowerShell" }

A sample list of available cmdlets are displayed in the following screenShot.

You cannot grant a user the Limited Access permission level

This is the error message I received when trying to assign a ListItem (Word Document), Limited Access permission.

To get a grip on this, first take a look at the following table. The table illustrates a list of all the Permission Level in Windows SharePoint Services 3.0

PERMISSION LEVEL DESCRIPTION
Full Control This permission level contains all permissions. Assigned to the Site name Owners SharePoint group, by default. This permission level cannot be customized or deleted.
Design Can create lists and document libraries, edit pages and apply themes, borders, and style sheets in the Web site. Not assigned to any SharePoint group, by default.
Contribute Can add, edit, and delete items in existing lists and document libraries. Assigned to the Site name Members SharePoint group, by default.
Read Read-only access to the Web site. Users and SharePoint groups with this permission level can view items and pages, open items, and documents. Assigned to the Site name Visitors SharePoint group, by default.
Limited Access The Limited Access permission level is designed to be combined with fine-grained permissions to give users access to a specific list, document library, item, or document, without giving them access to the entire site. However, to access a list or library, for example, a user must have permission to open the parent Web site and read shared data such as the theme and navigation bars of the Web site. The Limited Access permission level cannot be customized or deleted.

NOTE You cannot assign this permission level to users or SharePoint groups. Instead, Windows SharePoint Services 3.0 automatically assigns this permission level to users and SharePoint groups when you grant them access to an object on your site that requires that they have access to a higher level object on which they do not have permissions. For example, if you grant users access to an item in a list and they do not have access to the list itself, Windows SharePoint Services 3.0 automatically grants them Limited Access on the list, and also the site, if needed.

Now, I was trying to assign, from C# code, using Client Object Model, various Roles, to a user, like,

  • Read-Only,
  • Editor,
  • Contributor,
  • Administrator, &
  • Limited Access.

As it turns out, this permission level, Limited Access, is for SharePoint’s internal use only. So basically, we don’t have to be bothered about this.

There is a complete article about this on MSDN,  http://office.microsoft.com/en-us/windows-sharepoint-services-help/permission-levels-and-permissions-HA010100149.aspx

Add a reference of the Microsoft.Online.Administration.Automation.PSModule dll to your Project in Visual Studio

First of all make sure that all the required items are already installed on your machine. You can view the requirements here, https://realmpksharepoint.wordpress.com/2014/07/10/install-sharepoint-online-management-shell-on-client-side/. The Microsoft.Online.Administration.Automation.PSModule dll is required to execute the
Connect-MsolService

command and get the return values in the form of type, Microsoft.Online.Administration.User from within the .net C# code. Well, it’s supposed to be a simple job of adding a reference of this dll to your project. The problem is to identify the location of this dll.

Initially, I did some googling to download the dll. However, I couldn’t find any trusted source (Microsoft) from where I can download this dll. Then, I realized that this dll should have been downloaded with the installation of Windows Azure Active Directory Module. Hence, I navigated to that location I found the dll at the following location

C:\Windows\System32\WindowsPowerShell\v1.0\Modules\MSOnline

Unfortunately, the job’s not done yet. A strange thing started happening here. Though, I can view this dll in my Explorer. The folder, MSOnline was inaccessible from the Visual Studio Add Reference window!

Still, I am not aware of this weird behavior. What I did to resolve this issue is, I copied the entire MSOnline folder to the bin directory of the project and from there I was able to add the dll’s reference to the project.

Install SharePoint Online Management Shell on Client-Side

This particular job caused quite a bit of trouble. Though, the objective was just to download and install the SharePoint Online Management Shell, the issues arose due to various dependencies. I have tried to list down the various steps involved in this operation below

System Requirements:

    • Supported Operating System.
      • Windows 7 Service Pack 1,
      • Windows 8,
      • Windows Server 2008 R2 SP1,
      • Windows Server 2008 Service Pack 2,
      • Windows Server 2012
  • PowerShell 3.0

Update PowerShell from 2.0 to 3.0

If you’re running the PowerShell version < 3.0 then you need to update it to 3.0.  You can check the version of the PowerShell by running the following command in the shell.

$PSVersionTable.PSVersion

The ScreenShot above displays a PowerShell of version 3.0. You may get version 2.0 or if you can also get an error message stating, that the variable does not exist then, it is safe to assume that the engine is version 1.0. If your engine is 3.0 or higher you can skip this segment.

Next, download the latest Windows Update from the url, http://www.microsoft.com/en-us/download/details.aspx?id=34595 and install it.

Install Instructions:
To install Windows Management Framework 3.0:
1.    Download the correct package for your operating system and architecture.

  • Windows 7 Service Pack 1
  • 64-bit versions: Windows6.1-KB2506143-x64.msu
  • 32-bit versions: Windows6.1-KB2506143-x86.msu
  • Windows Server 2008 R2 SP1
  • 64-bit versions: Windows6.1-KB2506143-x64.msu
  • Windows Server 2008 Service Pack 2
  • 64-bit versions: Windows6.0-KB2506146-x64.msu
  • 32-bit versions: Windows6.0-KB2506146-x86.msu

2.    Close all Windows PowerShell windows.
3.    Uninstall any other versions of Windows Management Framework 3.0.
4.    Run the MSU file that you downloaded.
For information about troubleshooting the installation, see the Release Notes.

To uninstall Windows Management Framework 3.0:
5.    In Control Panel/Programs/Uninstall a program/View installed updates, locate and uninstall the following installed Windows Update:

  • KB2506143 – for Windows 7 SP1 and Windows Server 2008 R2 SP1
  • KB2506146 – for Windows Server 2008 SP2

SharePoint Online Management Shell

Download and install SharePoint Online Management Shell from the url, http://www.microsoft.com/en-us/download/details.aspx?id=35588 

Run the Shell

Open the SharePoint Online Management Shell

And type the command Connect-MsolService and press enter. If everything is fine then, you’ll be shown the following screen

Otherwise, the following error message will be displayed!

Fix the Issue to run Connect-MsolService, PowerShell command

If you can run the command, Connect-MsolService, then everything is fine and you can skip this step and run your commands successfully.

To successfully run the Connect-MsolService PowerShell command, you need to:
1.    Find out what bitness your operating system is (x86 / 32-bit OR x64 / 64-bit). See Microsoft’s “Is my PC running the 32-bit or 64-bit version of Windows?” article for help.
2.    If necessary, install the appropriate bitness version of PowerShell 3.0 (which I hope we just did already)
Note 1: Windows6.0 is Windows Vista and Windows6.1 is Windows 7
Note 2: If you get a message of “The update is not applicable to your computer.” during the install then either you downloaded the wrong version of you already have it installed
3.    Install the appropriate bitness version of the Microsoft Online Services Sign-In Assistant for IT Professionals
4.    Install the appropriate bitness version of the Windows Azure Active Directory Module for Windows PowerShell
Note: If you get an error of  “In order to install Windows Azure Active Directory Module for Windows PowerShell, you must have Microsoft Online Services Sign-In Assistant version 7.0 or greater installed on this computer.” and a resulting failed install, install the Microsoft Online Services Sign-In Assistant for IT Professionals BETA (you shouldn’t need to uninstall the normal version but I would recommend it).
5.    Run the appropriate bitness version of PowerShell
6.    Run the Import-Module MSOnline PowerShell command
7.    Finally, run the Connect-MsolService PowerShell command

You should now be able to see the login screen.
 

Finally, it’s done!!

[Edit]
It has been noted that on some machines, even though the command runs successfully directly from the PowerShell, the same cmdlet throws the “cmdlet not supported” error when trying to execute it from within a C# application. To tackle it:

Copy the folders called MSOnline and MSOnline Extended from
C:\Windows\System32\WindowsPowerShell\v1.0\Modules\ 

to the folder
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Modules\

And then in PS run the Import-Module MSOnline, and it will automatically get the modules.

Rename/Move an Existing SharePoint File using RPC C#

In this post, I am going to demonstrate how to rename an existing file using RPC. The code is along the same line as this one, https://realmpksharepoint.wordpress.com/2014/04/29/upload-large-files-to-the-sharepoint-documentlibrary-using-rpc-from-a-desktop-application-c/
public void RenamePage(string oldUrl, string newUrl)
{
    string requestUrl = this.ctx.Url + "/_vti_bin/_vti_aut/author.dll";
    string method = GetEncodedString("move document:15.0.0.4420");
    
    string serviceName = GetEncodedString(this.ctx.Web.ServerRelativeUrl);
    oldUrl = GetEncodedString(oldUrl);
    newUrl = GetEncodedString(newUrl);
    string urlList = GetEncodedString("[]");
    
    rpcCallString = "method={0}&service_name={1}&oldUrl={2}&newUrl={3}&url_list={4}&rename_option=findbacklinks&put_option=edit\n";

    rpcCallString = String.Format(rpcCallString, method, serviceName, oldUrl, newUrl, urlList).Replace("_", "%5f");

    HttpWebRequest wReq = WebRequest.Create(requestUrl) as HttpWebRequest;
    wReq.Method = "POST";

    wReq.Headers["Content"] = "application/x-vermeer-rpc";
    wReq.Headers["X-Vermeer-Content-Type"] = "application/x-vermeer-rpc";

    wReq.UserAgent = "FrontPage";
    wReq.UseDefaultCredentials = false;
    
    Uri targetSite = new Uri(this.ctx.Web.Url);
    SharePointOnlineCredentials spCredentials = (SharePointOnlineCredentials)this.ctx.Credentials;
    string authCookieValue = spCredentials.GetAuthenticationCookie(targetSite);
    wReq.CookieContainer = new CookieContainer();
    wReq.CookieContainer.Add(
        new Cookie("FedAuth",
            authCookieValue.TrimStart("SPOIDCRL=".ToCharArray()),
            String.Empty,
            targetSite.Authority));

    wReq.BeginGetRequestStream(new AsyncCallback(gotRequestStream), wReq);
}

private void gotRequestStream(IAsyncResult asynchronousResult)
{
    HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
    Stream requestStream = webRequest.EndGetRequestStream(asynchronousResult);
    List<byte> uploadData = new List<byte>();
    uploadData.AddRange(Encoding.UTF8.GetBytes(rpcCallString));
    
    byte[] fileData = uploadData.ToArray();
    requestStream.Write(fileData, 0, fileData.Length);
    requestStream.Close();
    webRequest.BeginGetResponse(new AsyncCallback(gotResponse), webRequest);
}

private void gotResponse(IAsyncResult asynchronousResult)
{
    HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
    HttpWebResponse webResponse = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult);
    Stream responseStream = webResponse.GetResponseStream();
    StreamReader reader = new StreamReader(webResponse.GetResponseStream());
    
    string responseString = String.Empty;
    responseString = reader.ReadToEnd();
    byte[] fileBuffer = Encoding.UTF8.GetBytes(responseString);
    responseStream.Close();
    reader.Close();
    webResponse.Close();
    
    if (responseString.IndexOf("\n
message=successfully"

) < 0)
    {
        throw new Exception(responseString);
    }
}

Now, let’s evaluate this.

  • Here we are using method “move document” and, “15.0.0.4420” is server extension version.
  • Service name is server relative URL of your site.
  • oldUrl is the current url of the page and newUrl is the new url to be set.
  • For authentication, we’re using the CookieContainer of HTTPWebRequest.

Here is the example of how will you call this upload method.

RenamePage("default.aspx", "defaultNew.aspx");

Here a utility method, GetEncodedString has been used here for encoding of string. Here it is for your reference.

public string GetEncodedString(string sourceString)
{
    if (!String.IsNullOrEmpty(sourceString))
    { 
        return HttpUtility.UrlEncode(sourceString).Replace(".", "%2e").Replace("_", "%5f");
    }
    else
    {
        return sourceString;
    }
}

Check out here to get some additional info about move document, http://msdn.microsoft.com/en-us/library/ms440627%28v=office.14%29.aspx.

Upload Large Files to the SharePoint DocumentLibrary using RPC from a Desktop Application C#

In one of my previous post, https://realmpksharepoint.wordpress.com/2014/01/19/upload-a-file-to-sharepoint-using-client-object-model/ , I had shown how we can upload documents to SharePoint using CSOM. Though, the client object model was working perfectly for smaller documents, it started throwing time-out errors when I tried to upload a file of size around 40MB (previously, I was uploading documents < 2MB).

So to upload large documents I am going to use RPC. RPC is an interprocess communication technique that allows client and server software to communicate. For more details of RPC you can visit WikiPedia and TechNet articles.

public void UploadFile(string currentWebUrl, string serviceName, string filePath, FileStream stream, string userDomainName)
{
    newFileData = null;
    newFileData = new byte[stream.Length];
    stream.Read(newFileData, 0, Convert.ToInt32(stream.Length));
    string requestUrl = currentWebUrl + "/_vti_bin/_vti_aut/author.dll";
    string method = GetEncodedString("put document:15.0.0.4420");
    serviceName = GetEncodedString("/" + serviceName);
    
    string putOption = "overwrite";
    string metaInfo = "[vti_modifiedby;SW|" + userDomainName + ";vti_author;SW|" + userDomainName + "]]";
    string comments = GetEncodedString("File uploaded using RPC call");
    string docDetails = String.Format("[document_name={0};meta_info={1}", filePath, metaInfo);
    docDetails = GetEncodedString(docDetails);
    rpcCallString = "method={0}&service_name={1}&document={2}&put_option={3}&comment={4}&keep_checked_out=false\n";
    rpcCallString = String.Format(rpcCallString, method, serviceName, docDetails, putOption, comments).Replace("_", "%5f");
    
    HttpWebRequest wReq = WebRequest.Create(requestUrl) as HttpWebRequest;
    wReq.Method = "POST";
    wReq.Headers["Content"] = "application/x-vermeer-urlencoded";
    wReq.Headers["X-Vermeer-Content-Type"] = "application/x-vermeer-urlencoded";
    wReq.UserAgent = "FrontPage";
    wReq.UseDefaultCredentials = false;
    
    Uri targetSite = new Uri(this.ctx.Web.Url);



//Get the credential for authentication
    SharePointOnlineCredentials spCredentials = (SharePointOnlineCredentials)this.ctx.Credentials;

//Retrieve the authentication cookie with the help of credentials
    string authCookieValue = spCredentials.GetAuthenticationCookie(targetSite);
    wReq.CookieContainer = new CookieContainer();
    wReq.CookieContainer.Add(
        new Cookie("FedAuth",
            authCookieValue.TrimStart("SPOIDCRL=".ToCharArray()),
            String.Empty,
            targetSite.Authority));

    wReq.BeginGetRequestStream(new AsyncCallback(gotRequestStream), wReq);
}

private void gotRequestStream(IAsyncResult asynchronousResult)
{
    HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
    Stream requestStream = webRequest.EndGetRequestStream(asynchronousResult);
    List<byte> uploadData = new List<byte>();
    uploadData.AddRange(Encoding.UTF8.GetBytes(rpcCallString));
    uploadData.AddRange(newFileData);
    
    byte[] fileData = uploadData.ToArray();
    requestStream.Write(fileData, 0, fileData.Length);
    requestStream.Close();
    webRequest.BeginGetResponse(new AsyncCallback(gotResponse), webRequest);
}

private void gotResponse(IAsyncResult asynchronousResult)
{
    HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
    HttpWebResponse webResponse = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult);
    Stream responseStream = webResponse.GetResponseStream();
    StreamReader reader = new StreamReader(webResponse.GetResponseStream());
    
    string responseString = String.Empty;
    responseString = reader.ReadToEnd();
    byte[] fileBuffer = Encoding.UTF8.GetBytes(responseString);
    responseStream.Close();
    reader.Close();
    webResponse.Close();
    
    if (responseString.IndexOf("\n
message=successfully"

) < 0)
    {
        //Indicates that the SharePoint has returned an error message. The document might have got uploaded also so one should better check the message first.
        throw new Exception(responseString);
    }
}

Now, let’s evaluate this.

  • Here we are using the method, “put document” and, “15.0.0.4420” is server extension version.
  • Service name is server relative URL of your site.
  • In document parameter we are providing to fields “document_name” and “meta_info”. Document name is the path at which we want to upload the file including the file name and meta info sets the metadata of the document to be uploaded. MetaInfo is a system site-column where SharePoint stores custom values related to that particular ListItem.
  • Next parameter is put_option where you can provide “overwrite” if you want to overwrite existing file with same name else you can provide “edit”.
  • Next two parameters comment and keep_checked_out are very straight forward.
  • For authentication, we’re using the CookieContainer of HTTPWebRequest.

In case of RPC calls it is confusing how to pass parameters, mostly in case of file paths. So here is the example of how will you call this upload method.

UploadFile("http://myserver/sites/teamsite/", "sites/teamsite", "Shared Documents/document1.docx", fileStream, "Piyush Singh");

One utility method has been used here for encoding of string. Here it is for the reference.

public string GetEncodedString(string sourceString)
{
    if (!String.IsNullOrEmpty(sourceString))
    { 
        return HttpUtility.UrlEncode(sourceString).Replace(".", "%2e").Replace("_", "%5f");
    }
    else
    {
        return sourceString;
    }
}

You can get more info about put document here, http://msdn.microsoft.com/en-us/library/ms479623.aspx.

It has been said that in this way we can upload document up to 2GB to the site. Well, I have tested it for the documents of size little over 100MB and it’s working fine.

Also, you can visit the following post to upload files up to 10GB to SharePoint Online,

https://realmpksharepoint.wordpress.com/2016/07/22/upload-large-files-to-sharepoint-online/.

Add a new User to the User Information List from the Office365 Active User Panel using Client Object Model C#

This post is about a hidden List of SharePoint, User Information List. In this, the items are the active Office365 users, that have some interaction with this site. For ex. if a user has visited the site, or, the user has been marked in one of the List [like assigned a Task] of the site, or, the user is the administrator then, the user gets automatically added to this List.

By default, the site’s administrator is the only added user to this List. So, if you assign say, a task, to an active user from the Office365 user panel, then, SharePoint automatically adds the user in the User Information List. In my one of the earlier post, https://realmpksharepoint.wordpress.com/2014/01/19/update-a-usermulti-column-value-in-client-object-model-c/, I had demonstrated how to update a UserField SiteColumn say, Attendees for a Calendar item[meeting], with the user id from the web’s SiteUsers. However, we only get the users from the User Information List as the SiteUsers in CSOM.

So how to add a new active user to this List using CSOM? The answer is the EnsureUser method.
It adds the valid user to the site if it’s not already added.

User user = clientContext.Web.EnsureUser("Piyush Singh");
clientContext.Load(user);
clientContext.ExecuteQuery();