sachin_namjoshi
Kilo Patron

Problem:

ServiceNow OOB provides subscription usage module which allows users to see usage of their allocated roles, licenses. This is great for managing license and proactively take actions for license allocation.

 

But, There is no OOB way which tells the unused plugins on the instance.

 

Solution:

 

I have created below fix script which does this job and prints unused plugins information on your instance.

 

(function () {

    var results = [];

    var pluginGR = new GlideRecord('sys_plugins');
    pluginGR.addQuery('active', true);
    pluginGR.query();

    while (pluginGR.next()) {

        var pluginName = pluginGR.getValue('name');
        var pluginTitle = pluginGR.getValue('title');

        
        if (pluginName.indexOf('com.glide') === 0 ||
            pluginName.indexOf('com.snc.platform') === 0 ||
            pluginName.indexOf('com.snc.core') === 0) {
            continue;
        }

        var confidence = 100;
        var reasons = [];

   
        var tableFound = false;
        var tableHasData = false;

        var tableGR = new GlideRecord('sys_db_object');
        tableGR.addQuery('sys_package', pluginName);
        tableGR.query();

        while (tableGR.next()) {
            tableFound = true;
            try {
                var dataGR = new GlideRecord(tableGR.getValue('name'));
                dataGR.setLimit(1);
                dataGR.query();
                if (dataGR.hasNext()) {
                    tableHasData = true;
                    break;
                }
            } catch (e) {
                // ignore inaccessible tables
            }
        }

        if (tableHasData) {
            confidence -= 50;
            reasons.push('Plugin tables contain data');
        } else if (tableFound) {
            confidence -= 10;
            reasons.push('Plugin tables exist but are empty');
        } else {
            reasons.push('No plugin tables found');
        }

 
        var roleFound = false;
        var roleAssigned = false;

        var roleGR = new GlideRecord('sys_user_role');
        roleGR.addQuery('sys_package', pluginName);
        roleGR.query();

        while (roleGR.next()) {
            roleFound = true;

            var userRoleGR = new GlideRecord('sys_user_has_role');
            userRoleGR.addQuery('role', roleGR.sys_id);
            userRoleGR.setLimit(1);
            userRoleGR.query();

            if (userRoleGR.hasNext()) {
                roleAssigned = true;
                break;
            }
        }

        if (roleAssigned) {
            confidence -= 40;
            reasons.push('Plugin roles assigned to users');
        } else if (roleFound) {
            confidence -= 5;
            reasons.push('Plugin roles exist but not assigned');
        } else {
            reasons.push('No plugin roles found');
        }

        if (confidence < 0) confidence = 0;

        // Show only likely unused plugins
        if (confidence >= 70) {
            results.push({
                name: pluginName,
                title: pluginTitle,
                confidence: confidence,
                reasons: reasons.join('; ')
            });
        }
    }


 

    results.sort(function (a, b) {
        return b.confidence - a.confidence;
    });

    for (var i = 0; i < results.length; i++) {
        gs.print(
            results[i].confidence + '% | ' +
            results[i].name + ' | ' +
            results[i].title + ' | ' +
            results[i].reasons
        );
    }

    gs.print('Total likely unused plugins: ' + results.length);

})();

 

Sample Output:

 

 

*** Script: 100% | Key Management Framework Scoped App | null | No plugin tables found; No plugin roles found
*** Script: 100% | Call Chain Tracking | null | No plugin tables found; No plugin roles found
*** Script: 100% | Email Address Internationalization | null | No plugin tables found; No plugin roles found
*** Script: 100% | Homepage Splash Page | null | No plugin tables found; No plugin roles found
*** Script: 100% | sn-custom-tinymce-scoped-app | null | No plugin tables found; No plugin roles found

 

Comments
JenniferRah
Mega Sage

This is very helpful, but I found a few issues with the script. The plugin name is in a field called "source" and the plugin title is in the field called "name". I also changed your table lookup to use the name of the sys_package variable since it's a reference field and was storing a sys_id rather than the plugin name. Here is my updated script.

 

(function () {

    var results = [];

    var pluginGR = new GlideRecord('sys_plugins');
    pluginGR.addQuery('active', true);
    pluginGR.query();

    while (pluginGR.next()) {

        var pluginName = pluginGR.getValue('source');
        var pluginTitle = pluginGR.getValue('name');

        
        if (pluginName.indexOf('com.glide') === 0 ||
            pluginName.indexOf('com.snc.platform') === 0 ||
            pluginName.indexOf('com.snc.core') === 0) {
            continue;
        }

        var confidence = 100;
        var reasons = [];

   
        var tableFound = false;
        var tableHasData = false;

        var tableGR = new GlideRecord('sys_db_object');
        tableGR.addQuery('sys_package.name', pluginTitle);
        tableGR.query();

        while (tableGR.next()) {
            tableFound = true;
            try {
                var dataGR = new GlideRecord(tableGR.getValue('name'));
                dataGR.setLimit(1);
                dataGR.query();
                if (dataGR.hasNext()) {
                    tableHasData = true;
                    break;
                }
            } catch (e) {
                // ignore inaccessible tables
            }
        }

        if (tableHasData) {
            confidence -= 50;
            reasons.push('Plugin tables contain data');
        } else if (tableFound) {
            confidence -= 10;
            reasons.push('Plugin tables exist but are empty');
        } else {
            reasons.push('No plugin tables found');
        }

 
        var roleFound = false;
        var roleAssigned = false;

        var roleGR = new GlideRecord('sys_user_role');
        roleGR.addQuery('sys_package.name', pluginTitle);
        roleGR.query();

        while (roleGR.next()) {
            roleFound = true;

            var userRoleGR = new GlideRecord('sys_user_has_role');
            userRoleGR.addQuery('role', roleGR.sys_id);
            userRoleGR.setLimit(1);
            userRoleGR.query();

            if (userRoleGR.hasNext()) {
                roleAssigned = true;
                break;
            }
        }

        if (roleAssigned) {
            confidence -= 40;
            reasons.push('Plugin roles assigned to users');
        } else if (roleFound) {
            confidence -= 5;
            reasons.push('Plugin roles exist but not assigned');
        } else {
            reasons.push('No plugin roles found');
        }

        if (confidence < 0) confidence = 0;

        // Show only likely unused plugins
        if (confidence >= 70) {
            results.push({
                name: pluginName,
                title: pluginTitle,
                confidence: confidence,
                reasons: reasons.join('; ')
            });
        }
    }


 

    results.sort(function (a, b) {
        return b.confidence - a.confidence;
    });

    for (var i = 0; i < results.length; i++) {
        gs.print(
            results[i].confidence + '% | ' +
            results[i].title + ' | ' +
			results[i].name + ' | ' +
            results[i].reasons
        );
    }

    gs.print('Total likely unused plugins: ' + results.length);

})();

 

I noticed that some plugins that don't have any tables are showing up in our results. It would be nice if we had another way to know if the functionality is being used, but this is a good start. Thanks for your work in creating it for the community!

Anton42
Tera Expert

Not very helpful. It also shows all sub plugins which get installed during major plugin installation. One example: "CSM Extension for Proxy Contacts".

Version history
Last update:
3 weeks ago
Updated by:
Contributors