Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Script not correctly parsing string containing "\r"

Mike Hashemi
Mega Sage

I am running a script (background script currently, but it will be in an ETL later). My goal is to accept a username in any of the formats:

I will convert the second two, to "username@domain.com" and do a query against sys_user, for that value. My problem is that I sometimes the username is something like "domain\rsmith". When I run the script, after adjusting the username value, I am left with "smith@domain.com" because SN is interpreting "\r" as a carriage return character. I have worked around the issue for \r but I could have the same problem with other regular expression characters (e.g. \n) and I don't really want to try to code for every possibility.

 

Is there an OOB way to make SN ignore "\r" and the like?

 

Here is the script I have been testing:

var input = 'domain\nsmith';

if (input.indexOf('\\') == -1) {
    gs.info('input contains a backslash');

    if (input.contains('\r')) {
        input = input.replace('domain\r', 'r');
    } else {
        input = input.replace('domain', '');
    }

    gs.info('Replaced domain: {0}', input);

    var backslashIndex = input.indexOf('\\');
    if (backslashIndex !== -1) {
        input = input.substring(backslashIndex + 1);
        gs.info('removed domain: {0}', input);
    } else {
        gs.info('domain not in username');
    }

    if (!input.includes('@domain.com')) {
        input += '@domain.com';
        gs.info('added mail domain. input is now: {0}', input);
    }

    var user = new GlideRecord('sys_user');
    user.addQuery('user_name', input);
    user.addQuery('active', 'true');
    user.query();

    var count = 0;
    var firstSysId;
    while (user.next()) {
        if (count === 0) {
            firstSysId = user.sys_id;
        }
        count++;
    }

    gs.info('returning user: {0}', firstSysId);
} else {
    gs.info('no slash');
}

 

Thanks.

1 ACCEPTED SOLUTION

Mike Hashemi
Mega Sage

I ended-up using the following script.

(function (batch, output) {
    for (var i = 0; i < batch.length; i++) {
        var input = batch[i].input;
        //var log_source = 'SccmUserLookup';
        var downLevelDomain = 'domain';
        var fullDomain = 'domain.com';
        var domainRegex = new RegExp('^(' + downLevelDomain + '|' + fullDomain + ')(\\\\)?', 'i');

        /*Logger = {
            message: '',
            appendLine: function (s) {
                this.message += new Date().toISOString() + ': ' + s + '\n';
            },
            flush: function (error) {
                var f = error ? gs.logError : gs.log;
                f(this.message, log_source);
            }
        };*/

        try {
            //Logger.appendLine('Beginning SCCM user lookup script.');

            if (input.includes(',')) {
                var inputArray = input.split(',');
                input = inputArray[0];
            }

            input = '.\administrator'
            switch (true) {
                case input.includes('\n'):
                    input = input.replace(/^.*(?=\n)/, '').replace('\n', 'n');
                    break;
                case input.includes('\r'):
                    input = input.replace(/^.*(?=\r)/, '').replace('\r', 'r');
                    break;
                case input.includes('\t'):
                    input = input.replace(/^.*(?=\t)/, '').replace('\t', 't');
                    break;
                case input.includes('\T'):
                    input = input.replace(/\\T/g, 'T');
                    break;
                case input.includes('\f'):
                    input = input.replace(/^.*(?=\f)/, '').replace('\f', 'f');
                    break;
                case input.includes('\v'):
                    input = input.replace(/^.*(?=\v)/, '').replace('\v', 'v');
                    break;
                case input.includes('\x08'): // represents \b
                    input = input.replace(/\x08/g, 'b');
                    break;
                case input.includes('\B'):
                    input = input.replace(/\\B/g, 'B');
                    break;
                case input.includes('\d'):
                    input = input.replace(/\\d/g, 'd');
                    break;
                case input.includes('\D'):
                    input = input.replace(/\\D/g, 'D');
                    break;
                case input.includes('\w'):
                    input = input.replace(/\\w/g, 'w');
                    break;
                case input.includes('\W'):
                    input = input.replace(/\\W/g, 'W');
                    break;
                case input.includes('\S'): // Skipped \s because no special handling is needed
                    input = input.replace(/\\S/g, 'S');
                    break;
                default:
                    break;
            }

            input = input.replace(domainRegex, '');

            //Logger.appendLine('Current username value: ' + input);

            if (!input.includes('@domain.com')) {
                input += '@domain.com';
                //Logger.appendLine('Appended domain to username. Modified username value: ' + input);
            }

            var user = new GlideRecord('sys_user');
            user.addQuery('user_name', input);
            user.addQuery('active', 'true');
            user.query();

            var count = 0;
            var firstSysId = '';
            while (user.next()) {
                if (count === 0) {
                    firstSysId = user.sys_id;
                }
                count++;
            }

            //Logger.appendLine('Found ' + count + ' user(s), returning user sys_id: ' + firstSysId);
            //Logger.flush();

            // Set each output element below
            output[i] = firstSysId;
        } catch (e) {
            //Logger.appendLine('Error: ' + e.message);
            //Logger.flush(true);
        }
    }
})(batch, output);

