From 08654b98473f556842a9e5c784a66216715d249e Mon Sep 17 00:00:00 2001 From: Gunjan Datta Date: Thu, 23 Jul 2026 11:37:27 -0400 Subject: [PATCH] Added new option to search for overshared groups in EEEU report. --- src/reports/searchEEEU.ts | 109 ++++++++++++++++++++++++++------------ src/tabs/lists.ts | 11 +++- src/tabs/reports.ts | 1 + 3 files changed, 87 insertions(+), 34 deletions(-) diff --git a/src/reports/searchEEEU.ts b/src/reports/searchEEEU.ts index fa6ccc5..7469de7 100644 --- a/src/reports/searchEEEU.ts +++ b/src/reports/searchEEEU.ts @@ -42,6 +42,7 @@ export class SearchEEEU { private static _elSubNav: HTMLElement = null; private static _items: ISearchItem[] = null; private static _loadOneDrive: boolean = null; + private static _oversharedGroups: string[] = null; private static _stopFl: boolean = false; // Analyzes a lists @@ -83,7 +84,6 @@ export class SearchEEEU { // Get the permissions batch.Items(item.Id).RoleAssignments().query({ - Filter: `Member/Title eq 'Everyone' or substringof('spo-grid-all-users', Member/LoginName)`, Expand: [ "Member", "RoleDefinitionBindings" ] @@ -93,28 +93,31 @@ export class SearchEEEU { let roleDef = roleAssignment.RoleDefinitionBindings.results[0]; let user: Types.SP.User = roleAssignment.Member as any; - // Add a row for this entry - let roleItem = { - Email: user.Email, - FileName: item["FileLeafRef"], - FileUrl: item["FileRef"], - Group: "", - GroupId: 0, - GroupInfo: "", - Id: user.Id, - ItemId: item.Id, - ListId: list.Id, - ListName: list.Title, - LoginName: user.LoginName, - ListUrl: list.RootFolder.ServerRelativeUrl, - Name: user.Title || user.LoginName, - Role: roleDef?.Name || "", - RoleInfo: roleDef?.Description || "", - WebUrl: web.Url, - WebTitle: web.Title - }; - this._items.push(roleItem); - this._dashboard.Datatable.addRow(roleItem); + // See if it's overshared + if (this.isOvershared(user)) { + // Add a row for this entry + let roleItem = { + Email: user.Email, + FileName: item["FileLeafRef"], + FileUrl: item["FileRef"], + Group: "", + GroupId: 0, + GroupInfo: "", + Id: user.Id, + ItemId: item.Id, + ListId: list.Id, + ListName: list.Title, + LoginName: user.LoginName, + ListUrl: list.RootFolder.ServerRelativeUrl, + Name: user.Title || user.LoginName, + Role: roleDef?.Name || "", + RoleInfo: roleDef?.Description || "", + WebUrl: web.Url, + WebTitle: web.Title + }; + this._items.push(roleItem); + this._dashboard.Datatable.addRow(roleItem); + } // Increment the counter and update the dialog this._elSubNav.children[1].innerHTML = `Batch Requests Processed ${++completed} of ${ctrBatchJobs % Strings.MaxBatchSize}...`; @@ -207,6 +210,13 @@ export class SearchEEEU { // Gets the form fields to display static getFormFields(): Components.IFormControlProps[] { return [ + { + name: "IncludeOversharedGroups", + label: "Include Overshared Groups?", + description: "Selecting this option will include the overshared groups in the search.", + type: Components.FormControlTypes.Switch, + value: true + }, { name: "SearchLists", label: "In Depth Search?", @@ -295,7 +305,6 @@ export class SearchEEEU { // Get the user information list let web = this._loadOneDrive ? Web.getOneDrive() : Web(DataSource.SiteContext.SiteFullUrl, { requestDigest: DataSource.SiteContext.FormDigestValue }); web.Lists("User Information List").Items().query({ - Filter: `Title eq 'Everyone' or substringof('spo-grid-all-users', Name)`, Select: ["Id", "Name", "EMail", "Title", "UserName"], GetAllItems: true, Top: 5000 @@ -304,14 +313,17 @@ export class SearchEEEU { for (let i = 0; i < items.results.length; i++) { let item = items.results[i]; - // Add the user - users.push({ - EMail: item["EMail"], - Id: item.Id, - Name: item["Name"], - Title: item.Title, - UserName: item["UserName"] - }); + // Add the user if this is flagged for overshared + if (this.isOvershared(item)) { + // Add the user + users.push({ + EMail: item["EMail"], + Id: item.Id, + Name: item["Name"], + Title: item.Title, + UserName: item["UserName"] + }); + } } // Resolve the request @@ -320,6 +332,31 @@ export class SearchEEEU { }); } + // Returns true if the item is an overshared group + private static isOvershared(item: Types.SP.ListItemOData | Types.SP.User): boolean { + let isOvershared = false; + + // See if this is the default groups + if (item.Title == "Everyone" || item.Title == "Everyone except external users" || item["Name"]?.indexOf("spo-grid-all-users") > 0) { + // Set the flag + isOvershared = true; + } + // Else, see if this is an overshared group + else if (this._oversharedGroups.length > 0) { + // Parse the overshared groups + for (let j = 0; j < this._oversharedGroups.length; j++) { + if (item.Title == this._oversharedGroups[j]) { + // Set the flag + isOvershared = true; + break; + } + } + } + + // Return the flag + return isOvershared; + } + // Removes a user from a group private static removeUser(user: string, userId: number) { // Display a loading dialog @@ -673,6 +710,9 @@ export class SearchEEEU { // Clear the items this._items = []; + // Set the overshared groups + this._oversharedGroups = (values["IncludeOversharedGroups"] == true ? values["OversharedGroups"] : null) || []; + // See if we are showing hidden lists let searchLists = values["SearchLists"]; @@ -727,13 +767,16 @@ export class SearchEEEU { } // Searches a list for EEEU - static searchList(webUrl: string, listName: string, auditOnly: boolean) { + static searchList(webUrl: string, listName: string, auditOnly: boolean, oversharedGroups: string[] = []) { this._loadOneDrive = false; this._stopFl = false; // Clear the items this._items = []; + // Set the overshared groups + this._oversharedGroups = oversharedGroups; + // Clear the modal Modal.clear(); Modal.setType(Components.ModalTypes.Full); diff --git a/src/tabs/lists.ts b/src/tabs/lists.ts index f669d75..f979155 100644 --- a/src/tabs/lists.ts +++ b/src/tabs/lists.ts @@ -691,6 +691,13 @@ export class ListsTab { controls: getDefaultControl(ReportTypes.SearchDocs).concat(SearchDocs.getFormFields(this._appProps.reportProps?.docSearchFileExt, this._appProps.reportProps?.docSearchKeywords, this._appProps.reportProps?.docSearchRegexPatterns, true), ListsTab.generateSubFolders(webId, driveId, folders)) }); break; + case ReportTypes.SearchEEEU: + // Set the form + form = Components.Form({ + el: Modal.BodyElement, + controls: getDefaultControl(ReportTypes.SearchEEEU).concat(SearchEEEU.getFormFields()) + }); + break; case ReportTypes.SensitivityLabels: // Set the form form = Components.Form({ @@ -762,7 +769,9 @@ export class ListsTab { break; case ReportTypes.SearchEEEU: // Run the EEEU report for this list - SearchEEEU.searchList(item.WebUrl, item.ListName, this._appProps.auditOnly); + SearchEEEU.searchList(item.WebUrl, item.ListName, + values["SearchLists"], + values["IncludeOversharedGroups"] ? this._appProps.reportProps.oversharedGroups : []); break; case ReportTypes.SensitivityLabels: // Set the target web and list diff --git a/src/tabs/reports.ts b/src/tabs/reports.ts index 7759b6f..2d759f1 100644 --- a/src/tabs/reports.ts +++ b/src/tabs/reports.ts @@ -347,6 +347,7 @@ export class ReportsTab { }); break; case ReportTypes.SearchEEEU: + formValues["OversharedGroups"] = this._reportProps?.oversharedGroups; Reports.SearchEEEU.run(this._el, this._auditOnly, formValues, () => { // Render this component this.render(this._selectedReport);