Skip to main content

ServiceNow Scripting Scenarios Answers

Okay, here are solutions for each of the scripting scenarios, presented in Markdown format. I'll provide concise, functional scripts that you can adapt and expand upon. I'll use JavaScript, the primary scripting language within ServiceNow. I'll also include comments to explain key parts of the code.

Important Considerations:

  • Error Handling: For brevity, I've omitted extensive error handling in most scripts. In a production environment, you must add robust error handling (try/catch blocks, logging, etc.).
  • Best Practices: These scripts are examples. Always follow ServiceNow best practices, including using Script Includes for reusable code, avoiding global business rules where possible, and thoroughly testing your scripts.
  • Table and Field Names: I'll use common ServiceNow table and field names (e.g., incident, sys_user, short_description). You may need to adjust these if your instance uses different names.
  • Context: Remember the context where these scripts would run (Client Script, Business Rule, Scheduled Job, etc.). I've indicated this in the comments.
  • GlideRecord Secure: These scripts have been updated to use GlideRecordSecure wherever possible, which is a best practice for security.

Basics

1. Generate Unique Identifier:

// (Business Rule - Before Insert - On your custom table)
(function executeRule(current, previous /*null when async*/) {

    // Simple example: Combine table name, current year, and a sequence number.
    function generateUniqueId(tableName) {
        var gr = new GlideRecord('sys_number');
        gr.addQuery('name', tableName);
        gr.query();
        if (gr.next()) {
            var currentNumber = gr.getValue('number');
            gr.number = parseInt(currentNumber) + 1;
            gr.update();
            return tableName + new Date().getFullYear() + "-" + currentNumber.padStart(5, '0'); // Pad with zeros
        }
        return null; // Handle case where no number record is found
    }

    current.u_unique_id = generateUniqueId(current.getTableName()); // Assuming your field is named 'u_unique_id'

})(current, previous);

2. Update User Department:

// (Business Rule - After Update - On sys_user table)
(function executeRule(current, previous /*null when async*/) {

    // Update department based on job title (example mapping)
    if (current.title.changes() && current.title) { // Check if title changed and is not empty
        var title = current.getValue('title');
        var department = '';

        switch (title.toLowerCase()) {
            case 'software engineer':
                department = 'Engineering';
                break;
            case 'project manager':
                department = 'Project Management';
                break;
            case 'hr specialist':
                department = 'Human Resources';
                break;
                // Add more cases as needed
            default:
                department = 'Other'; // Default department
        }

        var deptGr = new GlideRecordSecure('cmn_department');
		deptGr.addQuery('name', department);
		deptGr.query();
		if (deptGr.next()){
			current.department = deptGr.getUniqueValue();
		}

    }

})(current, previous);

3. Delete Old Records:

// (Scheduled Job)
(function() {

    var cutoffDate = new GlideDateTime();
    cutoffDate.addDays(-365); // Delete records older than 1 year

    var gr = new GlideRecordSecure('your_table_name'); // Replace with your table name
    gr.addQuery('sys_created_on', '<', cutoffDate);
    gr.query();
    gr.deleteMultiple(); // Use deleteMultiple for bulk deletion (more efficient)

    gs.info("Deleted " + gr.getRowCount() + " old records from your_table_name.");

})();

4. High-Priority Incident Notification:

// (Business Rule - After Insert - On incident table)
(function executeRule(current, previous /*null when async*/) {

    if (current.priority == 1) { // Assuming priority 1 is "High"
        gs.eventQueue('incident.high_priority', current, gs.getUserID(), gs.getUserName());
        // Or, use direct email sending:
        /*
        var email = new GlideEmailOutbound();
        email.setSubject('High Priority Incident Created: ' + current.number);
        email.setBody('A high-priority incident has been created: ' + current.getLink());
        email.addTo('recipient@example.com'); // Replace with recipient
        email.send();
        */
    }

})(current, previous);

5. Task Assignment:

