-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgetUsersList.gs
253 lines (215 loc) · 9.19 KB
/
getUsersList.gs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
const HEADER_BG_COLOR = "#fc3165";
const HEADER_FONT_COLOR = "#ffffff";
const FONT_FAMILY = "Montserrat";
const FONT_SIZE = 10;
const SHEET_NAME = "Users"; // Name the sheet to consolidate code.
function getUsersList() {
const users = [];
const userEmail = Session.getActiveUser().getEmail();
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const options = {
customer: "my_customer", // Keep this!
maxResults: 100,
projection: "FULL",
viewType: "admin_view",
orderBy: "email",
};
try {
// Get or create the "Users" sheet.
let usersSheet = getOrCreateSheet(spreadsheet, SHEET_NAME);
// Headers
const headers = ["Name", "Email", "Super Admin", "Delegated Admin", "Suspended",
"Archived", "Last Login Time", "Creation Date", "Enrolled in 2SV", "Enforced in 2SV",
"Org Path"];
const headerRange = usersSheet.getRange("A1:K1");
headerRange.setValues([headers]);
headerRange.setFontColor(HEADER_FONT_COLOR);
headerRange.setFontSize(FONT_SIZE);
headerRange.setFontFamily(FONT_FAMILY);
headerRange.setBackground(HEADER_BG_COLOR);
headerRange.setFontWeight("bold");
// Insert data in the spreadsheet
do {
try {
Utilities.sleep(200); // Add some delay to avoid hitting rate limits
let response = AdminDirectory.Users.list(options);
if (response && response.users) {
// Process users and push into the 'users' array
users.push(
...response.users.map((user) => {
const lastLoginTime = user.lastLoginTime === "1970-01-01T00:00:00.000Z" ? "Never logged in" : (user.lastLoginTime ? formatDate(user.lastLoginTime, true) : null);
const creationTime = user.creationTime ? formatDate(user.creationTime, false) : null;
return [
user.name.fullName,
user.primaryEmail,
user.isAdmin || false,
user.isDelegatedAdmin || false,
user.suspended || false,
user.archived || false,
lastLoginTime,
creationTime,
user.isEnrolledIn2Sv || false,
user.isEnforcedIn2Sv || false,
user.orgUnitPath || ""
];
})
);
} else {
Logger.log("No users found in this page or invalid response.");
}
if (response && response.nextPageToken) {
options.pageToken = response.nextPageToken;
} else {
options.pageToken = null;
}
} catch (apiError) {
Logger.log(`API Error: ${apiError} - PageToken: ${options.pageToken || 'First Page'}`);
break;
}
} while (options.pageToken);
// Set the values after the loop
if (users.length > 0) {
usersSheet.getRange(2, 1, users.length, headers.length).setValues(users);
usersSheet.setFrozenRows(1);
} else {
Logger.log("No users found to insert into the sheet.");
usersSheet.getRange("A2").setValue("No users found."); //Display "No users found." message below header
}
// Set Column Widths (Batch Update)
const columnWidths = [null, null, 112, 145, 105, 90, 135, 120, 129, 130, null]; // null for auto
for (let i = 0; i < columnWidths.length; i++) {
if (columnWidths[i] !== null) {
usersSheet.setColumnWidth(i + 1, columnWidths[i]);
} else {
usersSheet.autoResizeColumn(i + 1);
}
}
// Delete extra columns (L onwards)
usersSheet.deleteColumns(12, usersSheet.getMaxColumns() - 11); //Deletes from L to the end of sheet.
// Conditional Formatting (refactored for clarity)
applyConditionalFormatting(usersSheet);
// Re-calculate lastRow after data is written to the sheet
const lastRow = usersSheet.getLastRow();
// Dynamic Named Range Calculation
const rangeForNamedRange = usersSheet.getRange(2, 2, Math.max(1, lastRow - 1), 4); // B2:E[lastRow] Use Math.max to ensure height is never 0
// Named Range
// First remove the existing named range
let namedRange = spreadsheet.getNamedRanges();
for (let i = 0; i < namedRange.length; i++) {
if (namedRange[i].getName() == "UserStatus") {
try {
namedRange[i].remove();
} catch (remove_error) {
Logger.log("Unable to remove named range");
}
}
}
// Now create a new one.
spreadsheet.setNamedRange('UserStatus', rangeForNamedRange);
// Filter
addFilter(usersSheet);
// Highlight "Never logged in"
highlightNeverLoggedIn(usersSheet);
Logger.log("User list generation complete.");
} catch (e) {
Logger.log(`Error during user list generation: ${e}`);
SpreadsheetApp.getUi().alert(`An error occurred: ${e}. Check the logs.`);
}
}
function applyConditionalFormatting(usersSheet) {
// Clear any existing conditional formatting
usersSheet.clearConditionalFormatRules();
// Find the last row of *data* in column A (Name) - most reliable indicator
const lastRow = usersSheet.getLastRow(); //Used to capture all the user records.
const ranges = {
"C": usersSheet.getRange("C2:C" + lastRow), // Super Admin
"D": usersSheet.getRange("D2:D" + lastRow), // Delegated Admin
"I": usersSheet.getRange("I2:I" + lastRow), // Enrolled in 2SV
"J": usersSheet.getRange("J2:J" + lastRow) // Enforced in 2SV
};
let rules = []; //Create rules list
for (const col in ranges) {
const range = ranges[col];
const trueRule = SpreadsheetApp.newConditionalFormatRule()
.whenTextEqualTo("TRUE")
.setBackground("#b7e1cd")
.setRanges([range])
.build();
const falseRule = SpreadsheetApp.newConditionalFormatRule()
.whenTextEqualTo("FALSE")
.setBackground("#ffb6c1")
.setRanges([range])
.build();
rules = rules.concat([trueRule, falseRule]); //Add the rules to the list.
}
usersSheet.setConditionalFormatRules(rules); //Set all the rules at once.
}
function addFilter(usersSheet) {
try {
const lastRow = usersSheet.getLastRow();
const lastColumn = usersSheet.getLastColumn();
//Data range should only include the content. Start at first column, first row, last row of data.
const dataRange = usersSheet.getRange(1, 1, lastRow, lastColumn);
let filter = usersSheet.getFilter();
if (filter) {
filter.remove();
}
dataRange.createFilter(); //Create a new filter.
} catch (e) {
Logger.log(`Error adding filter: ${e}`);
}
}
function highlightNeverLoggedIn(usersSheet) {
const lastLoginColumnIndex = 7; // Column G
const lastRow = usersSheet.getLastRow();
const lastLoginRange = usersSheet.getRange(2, lastLoginColumnIndex, lastRow - 1, 1);
const lastLoginValues = lastLoginRange.getValues();
for (let i = 0; i < lastLoginValues.length; i++) {
if (lastLoginValues[i][0] === "Never logged in") {
usersSheet.getRange(i + 2, lastLoginColumnIndex).setBackground("yellow");
}
}
}
/**
* Formats a date string into a more readable format (without timezone).
* @param {string} dateString The date string to format (e.g., "2024-08-08T12:41:09.000Z").
* @param {boolean} includeTime Whether to include the time in the formatted output.
* @returns {string} The formatted date string (e.g., "1/28/24 12:41 PM"), or null if the input is null/undefined.
*/
function formatDate(dateString, includeTime) {
if (!dateString) {
return null;
}
try {
const date = new Date(dateString);
const month = date.getMonth() + 1;
const day = date.getDate();
const year = date.getFullYear().toString().slice(-2);
let formattedDate = `${month}/${day}/${year}`;
if (includeTime) {
let hours = date.getHours();
const minutes = date.getMinutes();
const ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12;
hours = hours ? hours : 12;
const formattedTime = `${hours}:${minutes.toString().padStart(2, '0')} ${ampm}`;
formattedDate += ` ${formattedTime}`;
}
return formattedDate;
} catch (e) {
Logger.log(`Error formatting date: ${dateString} - ${e}`);
return "Invalid Date";
}
}
function getOrCreateSheet(spreadsheet, sheetName) {
let sheet = spreadsheet.getSheetByName(sheetName);
if (sheet) {
try {
spreadsheet.deleteSheet(sheet); //Delete existing sheet
} catch (err) {
Logger.log("Unable to delete sheet with name "+sheetName+".")
}
}
sheet = spreadsheet.insertSheet(sheetName, spreadsheet.getSheets().length); //Insert new sheet at end
return sheet; //Return the sheet
}