public static async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log) { var storage = CloudStorageAccount.Parse(StorageAccount); var cloudTableClient = storage.CreateCloudTableClient(); var groupsStatisticsTable = cloudTableClient.GetTableReference("groupsstatistics"); var groupsOwnersTable = cloudTableClient.GetTableReference("groupowners"); var groupsGuestsTable = cloudTableClient.GetTableReference("groupguests"); await groupsStatisticsTable.CreateIfNotExistsAsync().ConfigureAwait(false); await groupsOwnersTable.CreateIfNotExistsAsync().ConfigureAwait(false); await groupsGuestsTable.CreateIfNotExistsAsync().ConfigureAwait(false); // Get a Bearer Token with the App var httpClient = new HttpClient(); string token; try { var app = ConfidentialClientApplicationBuilder.Create(AppId) .WithAuthority($"https://login.windows.net/{TenantId}/oauth2/token") .WithRedirectUri("https://governance365function") .WithClientSecret(AppSecret) .Build(); var authenticationProvider = new MsalAuthenticationProvider(app, Scopes); token = authenticationProvider.GetTokenAsync().Result; httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); } catch (Exception) { throw; } httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); JObject groupsPageJson = null; do { if (string.IsNullOrEmpty(groupsPageJson?["@odata.nextLink"]?.ToString())) { // first group page groupsPageJson = JObject.Parse(await(await httpClient.GetAsync(groupsUrl + groupsSelection).ConfigureAwait(false)).Content.ReadAsStringAsync().ConfigureAwait(false)); } else { // next group page groupsPageJson = JObject.Parse(await(await httpClient.GetAsync(groupsPageJson?["@odata.nextLink"]?.ToString()).ConfigureAwait(false)).Content.ReadAsStringAsync().ConfigureAwait(false)); } if (!(groupsPageJson["value"] is JArray groupsPage)) { continue; } // Batch operation to store pages of groups in Azure table storage var groupPageBatchOperation = new TableBatchOperation(); foreach (var group in groupsPage) { var memberCount = 0; var ownerCount = 0; var guestCount = 0; #region PROCESS GROUP TYPE AND DYNAMIC MEMBERSHIP var groupType = string.Empty; var dynamicMemberShip = false; var yammerProvisionedOffice365Group = false; foreach (var type in (JArray)group["groupTypes"]) { if (type.ToString().Equals("Unified")) { if (group["resourceProvisioningOptions"].ToString().Contains("Team")) { groupType = "Team"; } else { groupType = "Office365 Group"; } if (group["creationOptions"].ToString().Contains("YammerProvisioning")) { yammerProvisionedOffice365Group = true; } } if (type.ToString().Equals("DynamicMembership")) { dynamicMemberShip = true; } } if (groupType.Equals(string.Empty)) { if (!group["mailEnabled"].ToString().ToLower().Equals("true")) { groupType = "Security Group"; } else { if (!group["securityEnabled"].ToString().ToLower().Equals("true")) { groupType = "Distribution Group"; } else { groupType = "Mail-enabled Security Group"; } } } #endregion const string groupMemberSelection = "?$select=id,userPrincipalName,displayName,userType,accountEnabled"; var groupMembersUrl = $"https://graph.microsoft.com/v1.0/groups/{group["id"]?.ToString()}/members{groupMemberSelection}"; var groupOwnersUrl = $"https://graph.microsoft.com/v1.0/groups/{group["id"]?.ToString()}/owners{groupMemberSelection}"; #region PROCESS GROUP MEMBERS AND GUESTS var processMemberPageResult = await ProcessGroupMemberPageAsync(groupMembersUrl, group, httpClient, groupsGuestsTable, groupsOwnersTable, false).ConfigureAwait(false); memberCount += processMemberPageResult.MemberCount; guestCount += processMemberPageResult.GuestCount; while (processMemberPageResult.NextLink != null) { processMemberPageResult = await ProcessGroupMemberPageAsync(processMemberPageResult.NextLink, group, httpClient, groupsGuestsTable, groupsOwnersTable, false).ConfigureAwait(false); memberCount += processMemberPageResult.MemberCount; guestCount += processMemberPageResult.GuestCount; } #endregion #region PROCESS GROUP OWNERS var processOwnerPageResult = await ProcessGroupMemberPageAsync(groupOwnersUrl, group, httpClient, groupsGuestsTable, groupsOwnersTable, true).ConfigureAwait(false); ownerCount += processOwnerPageResult.OwnerCount; while (processOwnerPageResult.NextLink != null) { processOwnerPageResult = await ProcessGroupMemberPageAsync(processOwnerPageResult.NextLink, group, httpClient, groupsGuestsTable, groupsOwnersTable, true).ConfigureAwait(false); ownerCount += processOwnerPageResult.OwnerCount; } #endregion var groupStatisticsEntity = new GroupStatisticsItemTableEntity() { PartitionKey = "group", RowKey = group["id"]?.ToString(), Classification = group["classification"]?.ToString(), CreatedDateTime = group["createdDateTime"] != null && !group["createdDateTime"].ToString().Equals(string.Empty) ? DateTimeOffset.Parse(group["createdDateTime"].ToString()) : (DateTimeOffset?)null, DeletedDateTime = group["deletedDateTime"] != null && !group["deletedDateTime"].ToString().Equals(string.Empty) ? DateTimeOffset.Parse(group["deletedDateTime"].ToString()) : (DateTimeOffset?)null, Description = group["description"]?.ToString(), DisplayName = group["displayName"]?.ToString(), GroupType = groupType, DynamicMembership = dynamicMemberShip, Id = group["id"]?.ToString(), Mail = group["mail"]?.ToString(), MailEnabled = group["mailEnabled"]?.ToString(), MailNickname = group["mailNickname"]?.ToString(), OnPremisesSyncEnabled = group["onPremisesSyncEnabled"]?.ToString(), RenewedDateTime = group["renewedDateTime"] != null & !group["renewedDateTime"].ToString().Equals(string.Empty) ? DateTimeOffset.Parse(group["renewedDateTime"].ToString()) : (DateTimeOffset?)null, SecurityEnabled = group["securityEnabled"]?.ToString(), Visibility = group["visibility"]?.ToString(), Guests = guestCount, Owners = ownerCount, Members = memberCount }; groupPageBatchOperation.Add(TableOperation.InsertOrReplace(groupStatisticsEntity)); } await groupsStatisticsTable.ExecuteBatchAsync(groupPageBatchOperation).ConfigureAwait(false); } while (!string.IsNullOrEmpty(groupsPageJson["@odata.nextLink"]?.ToString())); httpClient.Dispose(); }
public static async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log) { var storage = CloudStorageAccount.Parse(StorageAccount); var cloudTableClient = storage.CreateCloudTableClient(); var usersTable = cloudTableClient.GetTableReference("users"); var userStatisticsTable = cloudTableClient.GetTableReference("userstatistics"); await usersTable.CreateIfNotExistsAsync().ConfigureAwait(false); await userStatisticsTable.CreateIfNotExistsAsync().ConfigureAwait(false); // Get a Bearer Token with the App var httpClient = new HttpClient(); string token; try { var app = ConfidentialClientApplicationBuilder.Create(AppId) .WithAuthority($"https://login.windows.net/{TenantId}/oauth2/token") .WithRedirectUri("https://governance365function") .WithClientSecret(AppSecret) .Build(); var authenticationProvider = new MsalAuthenticationProvider(app, Scopes); token = authenticationProvider.GetTokenAsync().Result; httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); } catch (Exception) { throw; } httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); //initialize object for storing all user statistics UserQueryObject usersPage = null; var userStatistics = new UserStatisticsTableEntity() { PartitionKey = "userstatistics", RowKey = TenantId, DeactivatedUsers = 0, DeletedUsers = 0, GuestUsers = 0, InternalUsers = 0, Users = 0 }; //get all users (until nextlinnk is empty) and members/guests + sum up statistics do { if (string.IsNullOrEmpty(usersPage?.OdataNextLink?.ToString())) { //first request usersPage = JsonConvert.DeserializeObject <Governance365.Models.UserQueryObject>(await(await httpClient.GetAsync(usersUrl + UserSelectedProperties).ConfigureAwait(false)).Content.ReadAsStringAsync().ConfigureAwait(false)); } else { //next page request usersPage = JsonConvert.DeserializeObject <Governance365.Models.UserQueryObject>(await(await httpClient.GetAsync(usersPage?.OdataNextLink?.ToString()).ConfigureAwait(false)).Content.ReadAsStringAsync().ConfigureAwait(false)); } //batch request to store pages of users in Azure storage var userPageBatchOperation = new TableBatchOperation(); foreach (var user in usersPage.Value) { if (user.UserType != null) { userStatistics.Users++; if (user.UserType.Equals("Member")) { userStatistics.InternalUsers++; } else if (user.UserType.Equals("Guest")) { userStatistics.GuestUsers++; } if (string.IsNullOrEmpty(user.AccountEnabled) && !bool.Parse(user.AccountEnabled)) { userStatistics.DeactivatedUsers++; } } user.PartitionKey = "user"; user.RowKey = user.Id.ToString(); //add user entity to batch operation userPageBatchOperation.Add(TableOperation.InsertOrReplace(user)); } //write user page to Azure tabel storage await usersTable.ExecuteBatchAsync(userPageBatchOperation).ConfigureAwait(false); } while (!string.IsNullOrEmpty(usersPage.OdataNextLink?.ToString())); //write user statistics to table "userstatistics" -> single value with overwrite var insertUserStatisticsOperation = TableOperation.InsertOrReplace(userStatistics); await userStatisticsTable.ExecuteAsync(insertUserStatisticsOperation).ConfigureAwait(false); httpClient.Dispose(); }