// (Business Rule - Before Insert/Update - On task table)
(function executeRule(current, previous /*null when async*/) {

    // Assign task to a group based on category
    if (current.category) { //check if it has category
        var category = current.getValue('category');
        var assignmentGroup = '';

        switch (category) {
            case 'software':
                assignmentGroup = 'Software Support';
                break;
            case 'hardware':
                assignmentGroup = 'Hardware Support';
                break;
                // Add more cases
            default:
               return;
        }

        var groupGr = new GlideRecordSecure('sys_user_group');
		groupGr.addQuery('name', assignmentGroup);
		groupGr.query();
		if (groupGr.next()){
			current.assignment_group = groupGr.getUniqueValue();
		}
    }

})(current, previous);

6. Form Input Validation:

// (Client Script - OnSubmit - On your custom table)
function onSubmit() {

    // Validate that a required field is not empty
    if (g_form.getValue('u_my_required_field') == '') {
        g_form.addErrorMessage('My Required Field cannot be empty.');
        return false; // Prevent form submission
    }

    // Validate a number field is within a range
    var numValue = parseInt(g_form.getValue('u_my_number_field'));
    if (isNaN(numValue) || numValue < 1 || numValue > 100) {
        g_form.addErrorMessage('My Number Field must be between 1 and 100.');
        return false;
    }

    return true; // Allow submission if all validations pass
}

7. Update User Location:

// (Business Rule - After Update - On cmn_department table  OR  Scheduled Job)
(function executeRule(current, previous /*null when async*/) {

    // Get the location of the department.
    var departmentLocation = current.location;  // Assuming department has a location

    // Update all users in the specified department
    var userGr = new GlideRecordSecure('sys_user');
    userGr.addQuery('department', current.sys_id);
    userGr.query();

    while (userGr.next()) {
        userGr.location = departmentLocation;
        userGr.update(); // Important:  Update each user record
    }
})(current, previous);

// ALTERNATIVELY:  Scheduled Job to run periodically
/*
(function() {
    var deptGr = new GlideRecord('cmn_department');
    deptGr.addQuery('name', 'Engineering'); // Example department
    deptGr.query();
    if (deptGr.next()) {
        var deptLocation = deptGr.location;

        var userGr = new GlideRecord('sys_user');
        userGr.addQuery('department', deptGr.sys_id);
        userGr.query();
        while (userGr.next()) {
            userGr.location = deptLocation;
            userGr.update();
        }
    }
})();
*/

8. Close Incidents on Deactivation:

// (Business Rule - Before Update - On sys_user table)
(function executeRule(current, previous /*null when async*/) {

    if (current.active.changesTo(false)) { // Check if the user is being deactivated
        var incGr = new GlideRecordSecure('incident');
        incGr.addQuery('caller_id', current.sys_id);
        incGr.addActiveQuery(); // Only open incidents
        incGr.query();

        while (incGr.next()) {
            incGr.incident_state = 7; // Assuming 7 is the "Closed" state value
            incGr.comments = 'Incident automatically closed due to user deactivation.';
            incGr.update();
        }
    }

})(current, previous);

9. Export Data to Excel:

// (Background Script -  Use with caution, can impact performance)
//  Better approach:  Use a Scheduled Report or a REST API for large exports.
//  This is a simplified example for a small dataset.

(function() {

    var gr = new GlideRecordSecure('incident'); // Example: Export incidents
    gr.setLimit(100);  // Limit the number of records for testing
    gr.query();

    var data = [];
    data.push(['Number', 'Short Description', 'State', 'Opened At']); // Header row

    while (gr.next()) {
        data.push([
            gr.getValue('number'),
            gr.getValue('short_description'),
            gr.getDisplayValue('incident_state'), // Get display value for choice fields
            gr.getValue('opened_at')
        ]);
    }

    // In a real scenario, you'd use a library (like SheetJS) to create an Excel file.
    // For this example, we'll just log the data in a CSV-like format:
    for (var i = 0; i < data.length; i++) {
        gs.info(data[i].join(','));
    }

})();

10. Calculate Total Incident Cost:

// (Scheduled Job  OR  Business Rule to update a custom field)

