5 minute read

Introduction

In this post, we’ll explore how to create SharePoint Online Classic Team Sites using C#, WinForms, and the Microsoft Authentication Library (MSAL) to support Multi-Factor Authentication (MFA). With MFA becoming a standard security measure, we’ll walk through how to integrate it into your SharePoint team site creation process. You can find the complete source code for this project on GitHub.

Running Project

Prerequisites

  1. Microsoft.SharePointOnline.CSOM: For interacting with SharePoint Online.
  2. Microsoft.Identity.Client (MSAL): For handling authentication with MFA.
  3. Azure AD App Registration: You need to register an app in Azure Active Directory to enable authentication. Ensure you have the Client ID and Tenant ID for this app, and appropriate permissions for SharePoint Online.

Project Setup

  1. Create a Windows Forms Application project in Visual Studio.
  2. Install the required NuGet packages:
    Install-Package Microsoft.SharePointOnline.CSOM
    Install-Package Microsoft.Identity.Client
    
  3. Add basic WinForms controls to allow input for Admin URL, Tenant ID, Client ID, Site Name, Owner, and Description.

The Code

Main Form Code (WinForms)

The main form collects the necessary details (like tenant admin URL, tenant ID, client ID, etc.) and triggers the creation process when a button is clicked.

using System;
using Form = System.Windows.Forms.Form;

namespace SharePointTeamSiteCreator
{
    public partial class Form1 : Form
    {
        private const string SiteTemplate = "STS#0"; // STS#0 is the template for a classic team site
        private const uint SiteLanguage = 1033; // English
        private const int SiteStorageQuota = 1000; // Storage quota in MB
        private const int SiteUserCodeQuota = 0; // User code quota (usually 0 unless required)

        public Form1()
        {
            InitializeComponent();
        }

        // Button click event to create the Team Site
        private async void btnCreateSite_Click(object sender, EventArgs e)
        {
            // Get user input from form fields
            var adminSiteUrl = txtAdminSiteUrl.Text; // Tenant admin url
            var tenantId = txtTenantId.Text; // Azure AD Tenant ID
            var clientId = txtClientId.Text; // Azure AD Client ID
            var siteDisplayName = txtSiteDisplayName.Text; // Desired Team Site name
            var siteOwner = textSiteOwner.Text; // Desired Team Site owner
            var siteDescription = txtSiteDescription.Text; // Site Description
            var siteUrl = adminSiteUrl.Replace("-admin", null) + "/sites/" +
                          siteDisplayName.Replace(" ", string.Empty).ToLower();

            await SharePointUtils.CreateTeamSiteAuthentication(adminSiteUrl, tenantId, clientId, SiteStorageQuota, SiteUserCodeQuota, siteDisplayName, siteOwner, siteUrl, SiteTemplate, SiteLanguage);
        }
    }
}

Utility Class for SharePoint Site Creation

This utility class handles the interaction with SharePoint Online, using MSAL for authentication and CSOM for creating the team site.

using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.SharePoint.Client;
using Microsoft.Online.SharePoint.TenantAdministration;
using Microsoft.Identity.Client;

