7

I have been trying out to create site collection using CSOM but unable to fins and class which creates site collection.

I have read in MSDN that CSOM runs as site collection scope hence creating site collection permission is not available.

Sub-Site i am able to create properly but unable to create site collection.

Rahul Barua
  • 329
  • 2
  • 7
  • 14

4 Answers4

5

Tenant.CreateSite method queues a site collection for creation with the specified properties. Tenant class is a part of Microsoft.Online.SharePoint.Client.Tenant.dll (SharePoint Online Management Shell)

How to create site collection via CSOM in SharePoint 2013

using System;
using System.Security;
using Microsoft.Online.SharePoint.TenantAdministration;
using Microsoft.SharePoint.Client;

namespace CSOMProvisioning
{
    class Program
    {
        static void Main(string[] args)
        {

            const string username = "username@contoso.onmicrosoft.com";
            const string password = "password";
            const string tenantAdminUrl = "https://contoso-admin.sharepoint.com/";
            var securedPassword = new SecureString();
            foreach (var c in password.ToCharArray()) securedPassword.AppendChar(c);
            var credentials = new SharePointOnlineCredentials(username, securedPassword);



            using (var context = new ClientContext(tenantAdminUrl))
            {
                context.Credentials = credentials;
                CreateSite(context, "https://contoso.sharepoint.com/sites/marketing","Marketing");
            }

        }


        /// <summary>
        /// Create a new site.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="url">rootsite + "/" + managedPath + "/" + sitename: e.g. "https://auto.contoso.com/sites/site1"</param>
        /// <param name="title">site title: e.g. "Test Site"</param>
        /// <param name="owner">site owner: e.g. admin@contoso.com</param>
        /// <param name="template">The site template used to create this new site</param>
        /// <param name="localeId"></param>
        /// <param name="compatibilityLevel"></param>
        /// <param name="storageQuota"></param>
        /// <param name="resourceQuota"></param>
        /// <param name="timeZoneId"></param>
        internal static void CreateSite(ClientContext context, String url, String owner, String title =null, String template = null, uint? localeId = null, int? compatibilityLevel = null, long? storageQuota = null, double? resourceQuota = null, int? timeZoneId = null)
        {
            var tenant = new Tenant(context);

            if (url == null)
                throw new ArgumentException("Site Url must be specified");

            if (string.IsNullOrEmpty(owner))
                throw new ArgumentException("Site Owner must be specified");

            var siteCreationProperties = new SiteCreationProperties {Url = url, Owner = owner};
            if (!string.IsNullOrEmpty(template))
                siteCreationProperties.Template = template;
            if (!string.IsNullOrEmpty(title))
                siteCreationProperties.Title = title;
            if (localeId.HasValue)
                siteCreationProperties.Lcid = localeId.Value;
            if (compatibilityLevel.HasValue)
                siteCreationProperties.CompatibilityLevel = compatibilityLevel.Value;
            if (storageQuota.HasValue)
                siteCreationProperties.StorageMaximumLevel = storageQuota.Value;
            if (resourceQuota.HasValue)
                siteCreationProperties.UserCodeMaximumLevel = resourceQuota.Value;
            if (timeZoneId.HasValue)
                siteCreationProperties.TimeZoneId = timeZoneId.Value;
            var siteOp = tenant.CreateSite(siteCreationProperties);
            context.Load(siteOp);
            context.ExecuteQuery();

        }



    }
}
Vadim Gremyachev
  • 42,498
  • 3
  • 86
  • 167
3