(function() {

    var totalCost = 0;
    var gr = new GlideRecordSecure('incident');
    gr.addActiveQuery(); // Only open incidents
    gr.query();

    while (gr.next()) {
        // Assuming you have a 'u_cost' field on the incident table
        totalCost += parseFloat(gr.getValue('u_cost') || 0); // Handle null/empty values
    }

    gs.info('Total cost of open incidents: ' + totalCost);

    // To update a field (e.g., on a custom table to store this value):
    /*
    var summaryGr = new GlideRecord('u_incident_summary');
    summaryGr.get('your_record_sys_id'); // Get the specific record to update
    summaryGr.u_total_cost = totalCost;
    summaryGr.update();
    */

})();

Advanced GlideRecord Queries

1. Incidents for CI:

var ciSysId = 'your_ci_sys_id'; // Replace with the actual sys_id of the CI
var gr = new GlideRecordSecure('incident');
gr.addQuery('cmdb_ci', ciSysId);
gr.query();
while (gr.next()) {
    gs.info('Incident: ' + gr.number);
}

2. Active Users in Domain:

var domain = 'your_domain_name'; // Replace with the domain name
var gr = new GlideRecordSecure('sys_user');
gr.addQuery('sys_domain', domain);
gr.addActiveQuery(); // Only active users
gr.query();
while (gr.next()) {
    gs.info('User: ' + gr.user_name);
}

3. Open Incidents for Group:

var groupSysId = 'your_group_sys_id'; // Replace with the group's sys_id
var gr = new GlideRecordSecure('incident');
gr.addQuery('assignment_group', groupSysId);
gr.addActiveQuery();
gr.query();
while (gr.next()) {
    gs.info('Incident: ' + gr.number);
}

4. Problems for Incident:

var incidentSysId = 'your_incident_sys_id'; // Replace with the incident's sys_id
var gr = new GlideRecordSecure('problem');
gr.addQuery('rfc', incidentSysId); // Assuming 'rfc' field links to the incident
gr.query();
while (gr.next()) {
    gs.info('Problem: ' + gr.number);
}

5. Incidents by Priority and Group:

var priority = 1; // Example: Priority 1
var groupSysId = 'your_group_sys_id';
var gr = new GlideRecordSecure('incident');
gr.addQuery('priority', priority);
gr.addQuery('assignment_group', groupSysId);
gr.query();
while (gr.next()) {
    gs.info('Incident: ' + gr.number);
}

6. Changes for Maintenance Window:

var windowStart = new GlideDateTime('2024-03-15 22:00:00'); // Example start time
var windowEnd = new GlideDateTime('2024-03-16 06:00:00');   // Example end time

var gr = new GlideRecordSecure('change_request');
gr.addQuery('start_date', '>=', windowStart);
gr.addQuery('end_date', '<=', windowEnd);
// OR, if you have a dedicated maintenance window table:
// gr.addQuery('maintenance_window', 'your_window_sys_id');
gr.query();
while (gr.next()) {
    gs.info('Change: ' + gr.number);
}

7. Open Tasks by Group and Due Date:

var groupSysId = 'your_group_sys_id';
var dueDate = new GlideDateTime('2024-03-20'); // Example due date

var gr = new GlideRecordSecure('task'); // Or a specific task table like 'sc_task'
gr.addQuery('assignment_group', groupSysId);
gr.addQuery('due_date', '<=', dueDate);
gr.addActiveQuery();
gr.query();
while (gr.next()) {
    gs.info('Task: ' + gr.number);
}

8. Knowledge Articles by Category:

var categorySysId = 'your_category_sys_id'; // Replace with the category's sys_id
var gr = new GlideRecordSecure('kb_knowledge');
gr.addQuery('kb_category', categorySysId);
gr.query();
while (gr.next()) {
    gs.info('Article: ' + gr.short_description);
}

9. Catalog Items by Category and Price:

var categorySysId = 'your_category_sys_id';
var price = 100; // Example price

var gr = new GlideRecordSecure('sc_cat_item');
gr.addQuery('category', categorySysId);
gr.addQuery('price', '<=', price);  // Or '>=', '=', etc.
gr.query();
while (gr.next()) {
    gs.info('Item: ' + gr.name);
}