namespace SharePointTeamSiteCreator
{
    /// <summary>
    /// Utility class that provides methods for SharePoint Online site creation using the Client-Side Object Model (CSOM)
    /// and Multi-Factor Authentication (MFA) via Microsoft Authentication Library (MSAL).
    /// </summary>
    internal static class SharePointUtils
    {
        /// <summary>
        /// Creates a new SharePoint Online Classic Team Site using Client-Side Object Model (CSOM) and MFA.
        /// The method uses Microsoft Identity Client (MSAL) for authentication and creates the site using the 
        /// Tenant administration API.
        /// </summary>
        /// <param name="adminSiteUrl">The SharePoint Online admin site URL.</param>
        /// <param name="tenantId">The Azure Active Directory Tenant ID.</param>
        /// <param name="clientId">The Azure AD app registration Client ID.</param>
        /// <param name="siteStorageQuota">The storage quota in MB for the new site.</param>
        /// <param name="siteUserCodeQuota">The user code quota for the new site.</param>
        /// <param name="siteTitle">The title for the new SharePoint site.</param>
        /// <param name="siteOwner">The owner of the new SharePoint site.</param>
        /// <param name="siteUrl">The URL for the new SharePoint site.</param>
        /// <param name="template">The template for the site (e.g., STS#0 for a classic team site).</param>
        /// <param name="siteLanguage">The language locale ID for the site (default is 1033 for English).</param>
        /// <returns>A Task representing the asynchronous site creation operation.</returns>
        internal static async Task CreateTeamSiteAuthentication(string adminSiteUrl, string tenantId, string clientId,
            long siteStorageQuota, long siteUserCodeQuota, string siteTitle, string siteOwner, string siteUrl,
            string template = "STS#0", uint siteLanguage = 1033)
        {
            var scopes = new string[] { adminSiteUrl + "/.default" }; // Scopes


            var app = GetPublicClientApp(tenantId, clientId);
            AuthenticationResult authResult = null;
            try
            {
                // Use interactive authentication to sign in
                authResult = await app.AcquireTokenInteractive(scopes).ExecuteAsync().ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                MessageBox.Show(@"Error acquiring token: " + ex.Message, Application.ProductName, MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                return;
            }

            // Access token retrieved
            var accessToken = authResult.AccessToken;

            try
            {
                // Create a new ClientContext using the access token for MFA
                using (var clientContext = new ClientContext(adminSiteUrl))
                {
                    clientContext.ExecutingWebRequest += (sender, webRequestEventArgs) =>
                    {
                        webRequestEventArgs.WebRequestExecutor.RequestHeaders["Authorization"] =
                            "Bearer " + accessToken;
                    };

                    // Tenant object to manage site creation
                    var tenant = new Tenant(clientContext);

                    var siteCreationInfo = new SiteCreationProperties
                    {
                        Url = siteUrl,
                        Title = siteTitle,
                        Lcid = siteLanguage, // Locale ID for English
                        Template = template, // Web Template for classic team site
                        Owner = siteOwner,
                        StorageMaximumLevel = siteStorageQuota,
                        UserCodeMaximumLevel = siteUserCodeQuota
                    };

                    var spoOperation = tenant.CreateSite(siteCreationInfo);
                    clientContext.Load(spoOperation, i => i.IsComplete);
                    clientContext.ExecuteQuery();
                    // Check the operation status
                    while (!spoOperation.IsComplete)
                    {
                        Console.WriteLine(@"Creating site... Please wait");
                        System.Threading.Thread.Sleep(10000); // Wait for 30 seconds
                        spoOperation.RefreshLoad();
                        clientContext.ExecuteQuery();
                    }

                    MessageBox.Show(@"Site has been created successfully.", Application.ProductName,
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(@"Error: " + ex.Message, Application.ProductName, MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Configures and returns a PublicClientApplication object for MSAL authentication.
        /// This method sets the authority and client ID for authentication.
        /// </summary>
        /// <param name="tenantId">The Azure Active Directory Tenant ID.</param>
        /// <param name="clientId">The Azure AD app registration Client ID.</param>
        /// <returns>An IPublicClientApplication object used for acquiring authentication tokens.</returns>
        private static IPublicClientApplication GetPublicClientApp(string tenantId, string clientId)
        {
            try
            {
                var tenant = string.IsNullOrEmpty(tenantId) ? "common" : tenantId;
                var authorityUri = $"https://login.microsoftonline.com/{tenant}";
                var clientApp = PublicClientApplicationBuilder.Create(clientId)
                    .WithAuthority(authorityUri)
                    .WithDefaultRedirectUri()
                    .Build();
                return clientApp;
            }
            catch (Exception ex)
            {
                MessageBox.Show(@"Error: " + ex.Message, Application.ProductName, MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                throw;
            }
        }
    }
}

Explanation

  • Authentication with MFA: The application uses MSAL (Microsoft Identity Client) to perform interactive authentication. This ensures that Multi-Factor Authentication (MFA) is handled during login, improving security.

  • Site Creation Process: Once authenticated, the application uses the ClientContext object from the CSOM API to communicate with SharePoint Online. The Tenant.CreateSite method creates the classic team site based on the input provided by the user.

  • Status Checking: The application continuously checks if the site creation process has been completed by polling the server until the operation is marked as complete.

Conclusion

In this tutorial, we’ve walked through how to create SharePoint Online Classic Team Sites using C#, WinForms, and MSAL for MFA. This approach ensures that your SharePoint operations are secure and comply with modern authentication standards.

This solution is flexible and can be adapted to handle other types of SharePoint site creation and management tasks. Happy coding!

Leave a comment