diff --git a/Server-Side Components/Background Scripts/Attachment Size Audit/README.md b/Server-Side Components/Background Scripts/Attachment Size Audit/README.md new file mode 100644 index 0000000000..c9adb86ed7 --- /dev/null +++ b/Server-Side Components/Background Scripts/Attachment Size Audit/README.md @@ -0,0 +1,105 @@ +# Attachment Size Audit + +A ServiceNow background script that analyzes your instance's attachment storage and identifies which tables consume the most space and locate oversized files. + +## Overview + +This read-only script scans all attachments in your instance and provides: +- Total storage used across all attachments +- Storage breakdown by source table (kb_knowledge, sc_task, incident, etc.) +- List of the 25 largest individual attachments + +The script does not modify or delete any data—it only reads and reports findings. + +## How It Works + +The script runs through three main steps: + +1. **Calculate Total Storage** - Sums all attachment sizes to give your total storage footprint +2. **Break Down by Table** - Groups attachments by source table to identify which applications consume the most storage +3. **Find Largest Files** - Identifies individual attachments larger than your threshold and lists them in descending order + +## Configuration + +Before running, adjust these variables at the top of the script: + +- `TOP_N_ATTACHMENTS` (default: 25) - Number of largest files to display +- `MIN_SIZE_MB` (default: 5) - Only show attachments larger than this size in MB +- `USE_COMPRESSED_SIZE` (default: true) - Use actual disk size (true) or logical file size (false) + +## Prerequisites + +- Admin role to execute background scripts +- Global scope (or scoped app with sys_attachment visibility) +- Read access to sys_attachment table +- Access to System Logs to view results + +## How to Run + +1. Navigate to **System Definition → Scripts - Background** +2. Click **New** and paste the script +3. Optionally adjust configuration variables +4. Click **Execute** +5. View results in **System Diagnostics → System Log** (search for "Attachment Size Audit") + +## Sample Output + +``` +=== Attachment Size Audit Started === +Using size field: SIZE_COMPRESSED + +Total Attachment Storage: 415.28 MB + +=== Storage Usage by Table (Descending) === +invisible.sys_store_app : 175.29 MB +sys_upgrade_manifest : 49.39 MB +ZZ_YYsn_wn_media : 33.50 MB +ZZ_YYdb_image : 28.99 MB +sys_sg_mobile_builder_config : 25.36 MB +ZZ_YYhelp_content : 21.00 MB +incident : 1.18 MB +kb_knowledge : 75.54 KB + +=== Top 25 Largest Attachments (>5 MB) === +[ 68.47 MB ] sncencZZYY.fd254d9443a161100967247e6bb8f200_3_1_3.zip | Table: invisible.sys_store_app | Record: fd254d9443a161100967247e6bb8f200 +[ 24.72 MB ] upgrade_manifest.csv | Table: sys_upgrade_manifest | Record: d5ee366b47203210ca05a464116d4328 +[ 24.66 MB ] upgrade_manifest.csv | Table: sys_upgrade_manifest | Record: 9ee610ffe17a22108bb2327e625886d0 +[ 17.77 MB ] image | Table: ZZ_YYhelp_content | Record: 19d642e347203210ca05a464116d4369 +[ 11.63 MB ] sncencZZYY.a77e3ede4df92010f87774ecf02d44f3_28_1_1.zip | Table: invisible.sys_store_app | Record: a77e3ede4df92010f87774ecf02d44f3 + +=== Attachment Size Audit Complete === +``` + +## Use Cases + +- **Storage Planning** - Understand current attachment storage and plan for capacity growth +- **Cost Optimization** - Identify storage hotspots for cloud instances to reduce costs +- **Performance Issues** - Find large attachment tables that may be slowing queries +- **Cleanup Strategy** - Identify which tables and files should be targeted for archival or deletion +- **Pre-Upgrade Preparation** - Run before major upgrades to identify optimization opportunities + +## Future Enhancement Opportunities + +- **Generate Cleanup Script** - Create a companion script to delete old or orphaned attachments with DRY_RUN mode +- **Orphaned Attachment Detection** - Identify attachments where parent records have been deleted +- **File Age Analysis** - Track attachments older than 30/90/365 days to support retention policies +- **File Type Breakdown** - Categorize attachments by extension (PDF, DOCX, MP4, etc.) +- **Email Notifications** - Send automated summaries to storage admins with key metrics +- **Dashboard Widget** - Create PA widget to visualize storage trends over time +- **Scheduled Reporting** - Set up as scheduled job to track growth monthly +- **Duplicate Detection** - Find duplicate attachments on same records for cleanup opportunities + +## Safety & Performance + +- **Read-only operation** - No data is modified or deleted +- **No infinite loops** - Explicit limits on record processing +- **Timeout prevention** - Efficient aggregate queries for large datasets +- **Sub Pro Testing** - Test in sub-production environments first + + +## Authors +Masthan Sharif Shaik ( LinkedIn , SN Community ) + +## Version History: +* 0.1 + * Initial Release diff --git a/Server-Side Components/Background Scripts/Attachment Size Audit/attachmentSizeAudit.js b/Server-Side Components/Background Scripts/Attachment Size Audit/attachmentSizeAudit.js new file mode 100644 index 0000000000..9956c91df3 --- /dev/null +++ b/Server-Side Components/Background Scripts/Attachment Size Audit/attachmentSizeAudit.js @@ -0,0 +1,82 @@ +// Background Script: Attachment Size Audit +// Purpose: Analyzes your ServiceNow instance's attachment storage to identify which tables and individual files consume the most space. +//Helps you understand storage usage patterns, locate oversized files, and plan cleanup or archival strategies. +//Provides a read-only audit report without modifying any data. +// +// Author: Masthan Sharif Shaik +// Date: October 2025 +// Tested on: Zurich, Yokohama +// +// IMPORTANT: Test in non-production environment first + +(function attachmentSizeAudit() { + + // ================= CONFIGURATION ================= + var TOP_N_ATTACHMENTS = 25; // Number of largest attachments to list + var MIN_SIZE_MB = 5; // Only list attachments larger than this (MB) + var USE_COMPRESSED_SIZE = true; // true = use size_compressed, false = use size_bytes + // ================================================= + + var sizeField = USE_COMPRESSED_SIZE ? "size_compressed" : "size_bytes"; + var totalSizeBytes = 0; + + gs.info("=== Attachment Size Audit Started ==="); + gs.info("Using size field: " + sizeField.toUpperCase()); + + // ----------------- TOTAL SIZE -------------------- + var totalAgg = new GlideAggregate("sys_attachment"); + totalAgg.addAggregate("SUM", sizeField); + totalAgg.query(); + if (totalAgg.next()) { + totalSizeBytes = totalAgg.getAggregate("SUM", sizeField); + } + + gs.info("Total Attachment Storage: " + + formatBytes(totalSizeBytes)); + + // ------------- SIZE PER TABLE (AGGREGATED) -------------- + gs.info("\n=== Storage Usage by Table (Descending) ==="); + + var tableAgg = new GlideAggregate("sys_attachment"); + tableAgg.groupBy("table_name"); + tableAgg.addAggregate("SUM", sizeField); + tableAgg.orderByAggregate("SUM", sizeField); + tableAgg.query(); + + while (tableAgg.next()) { + var table = tableAgg.getValue("table_name") || ""; + var tableSize = tableAgg.getAggregate("SUM", sizeField); + gs.info(table.padEnd(40) + " : " + formatBytes(tableSize)); + } + + // --------------- TOP N BIGGEST ATTACHMENTS --------------- + gs.info("\n=== Top " + TOP_N_ATTACHMENTS + " Largest Attachments (>" + MIN_SIZE_MB + " MB) ==="); + + var attGR = new GlideRecord("sys_attachment"); + attGR.addQuery(sizeField, ">", MIN_SIZE_MB * 1024 * 1024); + attGR.orderByDesc(sizeField); + attGR.setLimit(TOP_N_ATTACHMENTS); + attGR.query(); + + while (attGR.next()) { + gs.info( + "[ " + formatBytes(attGR[sizeField]) + " ] " + + attGR.getValue("file_name") + + " | Table: " + attGR.getValue("table_name") + + " | Record: " + attGR.getValue("table_sys_id") + ); + } + + gs.info("\n=== Attachment Size Audit Complete ==="); + + // ------------- FORMATTER ---------------- + function formatBytes(bytes) { + bytes = parseInt(bytes, 10) || 0; + if (bytes < 1024) return bytes + " B"; + var i = Math.floor(Math.log(bytes) / Math.log(1024)); + var sizes = ["B", "KB", "MB", "GB", "TB"]; + var value = (bytes / Math.pow(1024, i)).toFixed(2); + return value + " " + sizes[i]; + } + +})();