10. Users by Department and Job Title:

var departmentSysId = 'your_department_sys_id';
var jobTitle = 'Software Engineer';

var gr = new GlideRecordSecure('sys_user');
gr.addQuery('department', departmentSysId);
gr.addQuery('title', jobTitle);
gr.query();
while (gr.next()) {
    gs.info('User: ' + gr.user_name);
}

UI Policies and Client Scripts

1. Short Description Format:

// (UI Policy - On Incident table)
// Condition:  (Leave blank to apply to all records)
// Script:  Execute if true:

function onCondition() {
  g_form.getControl('short_description').style.textTransform = 'uppercase'; // Example:  Force uppercase
  // Or, use a regular expression to enforce a more complex format
}

2. Client-Side Form Validation: (See example #6 in Basics)

3. Hide/Disable Fields by Role:

// (UI Policy - On your table)
// Condition:  gs.hasRole('itil')  (Example:  Only for ITIL users)
// Script:  Execute if true:

function onCondition() {
    g_form.setVisible('u_my_field', false); // Hide the field
    g_form.setDisabled('u_another_field', true); // Disable the field
}

// Script:  Execute if false: (Optional - to show/enable fields for other roles)

function onCondition() {
    g_form.setVisible('u_my_field', true);
    g_form.setDisabled('u_another_field', false);
}

4. Auto-Populate Fields:

// (Client Script - OnChange - On the field that triggers the auto-population)
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
   if (isLoading || newValue === '') {
      return;
   }

   // Example:  Auto-populate the 'assigned_to' field based on the 'assignment_group'
   if (g_form.getValue('assignment_group') == 'your_group_sys_id') {
       g_form.setValue('assigned_to', 'user_sys_id'); // Set to a specific user
   }

    //Example: Populate the 'location' field based on the 'caller_id'
	var caller = g_form.getReference('caller_id', setLocation); // Use getReference for related fields
}
	
function setLocation(caller) {
	if(caller){
		g_form.setValue('location', caller.location);
	}
}

5. Conditional Mandatory Field:

// (UI Policy - On your table)
// Condition:  current.u_my_trigger_field == 'some_value'  (Example condition)
// Script:  Execute if true:

function onCondition() {
    g_form.setMandatory('u_my_dependent_field', true);
}

// Script:  Execute if false:

function onCondition() {
    g_form.setMandatory('u_my_dependent_field', false);
}

6. Auto-Complete Field:

// (Client Script - OnLoad - On your table)
//  Requires creating a Script Include to handle the server-side query.

function onLoad() {

    // This is a simplified example.  For a robust auto-complete, you'd use
    // AJAX and a Script Include to query the server as the user types.

    g_form.getElement('u_my_autocomplete_field').setAttribute('autocomplete', 'off'); // Disable browser autocomplete

    g_form.getElement('u_my_autocomplete_field').addEventListener('keyup', function(event) {
        var input = g_form.getValue('u_my_autocomplete_field');
        if (input.length > 2) { // Start suggesting after 2 characters
            // Call a Script Include via GlideAjax to get suggestions
            var ga = new GlideAjax('MyAutocompleteUtil'); // Replace with your Script Include name
            ga.addParam('sysparm_name', 'getSuggestions');
            ga.addParam('sysparm_input', input);
            ga.getXML(handleSuggestions);
        }
    });

    function handleSuggestions(response) {
        var suggestions = response.responseXML.documentElement.getAttribute("answer");
        // suggestions will be a comma-separated string of sys_ids (from the Script Include)
        // You'd then display these suggestions in a dropdown or similar UI element.
        // (This part requires more complex UI manipulation and is beyond a simple example.)
    }
}


// --- Script Include: MyAutocompleteUtil ---
// (Client callable: true)