I know you asked for CSOM, but in case it helps anyone, I was able to do this in PowerShell using the CreateSite method of the Admin web service against on-prem SP2013. You can call DeleteSite similarly (it's simpler as it has only one parameter). I started out down the route of creating a tenant administration site for my on-prem SP2013 but was having authentication issues. This was a good fallback approach for me (does everything I need it to).

The inputs to the script are as follows:

  • $user - farm admin login (I am also using this as the owner of the new site collection)
  • $pwd - farm admin pwd
  • $adminSiteUrl - central admin site URL (must be accessible from the box where this script is running)
  • $siteUrl - the full URL of the new site collection to be created
  • $siteTitle - the title of the new site collection
  • $username - the display name of the new site collection owner

Here's the PowerShell:

$securePwd = ConvertTo-SecureString $pwd -AsPlainText -Force
$cred = New-Object PSCredential($user, $securePwd)
$wsdlUrl = $adminSiteUrl + "/_vti_adm/Admin.asmx?WSDL"
$svc = New-WebServiceProxy -Uri $wsdlUrl -Credential $cred
$svc.CreateSite(
    $siteUrl,   # URL
    $siteTitle, # Title
    "",         # Description
    1033,       # LCID
    "STS#0",    # WebTemplate
    $user,      # Owner Login
    $userName,  # Owner Name
    "",         # Owner Email
    "",         # PortalUrl
    "")         # PortalName
Kirk Liemohn
  • 1,423
  • 2
  • 18
  • 35
3

This example is taken from a SharePoint Online environment with provided hosted apps in mind. Creating a console application, adding reference to

  • Microsoft.SharePoint.Client.dll
  • Microsoft.SharePoint.Client.Runtime.dll
  • Microsoft.Online.SharePoint.Client.Tenant.dll

and pasting this snippet to the main method should do the trick.

var SHAREPOINT_PID = "00000003-0000-0ff1-ce00-000000000000"; // SharePoint constant
var tenantAdminUri = new Uri("https://<TENANT>-admin.sharepoint.com");
var token = TokenHelper.GetAppOnlyAccessToken(SHAREPOINT_PID, tenantAdminUri.Authority, null).AccessToken;

using (var context = TokenHelper.GetClientContextWithAccessToken(tenantAdminUri.ToString(), token))
{
    var tenant = new Tenant(context);
    var properties = new SiteCreationProperties()
    {
        Url = "https://<TENANT>.sharepoint.com/sites/site1",
        Owner = "<USER>@<TENANT>.onmicrosoft.com",
        Template = "STS#0",
        StorageMaximumLevel = 1000,
        UserCodeMaximumLevel = 300
    };
    tenant.CreateSite(properties);

    context.Load(tenant);
    context.ExecuteQuery();
}

In this example I’ve created a simple console application but it might as well be a service running in Azure or any other .NET application.

Reference: Create Site Collections in SharePoint Online using CSOM

Benny Skogberg
  • 25,542
  • 12
  • 68
  • 163
1

They said on prem and CSOM. None of the answers here are what he asked.

Here are some methods that do what we need:

HttpWebRequest CreateSoapWebRequest() {
  HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(adminUrl + "/_vti_adm/Admin.asmx");
  webRequest.Headers.Add("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/CreateSite");
  webRequest.ContentType = "text/xml; charset=\"utf-8\"";
  webRequest.Method = "POST";
  webRequest.Credentials = new NetworkCredential(username, password);
  return webRequest;
}

XmlDocument CreateSoapEnvelope(string url, string title, string description, string user, string lcid, string webTemplate) {
  XmlDocument soapEnvelopeDocument = new XmlDocument();
  string soapEnv = string.Format(@"<?xml version=""1.0"" encoding=""utf-8""?>
    <soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/""
                   xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
      <soap:Body>
        <CreateSite xmlns=""http://schemas.microsoft.com/sharepoint/soap/"">
          <Url>{0}</Url>
          <Title>{1}</Title>
          <Description>{2}</Description>
          <Lcid>{3}</Lcid>
          <WebTemplate>{4}</WebTemplate>
          <OwnerLogin>{5}</OwnerLogin>
          <OwnerName>{6}</OwnerName>
          <OwnerEmail/>
          <PortalUrl/>
          <PortalName/>
        </CreateSite>
      </soap:Body>
    </soap:Envelope>", url, title, description, lcid, webTemplate, user, user);
  Console.WriteLine("Create site collection soap request: {0}", soapEnv);
  soapEnvelopeDocument.LoadXml(soapEnv);
  return soapEnvelopeDocument;
}

void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest) {
  using (Stream stream = webRequest.GetRequestStream()) {
    soapEnvelopeXml.Save(stream);
  }
}

And you can use the code like this:

XmlDocument soapEnvelopeXml = CreateSoapEnvelope(
        yourUrl,
        yourTitle,
        yourDescription,
        yourUser,
        yourLcid,
        yourWebTemplate
      );
      HttpWebRequest webRequest = CreateSoapWebRequest();
      InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);
      IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);

      asyncResult.AsyncWaitHandle.WaitOne();

      using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult)) {
        using (StreamReader rd = new StreamReader(webResponse.GetResponseStream())) {
          Console.WriteLine(rd.ReadToEnd());
        }
      }
Nicholas DiPiazza
  • 717
  • 2
  • 16
  • 42