using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Text.RegularExpressions; using System.Runtime.CompilerServices; using C4IT.Logging; using C4IT.MsGraph; using static C4IT.Logging.cLogManager; using C4IT.Matrix42.ServerInfo; using static C4IT.MsGraph.cMsGraphSharepoint; namespace C4IT.LIAM { public static class LiamInitializer { public static Guid msTeamsModuleId = new Guid("2591832a-1b25-ec11-6985-00155d300101"); static public cLiamProviderBase CreateInstance(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData) { return new cLiamProviderMsTeams(LiamConfiguration, ProviderData); } } public class cLiamProviderMsTeams : cLiamProviderBase { public readonly cMsGraphSharepoint MsSharepoint = new cMsGraphSharepoint(new cMsGraphBase()); public const string allowedMailNickNameCharacter = @"[^A-Za-z0-9!#$%&'*+\-/=?^_`{|}~]"; public readonly bool WithoutPrivateChannels = true; public cLiamProviderMsTeams(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData) : base(LiamConfiguration, ProviderData) { WithoutPrivateChannels = AdditionalConfiguration.ContainsKey("WithoutPrivateChannels") ? AdditionalConfiguration["WithoutPrivateChannels"].ToLower() == "true" || AdditionalConfiguration["WithoutPrivateChannels"] == "1" : false; } public override async Task LogonAsync() { return await LogonAsync(true); } public async Task LogonAsync(bool force = false) { if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return false; } if (!force && this.MsSharepoint.Base.IsOnline) return true; var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var LI = new cMsGraphLogonInfo() { Tenant = this.Domain, ClientID = this.Credential?.Identification, ClientSecret = this.Credential?.Secret }; var RetVal = await MsSharepoint.Base.LogonAsync(LI); return RetVal; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return false; } public override async Task> getDataAreasAsync(int Depth = -1) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!await LogonAsync()) return null; var DataAreas = new List(); var DAL = await MsSharepoint.RequestTeamsListAsync(); if (DAL == null) return null; foreach (var Entry in DAL) { if (!string.IsNullOrEmpty(this.DataAreaRegEx) && !Regex.Match(Entry.Key, this.DataAreaRegEx).Success) continue; var MsTeam = await MsSharepoint.RequestGroupInfoAsync(Entry.Value); if (MsTeam == null) continue; var Team = new cLiamMsTeamsTeam(this, MsTeam); DataAreas.Add(Team); } if (Depth > 0) { var allChilds = new List(); foreach (var Entry in DataAreas) { var entryChilds = await (Entry as cLiamMsTeamsTeam).getChannels(true); if (entryChilds != null && entryChilds.Count > 0) allChilds.AddRange(entryChilds); } DataAreas.AddRange(allChilds); } return DataAreas; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return null; } public override async Task LoadDataArea(string UID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return null; } var lstIds = UID.Split('|'); switch (lstIds.Length) { case 4: var FO = await cLiamMsTeamsFolder.Load(this, UID); return FO; case 2: var CH = await cLiamMsTeamsChannel.Load(this, UID); return CH; case 1: var TM = await cLiamMsTeamsTeam.Load(this, UID); return TM; } return null; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } public static string getUidItem(ref string UID) { try { var p = UID.IndexOf('|'); if (p >= 0) { var Item = UID.Substring(0, p); UID = UID.Remove(0, p + 1); UID = UID.TrimStart(); return Item.Trim(); } } catch { }; var h2 = UID; UID = ""; return h2; } public static cMsGraphResultPermission.ePermissionRole getMsGraphRole(eLiamAccessRoles LiamRole) { switch (LiamRole) { case eLiamAccessRoles.Owner: return cMsGraphResultPermission.ePermissionRole.owner; case eLiamAccessRoles.Write: return cMsGraphResultPermission.ePermissionRole.write; default: return cMsGraphResultPermission.ePermissionRole.read; } } public static eLiamAccessRoles getLiamRole(cMsGraphResultPermission.ePermissionRole MsGraphRole) { switch (MsGraphRole) { case cMsGraphResultPermission.ePermissionRole.owner: return eLiamAccessRoles.Owner; case cMsGraphResultPermission.ePermissionRole.write: return eLiamAccessRoles.Write; default: return eLiamAccessRoles.Read; } } public override Task> getSecurityGroupsAsync(string groupFilter) { throw new NotImplementedException(); } public override string GetLastErrorMessage() { throw new NotImplementedException(); } public async Task cloneTeam(string teamId, string name, string description, int visibility, int partsToClone, string additionalMembers, string additionalOwners) { var request = new CloneTeamRequest() { DisplayName = name, Visibility = (CloneTeamRequest.TeamVisibilityType)visibility, MailNickname = Regex.Replace(name, allowedMailNickNameCharacter, ""), Description = description }; request.SetClonableParts((CloneTeamRequest.ClonableTeamParts)partsToClone); var res = await MsSharepoint.CloneTeam(teamId, request); return res; } } public class cLiamMsTeamsTeam : cLiamDataAreaBase { public new readonly cLiamProviderMsTeams Provider = null; private readonly cMsGraphResultGroup MsTeam = null; public cLiamMsTeamsTeam(cLiamProviderMsTeams Provider, cMsGraphResultGroup MsTeam) : base(Provider) { this.Provider = Provider; this.MsTeam = MsTeam; this.TechnicalName = getUID(MsTeam.ID); this.DisplayName = MsTeam.DisplayName; this.Level = 0; this.UID = getUID(MsTeam.ID); this.ParentUID = ""; this.DataType = eLiamDataAreaTypes.MsTeamsTeam; this.SupportsOwners = true; this.SupportsPermissions = true; } internal static string getUID(string TeamID) { return $"{TeamID}"; } internal async Task> getChannels(bool OnlyPrivate) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (MsTeam == null) return null; var RegExFilter = this.Provider?.DataAreaRegEx; var SP = this.Provider?.MsSharepoint; var WithoutPrivateChannels = this.Provider?.WithoutPrivateChannels ?? false; if (MsTeam.Channels == null) if (SP == null || !await MsTeam.ResolveChannels(SP, OnlyPrivate)) return null; var RetVal = new List(MsTeam.Channels.Count); foreach (var Entry in MsTeam.Channels.Values) { if (!string.IsNullOrEmpty(RegExFilter) && !Regex.Match(Entry.DisplayName, RegExFilter).Success) continue; if (WithoutPrivateChannels && !string.IsNullOrEmpty(Entry.MembershipType) && Entry.MembershipType == "private") continue; var DA = new cLiamMsTeamsChannel(Provider, this, Entry); RetVal.Add(DA); } return RetVal; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } public override async Task> getChildrenAsync(int Depth = -1) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return null; } var RetVal = await getChannels(false); if (RetVal != null) RetVal.AddRange(await getChildrenFromListAsync(RetVal, Depth)); return RetVal; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } public static async Task Load(cLiamProviderMsTeams Provider, string UID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var arrIDs = UID.Split('|'); if (arrIDs.Length != 1) return null; var TeamID = cLiamProviderMsTeams.getUidItem(ref UID); var T = await Provider.MsSharepoint.RequestGroupInfoAsync(TeamID); if (T == null) return null; var RetVal = new cLiamMsTeamsTeam(Provider, T); return RetVal; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } public override async Task> GetOwnersAsync() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { return await GetMembersAsync(true); } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } private async Task> GetMembersAsync(bool owners) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return null; } var SP = this.Provider?.MsSharepoint; if (SP == null) { LogEntry($"Could not get Sharepoint class from Provider for Team '{this.TechnicalName}'", LogLevels.Warning); return null; } cMsGraphCollectionUsers lstMembers; if(owners) lstMembers = await MsTeam.GetOwnersAsync(SP); else lstMembers = await MsTeam.GetMembersAsync(SP); if (lstMembers == null) { LogEntry($"Could not get owner list for Team '{this.TechnicalName}'", LogLevels.Warning); return null; } var RetVal = new List(lstMembers.Count); LogEntry($"Owners for Team found: {lstMembers.Count}", LogLevels.Debug); foreach (var MemberEntry in lstMembers.Values) { var User = new cLiamUserInfo() { DisplayName = MemberEntry.DisplayName, GivenName = MemberEntry.GivenName, SurName = MemberEntry.SurName, UserPrincipalName = MemberEntry.UserPrincipalName, EMail = MemberEntry.EMail, SID = null }; RetVal.Add(User); } return RetVal; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } public override async Task> GetPermissionsAsync(bool force = false) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return null; } var RetVal = new List(); var owners = await GetOwnersAsync(); foreach ( var owner in owners) { var permission = new cLiamPermissionInfo() { User = owner, AccessRole = eLiamAccessRoles.Owner }; RetVal.Add(permission); } var members = await GetMembersAsync(false); foreach (var member in members) { var permission = new cLiamPermissionInfo() { User = member, AccessRole = eLiamAccessRoles.Write }; RetVal.Add(permission); } return RetVal; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return null; } public override async Task GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return null; } var result = new cLiamPermissionResult(); if (Role == eLiamAccessRoles.Read) { return result; } try { var Roles = new List() { cLiamProviderMsTeams.getMsGraphRole(Role) }; var UserInfo = await Provider.MsSharepoint.RequestUserInfoAsync(User.UserPrincipalName); if(string.IsNullOrEmpty(UserInfo?.ID)) { LogEntry($"Could not find user {User.UserPrincipalName}", LogLevels.Error); return null; } var retVal = await Provider.MsSharepoint.AddGroupMembership(MsTeam, false, UserInfo); if(Role == eLiamAccessRoles.Owner) retVal = await Provider.MsSharepoint.AddGroupMembership(MsTeam, true, UserInfo); result.Valid = retVal; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return result; } public override async Task RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return false; } if (Role == eLiamAccessRoles.Read) { return false; } try { var Roles = new List() { cLiamProviderMsTeams.getMsGraphRole(Role) }; var UserInfo = await Provider.MsSharepoint.RequestUserInfoAsync(User.UserPrincipalName); if (string.IsNullOrEmpty(UserInfo?.ODataId)) { LogEntry($"Could not find user {User.UserPrincipalName}", LogLevels.Error); return false; } bool retVal = false; if (Role == eLiamAccessRoles.Owner) { retVal = await Provider.MsSharepoint.DeleteGroupMembership(MsTeam, true, UserInfo); retVal &= await Provider.MsSharepoint.DeleteGroupMembership(MsTeam, false, UserInfo); } if (Role == eLiamAccessRoles.Write) { var members = await Provider.MsSharepoint.RequestGroupOwnersAsync(MsTeam.ID, UserInfo.ID); if(members == null || members.Count == 0) { retVal = await Provider.MsSharepoint.DeleteGroupMembership(MsTeam, false, UserInfo); } } return retVal; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return false; } } public class cLiamMsTeamsChannel : cLiamDataAreaBase { public new readonly cLiamProviderMsTeams Provider = null; public readonly cMsGraphResultChannel MsChannel = null; public cLiamMsTeamsChannel(cLiamProviderMsTeams Provider, cLiamMsTeamsTeam Team, cMsGraphResultChannel MsChannel, string TeamUID = null) : base(Provider) { this.Provider = Provider; this.MsChannel = MsChannel; this.TechnicalName = getUID(MsChannel.ID, TeamUID ?? Team?.UID ?? "*"); this.DisplayName = MsChannel.DisplayName; this.Level = 1; this.UID = getUID(MsChannel.ID, TeamUID ?? Team?.UID ?? "*"); if (Team != null) this.ParentUID = Team.UID; this.DataType = eLiamDataAreaTypes.MsTeamsChannel; } internal static string getUID(string ChannelID, string TeamUID) { return $"{ChannelID} | {TeamUID}"; } public override async Task> getChildrenAsync(int Depth = -1) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return null; } if (MsChannel == null) return null; var RegExFilter = this.Provider?.DataAreaRegEx; var SP = this.Provider?.MsSharepoint; if (MsChannel.RootFolder == null) if (SP == null || !await MsChannel.ResolveRootFolder(SP)) return null; if (MsChannel.RootFolder.Folders == null) if (SP == null || !await MsChannel.RootFolder.ResolveFolders(SP)) return null; var DataAreas = new List(); foreach (var Entry in MsChannel.RootFolder.Folders.Values) { if (!string.IsNullOrEmpty(RegExFilter) && !Regex.Match(Entry.DisplayName, RegExFilter).Success) continue; var DA = new cLiamMsTeamsFolder(this, Entry); DataAreas.Add(DA); } DataAreas.AddRange(await getChildrenFromListAsync(DataAreas, Depth)); return DataAreas; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } public static async Task Load(cLiamProviderMsTeams Provider, string UID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var arrIDs = UID.Split('|'); if (arrIDs.Length != 2) return null; var ChannelID = cLiamProviderMsTeams.getUidItem(ref UID); var TeamID = cLiamProviderMsTeams.getUidItem(ref UID); var C = await Provider.MsSharepoint.RequestChannelInfo(TeamID, ChannelID); if (C == null) return null; var RetVal = new cLiamMsTeamsChannel(Provider, null, C, TeamID); return RetVal; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } } public class cLiamMsTeamsFolder : cLiamDataAreaBase { public new readonly cLiamProviderMsTeams Provider = null; public readonly cLiamMsTeamsChannel Channel = null; public readonly string ChannelUID = null; public readonly cMsGraphResultFileObject MsFolder = null; public cLiamMsTeamsFolder(cLiamMsTeamsChannel Channel, cMsGraphResultFileObject MsFolder) : this(Channel.Provider, Channel, Channel, MsFolder) { } public cLiamMsTeamsFolder(cLiamMsTeamsFolder ParentFolder, cMsGraphResultFileObject MsFolder) : this(ParentFolder.Channel.Provider, ParentFolder.Channel, ParentFolder, MsFolder) { } private cLiamMsTeamsFolder(cLiamProviderMsTeams Provider, cLiamMsTeamsChannel Channel, cLiamDataAreaBase ParentFolder, cMsGraphResultFileObject MsFolder, string ChannelUID = null) : base(Provider) { this.Channel = Channel; if (Channel == null) this.ChannelUID = ChannelUID; else this.ChannelUID = Channel.UID; this.Provider = Provider; this.MsFolder = MsFolder; this.TechnicalName = MsFolder.DisplayName; this.DisplayName = MsFolder.DisplayName; if (ParentFolder != null) { this.Level = ParentFolder.Level + 1; this.ParentUID = ParentFolder.UID; } this.UID = getUID(MsFolder.ID, MsFolder.DriveID, ChannelUID ?? Channel?.UID ?? "*|*"); this.DataType = eLiamDataAreaTypes.MsTeamsFolder; this.SupportsPermissions = true; } internal static string getUID(string FolderID, string DriveID, string ChannelUID) { return $"{FolderID} | {DriveID} | {ChannelUID}"; } public override async Task> getChildrenAsync(int Depth = -1) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return null; } if (MsFolder == null) return null; var RegExFilter = this.Provider?.DataAreaRegEx; var SP = this.Provider?.MsSharepoint; if (MsFolder.Folders == null) if (SP == null || !await MsFolder.ResolveFolders(SP)) return null; var DataAreas = new List(); foreach (var Entry in MsFolder.Folders.Values) { if (!string.IsNullOrEmpty(RegExFilter) && !Regex.Match(Entry.DisplayName, RegExFilter).Success) continue; var DA = new cLiamMsTeamsFolder(this.Provider, this.Channel, this, Entry, this.ChannelUID); DataAreas.Add(DA); } var CL = await getChildrenFromListAsync(DataAreas, Depth); if (CL != null) DataAreas.AddRange(CL); return DataAreas; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } public static async Task Load(cLiamProviderMsTeams Provider, string UID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var arrIDs = UID.Split('|'); if (arrIDs.Length != 4) return null; var FolderID = cLiamProviderMsTeams.getUidItem(ref UID); var DriveID = cLiamProviderMsTeams.getUidItem(ref UID); var F = await Provider.MsSharepoint.RequestFileObjectInfo(DriveID, FolderID); if (F == null) return null; var RetVal = new cLiamMsTeamsFolder(Provider, null, null, F, UID); return RetVal; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } public override async Task> GetPermissionsAsync(bool force = false) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return null; } var RetVal = new List(); if (this.MsFolder.Permissions == null || force) if (!await this.MsFolder.ResolvePermissions(Provider.MsSharepoint)) return null; if (this.MsFolder.Permissions == null) return null; foreach (var Perm in this.MsFolder.Permissions) { if (!(Perm is cMsGraphResultPermission.PermissionDirect) && !(Perm is cMsGraphResultPermission.PermissionLink)) continue; if (Perm.isInherited) continue; if (Perm.Identities != null) { foreach (var Role in Perm.Roles) { var AccessRole = cLiamProviderMsTeams.getLiamRole(Role); foreach (var Ident in Perm.Identities) { if (Ident.IdentityType != cMsGraphResultPermission.cMsGraphPermissionIdentity.eIdentityType.user) continue; if (string.IsNullOrEmpty(Ident.EMail)) continue; if (!string.IsNullOrEmpty(Ident.ID)) { var GroupInfo = await Provider.MsSharepoint.RequestGroupInfoAsync(Ident.ID); if (GroupInfo != null) continue; } var Usr = Ident.EMail.ToLowerInvariant(); var alreadyFound = false; foreach (var Entry in RetVal) { if (Usr == Entry.User.EMail.ToLowerInvariant()) if (AccessRole == Entry.AccessRole) { alreadyFound = true; break; } } if (!alreadyFound) { var UsrInfo = new cLiamUserInfo() { DisplayName = Ident.DisplayName, EMail = Ident.EMail, UserPrincipalName = Ident.EMail }; var PermInfo = new cLiamPermissionInfo() { User = UsrInfo, AccessRole = AccessRole }; RetVal.Add(PermInfo); } } } } } return RetVal; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return null; } public override async Task GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return null; } var Roles = new List() { cLiamProviderMsTeams.getMsGraphRole(Role) }; var RetVal = await this.MsFolder.AddPermission(Provider.MsSharepoint, Roles, cMsGraphResultPermission.eDriveReceipientType.email, User.EMail); if (RetVal == null) return null; var RetVal2 = new cLiamPermissionResult(); if (RetVal.Count>= 0) { RetVal2.Valid = true; var Perm = RetVal[0]; if (Perm is cMsGraphResultPermission.PermissionLink Link) { RetVal2.UserReference = Link.WebUrl; } else RetVal2.UserReference = this.MsFolder.WebUrl; } return RetVal2; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } public override async Task RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(LiamInitializer.msTeamsModuleId)) { LogEntry($"Error: License not valid", LogLevels.Error); return false; } var myRole = cLiamProviderMsTeams.getMsGraphRole(Role); var RetVal = await this.MsFolder.RemovePermission(Provider.MsSharepoint, myRole, User.EMail); return RetVal; } catch (Exception E) { LogException(E); return false; } finally { LogMethodEnd(CM); } } } }