Skip to content

Commit e1182b3

Browse files
authored
Merge pull request #5 from doitintl/filter-all-reports
Filter all reports
2 parents e05deb5 + 5d86f39 commit e1182b3

9 files changed

+144
-75
lines changed

getAppPasswords.gs

+49-42
Original file line numberDiff line numberDiff line change
@@ -6,92 +6,99 @@
66
function getAppPasswords() {
77
const userEmail = Session.getActiveUser().getEmail();
88
const domain = userEmail.split("@").pop();
9-
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
10-
const sheets = spreadsheet.getSheets();
11-
const lastSheetIndex = sheets.length;
129

13-
// Create or clear the "App Passwords" sheet at the last index
10+
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
11+
// Check for existing sheet and handle duplicates
1412
let appPasswordsSheet = spreadsheet.getSheetByName("App Passwords");
1513
if (appPasswordsSheet) {
14+
// If the sheet exists, delete it first
1615
spreadsheet.deleteSheet(appPasswordsSheet);
1716
}
18-
appPasswordsSheet = spreadsheet.insertSheet("App Passwords", lastSheetIndex);
19-
20-
// Set font to Montserrat
21-
appPasswordsSheet.getRange("A1:Z1").setFontFamily("Montserrat");
2217

23-
// Add headers
24-
const headers = ["CodeID", "Name", "Creation Time", "Last Time Used", "User"];
25-
appPasswordsSheet.appendRow(headers);
18+
// Create a new sheet with the desired name
19+
appPasswordsSheet = spreadsheet.insertSheet("App Passwords", spreadsheet.getNumSheets());
2620

27-
// Apply formatting to the header row
28-
const headerRange = appPasswordsSheet.getRange(1, 1, 1, headers.length);
29-
headerRange.setBackground("#fc3165").setFontColor("white").setFontWeight("bold");
21+
// Sheet styling (concise)
22+
const headerRange = appPasswordsSheet.getRange("A1:E1");
23+
headerRange.setFontFamily("Montserrat")
24+
.setBackground("#fc3165")
25+
.setFontColor("white")
26+
.setFontWeight("bold")
27+
.setValues([["CodeID", "Name", "Creation Time", "Last Time Used", "User"]]);
3028

31-
// Freeze the header row
3229
appPasswordsSheet.setFrozenRows(1);
3330

34-
// Delete columns F-Z. deleteColumns is called twice because (6, 20) was not deleting the last column.
35-
appPasswordsSheet.deleteColumns(7, 20);
36-
appPasswordsSheet.deleteColumns(6);
37-
38-
// Set pagination parameters
3931
let pageToken = null;
40-
4132
do {
42-
// Make an API call to retrieve users
43-
const options = {
33+
const response = AdminDirectory.Users.list({
4434
domain: domain,
4535
customer: "my_customer",
4636
maxResults: 100,
4737
projection: "FULL",
4838
viewType: "admin_view",
4939
orderBy: "email",
5040
pageToken: pageToken,
51-
};
41+
});
5242

53-
const response = AdminDirectory.Users.list(options);
54-
55-
// Process the retrieved users
56-
processUsers(response.users, appPasswordsSheet);
43+
if (response.users && response.users.length > 0) {
44+
processUsers(response.users, appPasswordsSheet);
45+
}
5746

58-
// Update the page token for the next iteration
5947
pageToken = response.nextPageToken;
6048
} while (pageToken);
6149

62-
// Auto resize the columns
50+
// Auto-resize and add filter after data is populated
6351
appPasswordsSheet.autoResizeColumns(1, 5);
52+
const lastRow = appPasswordsSheet.getLastRow();
53+
appPasswordsSheet.getRange('B1:E' + lastRow).createFilter();
6454
}
6555