View solution in original post

17 REPLIES 17

I see. You are asking what the string in the SCCM SQL table looks like, what SN is actually receiving. I will have to look into that.

 

Ankur Bawiskar
Tera Patron
Tera Patron

@Mike Hashemi 

try this

The escapeSpecialChars function is used to escape special characters like \r, \n, \t, \f, \v, and \\.

var input = 'domain\\nsmith';

// Function to escape special characters
function escapeSpecialChars(str) {
    return str.replace(/[\r\n\t\f\v\\]/g, function (char) {
        return '\\' + char.charCodeAt(0).toString(16);
    });
}

// Escape special characters in the input
input = escapeSpecialChars(input);

if (input.indexOf('\\') !== -1) {
    gs.info('input contains a backslash');

    input = input.replace(/domain\\[a-zA-Z0-9]+/, '');
    gs.info('Replaced domain: {0}', input);

    var backslashIndex = input.indexOf('\\');
    if (backslashIndex !== -1) {
        input = input.substring(backslashIndex + 1);
        gs.info('removed domain: {0}', input);
    } else {
        gs.info('domain not in username');
    }

    if (!input.includes('@domain.com')) {
        input += '@domain.com';
        gs.info('added mail domain. input is now: {0}', input);
    }

    var user = new GlideRecord('sys_user');
    user.addQuery('user_name', input);
    user.addQuery('active', 'true');
    user.query();

    var count = 0;
    var firstSysId;
    while (user.next()) {
        if (count == 0) {
            firstSysId = user.sys_id;
        }
        count++;
    }

    gs.info('returning user: {0}', firstSysId);
} else {
    gs.info('no slash');
}

If my response helped please mark it correct and close the thread so that it benefits future readers.

Regards,
Ankur
✨ Certified Technical Architect  ||  ✨ 9x ServiceNow MVP  ||  ✨ ServiceNow Community Leader

This script throws the error:

Javascript compiler exception: missing formal parameter (null.null.script; line 5) in:
var input = 'domain\nsmith';

 

When I run it. Also, remember that the username (for example) is "domain\nsmith" not "domain\\nsmith".

FWIW, the extra backslash is important because the backslash is an escape character. On a line of code, if you want to include a backslash, y'gotta include a double-backslash. It's just the way the source code in Javascript works. You can print out the string immediately using gs.info() and you'll see, Javascript only added one backslash.

 

If something returns a double backslash or returns [CR] or [LF], that's ... a bigger problem I admit.

FWIW, when you're out of this for a bit, a good intro to the crazy world of escape characters:

 

https://codedamn.com/news/javascript/how-to-escape-a-string-in-javascript