var MyAutocompleteUtil = Class.create();
MyAutocompleteUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    getSuggestions: function() {
        var input = this.getParameter('sysparm_input');
        var suggestions = [];

        var gr = new GlideRecordSecure('sys_user'); // Example:  Suggest users
        gr.addQuery('user_name', 'STARTSWITH', input);
        gr.setLimit(10); // Limit the number of suggestions
        gr.query();

        while (gr.next()) {
            suggestions.push(gr.getUniqueValue()); // Add sys_id to the suggestions array
        }

        return suggestions.join(','); // Return as a comma-separated string
    },

    type: 'MyAutocompleteUtil'
});

7. Date/Time Format:

// (UI Policy - On your table)
// Condition: (Leave blank to apply to all records)
// Script: Execute if true:
function onCondition() {
    //This is usually handled by user preferences, but can be forced with a UI policy
    // This does *not* change the underlying data, only the display.
    g_form.getControl('your_date_time_field').style.dateFormat = 'yyyy-MM-dd HH:mm:ss'; // Example format
}

8. Unsaved Changes Warning:

// (Client Script - OnLoad - On your table)

function onLoad() {
    g_form.enableUnloadConfirm(); // Enable the confirmation dialog
}

9. Show/Hide Sections:

//(UI Policy - On your table)
//Condition: current.u_my_trigger_field == 'some_value'
//Script: Execute if true:

function onCondition() {
    g_form.setSectionDisplay('your_section_name', false); // Hide the section
}

//Script: Execute if false:
function onCondition() {
    g_form.setSectionDisplay('your_section_name', true); // Show the section
}

10. Update Field Based on Others:

// (Client Script - OnChange - On one of the fields that triggers the update)

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
   if (isLoading || newValue === '') {
      return;
   }

    // Example: Calculate a 'total' field based on 'quantity' and 'price'
    var quantity = parseInt(g_form.getValue('u_quantity') || 0);
    var price = parseFloat(g_form.getValue('u_price') || 0);
    var total = quantity * price;
    g_form.setValue('u_total', total);
}

Script Includes and Server-Side Scripting

1. Task Due Date Calculation:

// Script Include: TaskDueDateCalculator
// (Client callable:  false)

var TaskDueDateCalculator = Class.create();
TaskDueDateCalculator.prototype = {
    initialize: function() {
    },

    calculateDueDate: function(priority, startDate) {
        // startDate should be a GlideDateTime object
        var dueDate = new GlideDateTime(startDate);

        switch (parseInt(priority)) {
            case 1: // High
                dueDate.addDays(1);
                break;
            case 2: // Medium
                dueDate.addDays(3);
                break;
            case 3: // Low
                dueDate.addDays(7);
                break;
            default:
                dueDate.addDays(7); // Default
        }

        return dueDate;
    },

    type: 'TaskDueDateCalculator'
};


// Example usage (in a Business Rule):
/*
(function executeRule(current, previous) {
    var calculator = new TaskDueDateCalculator();
    var startDate = new GlideDateTime(current.sys_created_on); // Use creation date as start
    current.due_date = calculator.calculateDueDate(current.priority, startDate);

})(current, previous);
*/

2. Phone Number Validation/Formatting:

// Script Include: PhoneNumberUtil
// (Client callable: true)

var PhoneNumberUtil = Class.create();
PhoneNumberUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    formatPhoneNumber: function(phoneNumber) {
        // Basic example:  Format as (XXX) XXX-XXXX
        var cleaned = ('' + phoneNumber).replace(/\D/g, ''); // Remove non-digits
        var match = cleaned.match(/^(\d{3})(\d{3})(\d{4})$/);

        if (match) {
            return '(' + match[1] + ') ' + match[2] + '-' + match[3];
        }
        return phoneNumber; // Return original if no match (or handle differently)
    },

    validatePhoneNumber: function(phoneNumber) {
        var cleaned = ('' + phoneNumber).replace(/\D/g, '');
        return /^\d{10}$/.test(cleaned);  // Example: Validate 10-digit number
    },

    type: 'PhoneNumberUtil'
});

// Example Client Script usage (OnChange):
/*
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
   if (isLoading || newValue === '') {
      return;
   }

    var util = new GlideAjax('PhoneNumberUtil');
    util.addParam('sysparm_name', 'formatPhoneNumber');
    util.addParam('sysparm_phone', newValue);
    util.getXMLAnswer(function(answer) {
        g_form.setValue('u_phone_number', answer); // Update the field with the formatted number
    });
}
*/