6656
function processUsers(users, sheet) {
67-
// Prepare data array
6857
const data = [];
6958

70-
// Iterate over the retrieved users
7159
users.forEach(function (user) {
72-
// Retrieve app passwords for the user
7360
const asps = AdminDirectory.Asps.list(user.primaryEmail);
7461

75-
// Process app passwords
7662
if (asps && asps.items) {
7763
asps.items.forEach(function (asp) {
7864
data.push([
7965
asp.codeId,
8066
asp.name,
81-
asp.creationTime,
82-
asp.lastTimeUsed,
67+
formatTimestamp(asp.creationTime),
68+
asp.lastTimeUsed ? formatTimestamp(asp.lastTimeUsed) : "",
8369
user.primaryEmail,
8470
]);
8571
});
8672
}
8773
});
8874

89-
// Write the data to the sheet in chunks to reduce API calls
90-
const batchSize = 1000;
75+
// Dynamic batch write:
76+
const batchSize = 500; // Maximum batch size
77+
9178
for (let i = 0; i < data.length; i += batchSize) {
92-
const chunk = data.slice(i, i + batchSize);
93-
if (chunk.length > 0) {
94-
sheet.getRange(sheet.getLastRow() + 1, 1, chunk.length, chunk[0].length).setValues(chunk);
95-
}
79+
const chunk = data.slice(i, i + batchSize); // Get the current chunk of data
80+
const numRows = chunk.length; // Number of rows in the current chunk
81+
82+
// Write only the necessary number of rows
83+
sheet.getRange(sheet.getLastRow() + 1, 1, numRows, chunk[0].length)
84+
.setValues(chunk);
9685
}
9786
}
87+
88+
// Corrected timestamp formatting:
89+
function formatTimestamp(timestampString) {
90+
if (timestampString === "0" || timestampString === 0) {
91+
return "Never Used"; // Handle 0 timestamps
92+
} else if (typeof timestampString === "string" && timestampString.length >= 13) {
93+
const timestamp = parseInt(timestampString.slice(0, 13));
94+
const date = new Date(timestamp);
95+
return Utilities.formatDate(date, Session.getScriptTimeZone(), "yyyy-MM-dd HH:mm:ss");
96+
} else {
97+
Logger.log("Unknown timestamp format: " + timestampString);
98+
return "Invalid Timestamp";
99+
}
100+
}
101+
102+
103+
104+

getDomainsDNS.gs

+16-1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,21 @@ sheet.getRange('A2').setValue('google.com');
160160

161161
const rules = [ruleD, ruleE, ruleF, ruleG, ruleDRed, ruleERed, ruleFRed, ruleGRed];
162162
sheet.setConditionalFormatRules(rules);
163+
164+
// --- Add Persistent Toast Notification ---
165+
SpreadsheetApp.getActiveSpreadsheet().toast(
166+
"If you use a third-party mail relay or a SPF flattener, records may be highlighted red and should be manually inspected.",
167+
"Instructions",
168+
-1 // Persistent toast
169+
);
170+
171+
// --- Add Filter View ---
172+
// --- Add Filter View ---
173+
const filterRange = sheet.getRange('B1:G' + lastRow); // Define the filter range
174+
filterRange.createFilter();
175+
176+
// --- Freeze Row 1 ---
177+
sheet.setFrozenRows(1);
163178
}
164179

165180
function NSLookup(type, domain) { //Function takes DNS record type and domain as input
@@ -219,4 +234,4 @@ function NSLookup(type, domain) { //Function takes DNS record type and domain as
219234
const outputString = outputData.join('\n');
220235

221236
return outputString;
222-
}
237+
}

getGroupMembers.gs

+15-7
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,24 @@ function getGroupMembers() {
7777

7878
// Set up the sheet with headers and formatting
7979
groupMembersSheet.getRange("A1:F1").setValues([["Group Email", "Member Email", "Member Role", "Member Status", "Member Type", "Member ID"]]);
80-
groupMembersSheet.getRange("A1:F1").setFontColor("#ffffff").setFontSize(10).setFontFamily("Montserrat").setBackground("#fc3165").setFontWeight("bold");
81-
groupMembersSheet.setFrozenRows(1);
82-
// Delete columns G-Z
83-
groupMembersSheet.deleteColumns(7, 20);
80+
groupMembersSheet.getRange("A1:F1").setFontColor("#ffffff").setFontSize(10).setFontFamily("Montserrat").setBackground("#fc3165").setFontWeight ("bold");
81+
groupMembersSheet.setFrozenRows(1);
8482

85-
// Append data to the end of the sheet
83+
// --- Add Note to Cell D1 ---
84+
groupMembersSheet.getRange("D1").setNote("A yellow highlighted row indicates a group member from an external organization.");
85+
86+
// --- Add Filter View ---
8687
const lastRow = groupMembersSheet.getLastRow();
87-
groupMembersSheet.getRange(lastRow + 1, 1, groupMembers.length, groupMembers[0].length).setValues(groupMembers);
88+
const filterRange = groupMembersSheet.getRange('A1:F' + lastRow); // Filter columns A through F, starting from row 1
89+
filterRange.createFilter();
90+
91+
// Append data to the end of the sheet (starting from row 3)
92+
groupMembersSheet.getRange(lastRow + 1, 1, groupMembers.length, groupMembers[0].length).setValues(groupMembers);
8893
groupMembersSheet.autoResizeColumns(1, 6);
8994

95+
// Delete columns G-Z (starting from row 3)
96+
groupMembersSheet.deleteColumns(7, 20); // G to Z
97+
9098
// Apply conditional formatting
9199
const range = groupMembersSheet.getRange("D2:D" + (lastRow + groupMembers.length));
92100
const rules = [
@@ -123,4 +131,4 @@ function getGroupMembers() {
123131
`Error writing group members to spreadsheet: ${error.message}`,
124132
);
125133
}
126-
}
134+
}

