|
| 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