3. Manager Approval Request:

// Script Include: ApprovalUtil
// (Client callable: false)

var ApprovalUtil = Class.create();
ApprovalUtil.prototype = {
    initialize: function() {
    },

    requestManagerApproval: function(recordSysId, tableName) {
        var gr = new GlideRecordSecure(tableName);
        if (gr.get(recordSysId)) {
            var manager = gr.caller_id.manager; // Assuming the record has a 'caller_id' field

            if (manager) {
                var approval = new GlideRecord('sysapproval_approver');
                approval.initialize();
                approval.state = 'requested';
                approval.sysapproval = recordSysId;
                approval.approver = manager;
                approval.document_id = recordSysId;
                approval.source_table = tableName;
                approval.insert();
                return true;
            }
        }
        return false;
    },

    type: 'ApprovalUtil'
};

//Example usage (in a Business Rule):
/*
(function executeRule(current, previous) {

    var approvalUtil = new ApprovalUtil();
    approvalUtil.requestManagerApproval(current.sys_id, current.getTableName());

})(current, previous);
*/

4. Custom Incident Number:

// Script Include: IncidentNumberUtil
// (Client callable: false)

var IncidentNumberUtil = Class.create();
IncidentNumberUtil.prototype = {
    initialize: function() {
    },

   getNextIncidentNumber: function() {
        var prefix = 'INC';
        var year = new Date().getFullYear();
        var sequenceField = 'u_incident_sequence'; // Custom field to store the sequence

        // Get the sequence record (create it if it doesn't exist)
        var seqGr = new GlideRecordSecure('u_custom_sequence'); // Or use sys_number table
        seqGr.addQuery('u_table_name', 'incident'); // Assuming a field to identify the table
		seqGr.query();
        var nextSeq;

        if (!seqGr.next()) {
            seqGr.initialize();
            seqGr.u_table_name = 'incident';
            seqGr.u_incident_sequence = 1;
            seqGr.insert();
            nextSeq = 1;
        } else {
            nextSeq = parseInt(seqGr.getValue(sequenceField)) + 1;
            seqGr.setValue(sequenceField, nextSeq);
            seqGr.update();
        }

        return prefix + year + '-' + String(nextSeq).padStart(5, '0'); // INC2024-00001
    },

    type: 'IncidentNumberUtil'
};

// Example usage (in a Business Rule - Before Insert - On incident table):
/*
(function executeRule(current, previous) {

    var util = new IncidentNumberUtil();
    current.number = util.getNextIncidentNumber();

})(current, previous);
*/

5. Data Encryption/Decryption:

// Script Include: EncryptionUtil
// (Client callable: false)
//  Requires the Encryption Support plugin to be activated.

var EncryptionUtil = Class.create();
EncryptionUtil.prototype = {
    initialize: function() {
        this.encryptionContext = 'your_encryption_context_sys_id'; // Replace!
    },

    encryptData: function(plainText) {
        if (!plainText) {
            return '';
        }
        var encrypter = new GlideEncrypter();
        return encrypter.encrypt(plainText, this.encryptionContext);
    },

    decryptData: function(encryptedText) {
         if (!encryptedText) {
            return '';
        }
        var encrypter = new GlideEncrypter();
        return encrypter.decrypt(encryptedText, this.encryptionContext);
    },

    type: 'EncryptionUtil'
};
// Example usage:
/*
var util = new EncryptionUtil();
var encrypted = util.encryptData('my secret data');
gs.info('Encrypted: ' + encrypted);
var decrypted = util.decryptData(encrypted);
gs.info('Decrypted: ' + decrypted);
*/