getGroupSettings.gs

+7
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,13 @@ groupSettingsSheet.setConditionalFormatRules(rules);
614614
}
615615
pageToken = page.nextPageToken;
616616
} while (pageToken);
617+
618+
// --- Add Filter View ---
619+
const lastRow = groupSettingsSheet.getLastRow();
620+
// Filter columns C through AG (3rd column to 33rd column)
621+
const filterRange = groupSettingsSheet.getRange('C1:AG' + lastRow);
622+
filterRange.createFilter();
623+
617624
}
618625

619626
function getSettingsGroup(email) {

getMobileDevices.gs

+5-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ function getMobileDevices() {
3636
rules.push(rule);
3737
mobileDeviceSheet.setConditionalFormatRules(rules);
3838

39+
const lastRow = mobileDeviceSheet.getLastRow();
40+
const filterRange = mobileDeviceSheet.getRange('B1:G' + lastRow); // Filter columns B through G (including header)
41+
filterRange.createFilter();
42+
3943
const customerId = "my_customer";
4044

4145
let rows = [];
@@ -78,4 +82,4 @@ function getMobileDevices() {
7882
if (columnsToDelete > 0) {
7983
mobileDeviceSheet.deleteColumns(8, columnsToDelete);
8084
}
81-
}
85+
}

getOAuthTokens.gs

+9-1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ function getTokens() {
6969

7070
// Hide column F
7171
oAuthTokenSheet.hideColumns(6);
72+
73+
// Add note to cell G1
74+
oAuthTokenSheet.getRange("G1").setNote("A light red highlighted row indicates the app uses a restricted or sensitive scope.");
7275

7376
// Apply conditional formatting
7477
const range = oAuthTokenSheet.getRange('A2:G999');
@@ -123,6 +126,11 @@ function getTokens() {
123126
console.log("Tokens written to Sheet Users: %s", tokens.length);
124127
const dataRange = oAuthTokenSheet.getRange(2, 1, tokens.length, tokens[0].length);
125128
dataRange.setValues(tokens);
129+
130+
// --- Add Filter View ---
131+
const lastRow = oAuthTokenSheet.getLastRow();
132+
const filterRange = oAuthTokenSheet.getRange('A1:G' + lastRow); // Filter columns A through G, starting from row 1
133+
filterRange.createFilter();
126134

127135
// Auto resize columns A, D, E
128136
oAuthTokenSheet.autoResizeColumns(1, 1);
@@ -135,4 +143,4 @@ function getTokens() {
135143
// Delete columns H-Z
136144
oAuthTokenSheet.deleteColumns(8, 18);
137145
oAuthTokenSheet.deleteColumns(8);
138-
}
146+
}

getOrgUnits.gs

+27-18
Original file line numberDiff line numberDiff line change
@@ -29,39 +29,43 @@ function getOrgUnits(){
2929
headerRange.setFontWeight("bold").setFontColor("#ffffff").setFontFamily("Montserrat");
3030
headerRange.setBackground("#fc3165");
3131

32-
// This code will inventory all OUs in Google Workspace. The org unit IDs are used in other sections of the workbook.
33-
const fileArray = [
34-
[
35-
"Org Name ID",
36-
"Org Unit Name",
37-
"OrgUnit Path",
38-
"Description",
39-
"Parent Org Unit ID",
40-
"Parent Org Unit Path",
41-
],
42-
];
4332

33+
// Fetch and sort org units
4434
const orgUnits = AdminDirectory.Orgunits.list("my_customer", {
4535
type: "ALL",
4636
}).organizationUnits;
4737

38+
// Sort the orgUnits array based on the orgUnitPath
39+
orgUnits.sort((a, b) => {
40+
// Split the paths into components
41+
const pathA = a.orgUnitPath.split("/");
42+
const pathB = b.orgUnitPath.split("/");
43+
44+
// Compare paths component by component
45+
for (let i = 0; i < Math.min(pathA.length, pathB.length); i++) {
46+
if (pathA[i] < pathB[i]) return -1; // a comes before b
47+
if (pathA[i] > pathB[i]) return 1; // a comes after b
48+
}
49+
50+
// If all components match, shorter path comes first
51+
return pathA.length - pathB.length;
52+
});
53+
54+
// Prepare data for the sheet (including headers)
55+
const fileArray = [headers];
4856
orgUnits.forEach((orgUnit) => {
4957
fileArray.push([
5058
orgUnit.orgUnitId.slice(3),
5159
orgUnit.name,
5260
orgUnit.orgUnitPath,
5361
orgUnit.description,
54-
orgUnit.parentOrgUnitId
55-
? orgUnit.parentOrgUnitId.replace(/^id:/, "")
56-
: "",
62+
orgUnit.parentOrgUnitId ? orgUnit.parentOrgUnitId.replace(/^id:/, "") : "",
5763
orgUnit.parentOrgUnitPath,
5864
]);
5965
});
6066

61-
// Write data back to our sheets
62-
orgUnitsSheet
63-
.getRange(1, 1, fileArray.length, fileArray[0].length)
64-
.setValues(fileArray);
67+
// Write data back to the sheet
68+
orgUnitsSheet.getRange(1, 1, fileArray.length, fileArray[0].length).setValues(fileArray);
6569

6670
// Delete columns G-Z
6771
orgUnitsSheet.deleteColumns(7, 20);
@@ -73,4 +77,9 @@ function getOrgUnits(){
7377
// Define ranges
7478
spreadsheet.setNamedRange('Org2ParentPath', orgUnitsSheet.getRange('E:F'));
7579
spreadsheet.setNamedRange('OrgID2Path', orgUnitsSheet.getRange('A:C'));
80+
81+
// --- Add Filter View ---
82+
const lastRow = orgUnitsSheet.getLastRow();
83+
const filterRange = orgUnitsSheet.getRange('A1:F' + lastRow); // Filter columns A through F (including header)
84+
filterRange.createFilter();
7685
}

getSharedDrives.gs

+6-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,12 @@ function getSharedDrives() {
115115
rules.push(rule2);
116116
sharedDrivesSheet.setConditionalFormatRules(rules);
117117

118+
// --- Add Filter View ---
119+
const lastRow = sharedDrivesSheet.getLastRow();
120+
const filterRange = sharedDrivesSheet.getRange('D1:J' + lastRow); // Filter columns D through H
121+
filterRange.createFilter();
122+
118123
const endTime = new Date().getTime();
119124
const elapsed = (endTime - startTime) / 1000;
120125
Logger.log("Elapsed Seconds: " + elapsed);
121-
}
126+
}

getUsersList.gs

+10-4
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,6 @@ function getUsersList() {
6666
usersSheet.setFrozenRows(1); // Sets headers in sheet and freezes row
6767
usersSheet.getRange(2, 1, users.length, users[0].length).setValues(users); // Adds in user info starting from row 1
6868

69-
// Auto resize all columns
70-
usersSheet.autoResizeColumns(1, usersSheet.getLastColumn());
71-
7269
// Apply conditional formatting
7370
var rangeC = usersSheet.getRange("C2:C1000");
7471
var ruleC = SpreadsheetApp.newConditionalFormatRule()
@@ -88,6 +85,7 @@ function getUsersList() {
8885
.setBackground("#ffb6c1")
8986
.setRanges([rangeH])
9087
.build();
88+
9189
var ruleHFalse = SpreadsheetApp.newConditionalFormatRule()
9290
.whenTextContains("TRUE")
9391
.setBackground("#b7e1cd")
@@ -121,6 +119,14 @@ function getUsersList() {
121119
var rules = [ruleC, ruleCFalse, ruleH, ruleHFalse, ruleI, ruleIFalse, ruleD, ruleDFalse];
122120
usersSheet.setConditionalFormatRules(rules);
123121

122+
// --- Add Filter View ---
123+
const lastRow = usersSheet.getLastRow();
124+
const filterRange = usersSheet.getRange('C1:J' + lastRow); // Filter columns C through J
125+
filterRange.createFilter();
126+
124127
// Create named range for columns B, C, D, and E
125-
var namedRange = spreadsheet.setNamedRange('UserStatus', usersSheet.getRange('B2:E1000'));
128+
const namedRange = spreadsheet.setNamedRange('UserStatus', usersSheet.getRange('B2:E' + lastRow));
129+
130+
// Auto resize all columns
131+
usersSheet.autoResizeColumns(1, usersSheet.getLastColumn());
126132
}

0 commit comments

Comments
 (0)