I'm struggeling to understand how to use SharePoint CSOM to add a user as Site Collection Admin.
So far this code works for a Global Admin to add a user as Site Colleciton Admin, eventhough the Global Admin is not included as Site Admin.
I've tried to run the code as normal user which is only Site Collection Admin, to add another user as Site Colleciton Admin. But then I get some errors:
If I use the SharePoint Admin URL to get the Access Token, then the code crash on row #48 as 401 "Unauthorized"
If I use the Site Collection URL to get the Access Token, I get error when trying to get the acces token saying that Site is doesn't exist on the environment.
If I use the root site URL ("https://domain-admin.sharepoint.com/) to get the Access Token, then the code crash on row #51 as 401 "Unauthorized".
I'm using the PnP.PowerShell code as reference: https://github.com/pnp/powershell/blob/dev/src/Commands/Admin/SetTenantSite.cs#L547-L574
And my process is pretty much the same as here: MSAL AD token not valid with SharePoint Online CSOM
But I don't have clear if it's a issue of access token or the CSOM commands I use.
Does anyone has any idea how to move forward?
btw, I guess if I use the Global Admin account I only need to use tenant.SetSiteAdmin(siteCollection, userEmail, true);. I read somewhere that even for global admin I need EnsureUser(userEmail);, but so far the code seems working without it.
using Microsoft.Identity.Client;
using Microsoft.SharePoint.Client;
namespace ScriptTester
{
internal class Program
{
static async Task Main(string[] args)
{
await AddUserAdmin();
}
public static async Task AddUserAdmin()
{
string siteAdmin = "https://domain-admin.sharepoint.com/";
string siteRoot = "https://domain.sharepoint.com/";
string siteCollection = "https://domain.sharepoint.com/sites/SiteName/";
string userEmail = "_email";
string accessToken = await GetAccessToken(siteRoot);
using (var context = new Microsoft.SharePoint.Client.ClientContext(siteRoot))
{
context.ExecutingWebRequest += (sender, e) =>
{
e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + accessToken;
};
var tenant = new Microsoft.Online.SharePoint.TenantAdministration.Tenant(context);
try
{
addLog("Try using tenant context");
tenant.SetSiteAdmin(siteCollection, userEmail, true);
tenant.Context.ExecuteQueryRetry();
}
catch (Exception ex)
{
addLog("Failed using Tenant context");
addLog(ex.Message);
using (var site = tenant.Context.Clone(siteCollection))
{
var user = site.Web.EnsureUser(userEmail);
user.Update();
user.IsSiteAdmin= true;
site.Load(user);
site.ExecuteQueryRetry();
tenant.SetSiteAdmin(siteCollection, userEmail, true);
tenant.Context.ExecuteQueryRetry();
}
}
}
}
public static async Task<string> GetAccessToken(string siteUrl)
{
string tenantId = "xxxx-xxxx-xxxx-xxxx-xxx";
string clientId = "xxxx-xxxx-xxxx-xxxx-xxx";
Uri authority = new Uri($"https://login.microsoftonline.com/{tenantId}");
string redirectUri = "http://localhost";
string defaultPermissions = siteUrl + "/.default";
string[] scopes = new string[] { defaultPermissions };
var app = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(authority)
.WithRedirectUri(redirectUri)
.Build();
AuthenticationResult result;
result = await app.AcquireTokenInteractive(scopes)
.WithUseEmbeddedWebView(false)
.ExecuteAsync();
return result.AccessToken;
}
}
}