6. Unique Record Code: (Similar to #1 in Basics - See that example)

// Script Include: IncidentUtil
// (Client callable: false)

var IncidentUtil = Class.create();
IncidentUtil.prototype = {
    initialize: function() {
    },

    updateRelatedTasks: function(incidentSysId) {
        var taskGr = new GlideRecordSecure('task'); // Or a specific task table
        taskGr.addQuery('parent', incidentSysId); // Assuming 'parent' field links to the incident
        taskGr.addActiveQuery();
        taskGr.query();

        while (taskGr.next()) {
            taskGr.state = 3; // Assuming 3 is the "Closed Complete" state
            taskGr.comments = 'Task closed automatically due to incident closure.';
            taskGr.update();
        }
    },

    type: 'IncidentUtil'
};

//Example usage (in a Business Rule - After Update - On incident table):
/*
(function executeRule(current, previous) {

    if (current.incident_state.changesTo(7)) { // Assuming 7 is "Closed"
        var util = new IncidentUtil();
        util.updateRelatedTasks(current.sys_id);
    }

})(current, previous);
*/

8. Service Catalog Request Cost:

// Script Include: RequestCostCalculator
// (Client callable: false)

var RequestCostCalculator = Class.create();
RequestCostCalculator.prototype = {
    initialize: function() {
    },

    calculateRequestCost: function(requestSysId) {
        var totalCost = 0;
        var itemGr = new GlideRecordSecure('sc_req_item');
        itemGr.addQuery('request', requestSysId);
        itemGr.query();

        while (itemGr.next()) {
            totalCost += parseFloat(itemGr.price || 0) * parseInt(itemGr.quantity || 1);
            // Consider options/variables that might affect cost
        }

        return totalCost;
    },

    type: 'RequestCostCalculator'
};

//Example usage (in a Business Rule - After Update - On sc_request table):
/*
(function executeRule(current, previous) {

    var calculator = new RequestCostCalculator();
    current.u_total_cost = calculator.calculateRequestCost(current.sys_id); // Store in a custom field

})(current, previous);
*/

9. Group Users and Manager Info:

// Script Include: GroupInfoUtil
// (Client callable:  true/false, depending on how you use it)
var GroupInfoUtil = Class.create();
GroupInfoUtil.prototype =  Object.extendsObject(AbstractAjaxProcessor,{
    initialize: function() {
    },

    getGroupMembersAndManagers: function(groupSysId) {
        var members = [];
        var userGr = new GlideRecordSecure('sys_user_grmember');
        userGr.addQuery('group', groupSysId);
        userGr.query();

        while (userGr.next()) {
            var user = userGr.user.getRefRecord(); // Efficiently get the user record
            if (user.isValidRecord() && user.active) { //check if its valid and active
				var manager = user.manager.getRefRecord();
				var managerName = manager.isValidRecord() ? manager.getValue('name') : 'No Manager'; //check if manager is valid
				members.push({
					user_name: user.getValue('user_name'),
					email: user.getValue('email'),
					manager: managerName
				});
			}
        }

        return members;  // Return an array of objects
    },

    type: 'GroupInfoUtil'
});

// Example usage (can be used in a client script with GlideAjax, or server-side):
/*
// Server-side:
var util = new GroupInfoUtil();
var groupInfo = util.getGroupMembersAndManagers('your_group_sys_id');
for (var i = 0; i < groupInfo.length; i++) {
    gs.info('User: ' + groupInfo[i].user_name + ', Manager: ' + groupInfo[i].manager);
}

// Client-side (with GlideAjax):
var ga = new GlideAjax('GroupInfoUtil');
ga.addParam('sysparm_name', 'getGroupMembersAndManagers');
ga.addParam('sysparm_group', g_form.getValue('assignment_group')); // Example
ga.getXMLAnswer(function(answer) {
    var members = JSON.parse(answer); // Parse the JSON response
     for (var i = 0; i < members.length; i++) {
        console.log('User: ' + members[i].user_name + ', Manager: ' + members[i].manager);
    }
});
*/

10. Email Notification with Incident Details:

// Script Include: IncidentNotificationUtil
// (Client callable: false)
var IncidentNotificationUtil = Class.create();
IncidentNotificationUtil.prototype = {
    initialize: function() {
    },

    sendIncidentNotification: function(incidentSysId, recipientEmail