Script not correctly parsing string containing "\r"

Mike Hashemi
Kilo 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
Kilo 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