Skip to content

Commit be47196

Browse files
Merge branch 'main' into Hacktoberfest2023-1st-Pull_request
2 parents 82446a5 + 698e03a commit be47196

File tree

5 files changed

+282
-0
lines changed

5 files changed

+282
-0
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Group Membership Utility
2+
3+
The **Group Membership Utility** is a ServiceNow server-side tool designed to streamline the management of user membership in assignment groups. It provides administrators with two UI actions on the Assignment Group table to add or remove themselves from a group, ensuring efficient group membership management. Super helpful when doing group membership testing.
4+
5+
## Challenge
6+
7+
Managing assignment group memberships manually can be time-consuming and frustrating when doing group change related testings.
8+
9+
## Features
10+
11+
- **Add Me**: Adds the current user to the selected assignment group, ensuring quick inclusion.
12+
- **Remove Me**: Removes the current user from the selected assignment group, simplifying group updates.
13+
- **Admin-Only Visibility**: Both actions are restricted to users with administrative privileges i.e admin user role, ensuring controlled access.
14+
15+
## Functionality
16+
17+
The Group Membership Utility provides the following capabilities:
18+
- Detects the current user's membership status in the selected group.
19+
- Dynamically enables or disables the **Add Me** and **Remove Me** actions based on the user's membership.
20+
- Ensures visibility of these actions only for users with administrative privileges.
21+
22+
## Visibility
23+
24+
Add below condition script for the "Add Me" UI action
25+
```javascript
26+
gs.hasRole('admin') && !gs.getUser().isMemberOf(current.sys_id);
27+
```
28+
Add below condition script for the "Remove Me" UI action
29+
```javascript
30+
gs.hasRole('admin') && gs.getUser().isMemberOf(current.sys_id);
31+
```
32+
33+
## Usage Instructions
34+
35+
1. Navigate to the Assignment Group table.
36+
2. Select a group.
37+
3. Use the **Add Me** button to add yourself to the group if you're not already a member.
38+
4. Use the **Remove Me** button to remove yourself from the group if you're already a member.
39+
40+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
try {
2+
var groupSysId = current.sys_id;
3+
var userSysId = gs.getUserID();
4+
5+
// Validate input
6+
if (!groupSysId || !userSysId) {
7+
throw new Error("Group Sys ID and User Sys ID are required.");
8+
}
9+
10+
// Create a new record in the sys_user_grmember table
11+
var gr = new GlideRecord("sys_user_grmember");
12+
gr.initialize();
13+
gr.group = groupSysId;
14+
gr.user = userSysId;
15+
var sysId = gr.insert();
16+
17+
if (sysId) {
18+
gs.addInfoMessage(
19+
"User successfully added to the group. Record Sys ID: " + sysId
20+
);
21+
} else {
22+
throw new Error("Failed to add user to the group.");
23+
}
24+
} catch (error) {
25+
gs.addErrorMessage("Error adding user to group: " + error.message);
26+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
try {
2+
var groupSysId = current.sys_id;
3+
var userSysId = gs.getUserID();
4+
5+
// Validate input
6+
if (!groupSysId || !userSysId) {
7+
throw new Error("Group Sys ID and User Sys ID are required.");
8+
}
9+
10+
// Query the sys_user_grmember table to find the record
11+
var gr = new GlideRecord("sys_user_grmember");
12+
gr.addQuery("group", groupSysId);
13+
gr.addQuery("user", userSysId);
14+
gr.query();
15+
16+
if (gr.next()) {
17+
// Delete the record
18+
var deleted = gr.deleteRecord();
19+
if (deleted) {
20+
gs.addInfoMessage("User successfully removed from the group.");
21+
} else {
22+
throw new Error("Failed to remove user from the group.");
23+
}
24+
} else {
25+
throw new Error("No matching record found for the user in the group.");
26+
}
27+
} catch (error) {
28+
gs.addErrorMessage("Error removing user from group: " + error.message);
29+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Attachment Size Audit
2+
3+
A ServiceNow background script that analyzes your instance's attachment storage and identifies which tables consume the most space and locate oversized files.
4+
5+
## Overview
6+
7+
This read-only script scans all attachments in your instance and provides:
8+
- Total storage used across all attachments
9+
- Storage breakdown by source table (kb_knowledge, sc_task, incident, etc.)
10+
- List of the 25 largest individual attachments
11+
12+
The script does not modify or delete any data—it only reads and reports findings.
13+
14+
## How It Works
15+
16+
The script runs through three main steps:
17+
18+
1. **Calculate Total Storage** - Sums all attachment sizes to give your total storage footprint
19+
2. **Break Down by Table** - Groups attachments by source table to identify which applications consume the most storage
20+
3. **Find Largest Files** - Identifies individual attachments larger than your threshold and lists them in descending order
21+
22+
## Configuration
23+
24+
Before running, adjust these variables at the top of the script:
25+
26+
- `TOP_N_ATTACHMENTS` (default: 25) - Number of largest files to display
27+
- `MIN_SIZE_MB` (default: 5) - Only show attachments larger than this size in MB
28+
- `USE_COMPRESSED_SIZE` (default: true) - Use actual disk size (true) or logical file size (false)
29+
30+
## Prerequisites
31+
32+
- Admin role to execute background scripts
33+
- Global scope (or scoped app with sys_attachment visibility)
34+
- Read access to sys_attachment table
35+
- Access to System Logs to view results
36+
37+
## How to Run
38+
39+
1. Navigate to **System Definition → Scripts - Background**
40+
2. Click **New** and paste the script
41+
3. Optionally adjust configuration variables
42+
4. Click **Execute**
43+
5. View results in **System Diagnostics → System Log** (search for "Attachment Size Audit")
44+
45+
## Sample Output
46+
47+
```
48+
=== Attachment Size Audit Started ===
49+
Using size field: SIZE_COMPRESSED
50+
51+
Total Attachment Storage: 415.28 MB
52+
53+
=== Storage Usage by Table (Descending) ===
54+
invisible.sys_store_app : 175.29 MB
55+
sys_upgrade_manifest : 49.39 MB
56+
ZZ_YYsn_wn_media : 33.50 MB
57+
ZZ_YYdb_image : 28.99 MB
58+
sys_sg_mobile_builder_config : 25.36 MB
59+
ZZ_YYhelp_content : 21.00 MB
60+
incident : 1.18 MB
61+
kb_knowledge : 75.54 KB
62+
63+
=== Top 25 Largest Attachments (>5 MB) ===
64+
[ 68.47 MB ] sncencZZYY.fd254d9443a161100967247e6bb8f200_3_1_3.zip | Table: invisible.sys_store_app | Record: fd254d9443a161100967247e6bb8f200
65+
[ 24.72 MB ] upgrade_manifest.csv | Table: sys_upgrade_manifest | Record: d5ee366b47203210ca05a464116d4328
66+
[ 24.66 MB ] upgrade_manifest.csv | Table: sys_upgrade_manifest | Record: 9ee610ffe17a22108bb2327e625886d0
67+
[ 17.77 MB ] image | Table: ZZ_YYhelp_content | Record: 19d642e347203210ca05a464116d4369
68+
[ 11.63 MB ] sncencZZYY.a77e3ede4df92010f87774ecf02d44f3_28_1_1.zip | Table: invisible.sys_store_app | Record: a77e3ede4df92010f87774ecf02d44f3
69+
70+
=== Attachment Size Audit Complete ===
71+
```
72+
73+
## Use Cases
74+
75+
- **Storage Planning** - Understand current attachment storage and plan for capacity growth
76+
- **Cost Optimization** - Identify storage hotspots for cloud instances to reduce costs
77+
- **Performance Issues** - Find large attachment tables that may be slowing queries
78+
- **Cleanup Strategy** - Identify which tables and files should be targeted for archival or deletion
79+
- **Pre-Upgrade Preparation** - Run before major upgrades to identify optimization opportunities
80+
81+
## Future Enhancement Opportunities
82+
83+
- **Generate Cleanup Script** - Create a companion script to delete old or orphaned attachments with DRY_RUN mode
84+
- **Orphaned Attachment Detection** - Identify attachments where parent records have been deleted
85+
- **File Age Analysis** - Track attachments older than 30/90/365 days to support retention policies
86+
- **File Type Breakdown** - Categorize attachments by extension (PDF, DOCX, MP4, etc.)
87+
- **Email Notifications** - Send automated summaries to storage admins with key metrics
88+
- **Dashboard Widget** - Create PA widget to visualize storage trends over time
89+
- **Scheduled Reporting** - Set up as scheduled job to track growth monthly
90+
- **Duplicate Detection** - Find duplicate attachments on same records for cleanup opportunities
91+
92+
## Safety & Performance
93+
94+
- **Read-only operation** - No data is modified or deleted
95+
- **No infinite loops** - Explicit limits on record processing
96+
- **Timeout prevention** - Efficient aggregate queries for large datasets
97+
- **Sub Pro Testing** - Test in sub-production environments first
98+
99+
100+
## Authors
101+
Masthan Sharif Shaik ( <a href="https://www.linkedin.com/in/nowsharif/" target="_blank">LinkedIn</a> , <a href="https://www.servicenow.com/community/user/viewprofilepage/user-id/668622" target="_blank">SN Community</a> )
102+
103+
## Version History:
104+
* 0.1
105+
* Initial Release
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Background Script: Attachment Size Audit
2+
// Purpose: Analyzes your ServiceNow instance's attachment storage to identify which tables and individual files consume the most space.
3+
//Helps you understand storage usage patterns, locate oversized files, and plan cleanup or archival strategies.
4+
//Provides a read-only audit report without modifying any data.
5+
//
6+
// Author: Masthan Sharif Shaik
7+
// Date: October 2025
8+
// Tested on: Zurich, Yokohama
9+
//
10+
// IMPORTANT: Test in non-production environment first
11+
12+
(function attachmentSizeAudit() {
13+
14+
// ================= CONFIGURATION =================
15+
var TOP_N_ATTACHMENTS = 25; // Number of largest attachments to list
16+
var MIN_SIZE_MB = 5; // Only list attachments larger than this (MB)
17+
var USE_COMPRESSED_SIZE = true; // true = use size_compressed, false = use size_bytes
18+
// =================================================
19+
20+
var sizeField = USE_COMPRESSED_SIZE ? "size_compressed" : "size_bytes";
21+
var totalSizeBytes = 0;
22+
23+
gs.info("=== Attachment Size Audit Started ===");
24+
gs.info("Using size field: " + sizeField.toUpperCase());
25+
26+
// ----------------- TOTAL SIZE --------------------
27+
var totalAgg = new GlideAggregate("sys_attachment");
28+
totalAgg.addAggregate("SUM", sizeField);
29+
totalAgg.query();
30+
if (totalAgg.next()) {
31+
totalSizeBytes = totalAgg.getAggregate("SUM", sizeField);
32+
}
33+
34+
gs.info("Total Attachment Storage: " +
35+
formatBytes(totalSizeBytes));
36+
37+
// ------------- SIZE PER TABLE (AGGREGATED) --------------
38+
gs.info("\n=== Storage Usage by Table (Descending) ===");
39+
40+
var tableAgg = new GlideAggregate("sys_attachment");
41+
tableAgg.groupBy("table_name");
42+
tableAgg.addAggregate("SUM", sizeField);
43+
tableAgg.orderByAggregate("SUM", sizeField);
44+
tableAgg.query();
45+
46+
while (tableAgg.next()) {
47+
var table = tableAgg.getValue("table_name") || "<no table>";
48+
var tableSize = tableAgg.getAggregate("SUM", sizeField);
49+
gs.info(table.padEnd(40) + " : " + formatBytes(tableSize));
50+
}
51+
52+
// --------------- TOP N BIGGEST ATTACHMENTS ---------------
53+
gs.info("\n=== Top " + TOP_N_ATTACHMENTS + " Largest Attachments (>" + MIN_SIZE_MB + " MB) ===");
54+
55+
var attGR = new GlideRecord("sys_attachment");
56+
attGR.addQuery(sizeField, ">", MIN_SIZE_MB * 1024 * 1024);
57+
attGR.orderByDesc(sizeField);
58+
attGR.setLimit(TOP_N_ATTACHMENTS);
59+
attGR.query();
60+
61+
while (attGR.next()) {
62+
gs.info(
63+
"[ " + formatBytes(attGR[sizeField]) + " ] " +
64+
attGR.getValue("file_name") +
65+
" | Table: " + attGR.getValue("table_name") +
66+
" | Record: " + attGR.getValue("table_sys_id")
67+
);
68+
}
69+
70+
gs.info("\n=== Attachment Size Audit Complete ===");
71+
72+
// ------------- FORMATTER ----------------
73+
function formatBytes(bytes) {
74+
bytes = parseInt(bytes, 10) || 0;
75+
if (bytes < 1024) return bytes + " B";
76+
var i = Math.floor(Math.log(bytes) / Math.log(1024));
77+
var sizes = ["B", "KB", "MB", "GB", "TB"];
78+
var value = (bytes / Math.pow(1024, i)).toFixed(2);
79+
return value + " " + sizes[i];
80+
}
81+
82+
})();

0 commit comments

Comments
 (0)