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.

Random Password in catalog item run script

Brendan Hallida
Kilo Guru

Hi all,

So I got some assistance from a consultant on this script.  Our requirements are to generate a random password, and the password needed to have the following:

  • 8 characters
  • At least 1 Uppercase
  • At least 1 Lowercase
  • At least 1 Number

The password is then passed over to our custom powershell activities.

We came up with the below:

var randomNum;
lowerUpperNum = false;
while(!lowerUpperNum) {
    randomNum = GlideSecureRandomUtil.getSecureRandomString(8);
    if(hasLowerUpperNumCase(randomNum)) {
        lowerUpperNum = true;
    }
}

current.variables.password = randomNum; //passes string to request item variable

function hasLowerUpperNumCase(_randomNum) {
    return (/[a-zA-Z0-9]/.test(_randomNum));
}

It seemed to be working, however, i just got a result without a lowercase: ie this was it 38B9U485.

Anyone know what could be happening, or if there was a better way to meet our requirements?

 

Cheers,

Brendan

 

1 ACCEPTED SOLUTION

Try running it with the print enclosed inside of an evaluation of lowerUpperNum. As you've written it, the password is always printed, even if lowerUpperNum evaluates as false.

I just tested the following and got 1,000 matches exactly.

 

for (i=0; i<1000; ){
	var lowerUpperNum = false;
	while(!lowerUpperNum) {

		var password = GlideSecureRandomUtil.getSecureRandomString(8);	
		lowerUpperNum = !!((password).match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/));
		
		if(lowerUpperNum) {
			gs.print(password);
			i++;
		}

		//current.variables.password = GlideSecureRandomUtil.getSecureRandomString(8);	
		//lowerUpperNum = !!((current.variables.password).match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/));
	}
}

 

You could take it a step further and modify it for your application by the following, which guarantees that lowerUpperNum needs to be truthy before password is assigned.

 

var lowerUpperNum = false;
while(!lowerUpperNum) {

	var password = GlideSecureRandomUtil.getSecureRandomString(8);	
	lowerUpperNum = !!((password).match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/));
	
	if(lowerUpperNum) {
		current.variables.password = password;	
	}
	
}

View solution in original post

11 REPLIES 11

Hi, I slightly update and this worked for me. Can you try it out

var randomNum;
for (i=0; i<10; ){
lowerUpperNum = false;
while(!lowerUpperNum) {
    randomNum = GlideSecureRandomUtil.getSecureRandomString(8);
    if(hasLowerUpperNumCase(randomNum)) {
        lowerUpperNum = true;
	gs.print(randomNum);
        i++;
    }
}
}
function hasLowerUpperNumCase(_randomNum) {
var a = (/[a-z][A-Z][0-9]/.test(_randomNum));
//gs.log("a is ---- "+a);
return a;

}

Cheers mate,

This did work perfectly, however, I chose Ben's answer as correct as I believe it is the most efficient code.

 

i appreciate your assistance 🙂

benjamin_alldri
Mega Expert

You're almost there with your original code. But, for the sake of scope security, I personally prefer to handle everything inside of the loop itself. I also find that using String.prototype.match(...) is easier to work with than RegExp.prototype.test(...), especially when you're ensuring it as a boolean by prepending a double-bang.

 

var lowerUpperNum = false;

while(!lowerUpperNum) {

    current.variables.password = GlideSecureRandomUtil.getSecureRandomString(8);	
    lowerUpperNum = !!((current.variables.password).match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/));
}

 

It's all personal preference of course, but that should achieve what you are chasing.

Thanks for your reply 🙂

 

I tried it and add it to a loop to test 1000 times, and it is failing also.  Am I missing something?  I do like this as it is a smaller script 🙂

 

for (i=0; i<1000; ){
var lowerUpperNum = false;
while(!lowerUpperNum) {

		var password = GlideSecureRandomUtil.getSecureRandomString(8);	
		lowerUpperNum = !!((password).match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/));
		
		gs.print(password);
			i++;

    //current.variables.password = GlideSecureRandomUtil.getSecureRandomString(8);	
    //lowerUpperNum = !!((current.variables.password).match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/));
}
}

Try running it with the print enclosed inside of an evaluation of lowerUpperNum. As you've written it, the password is always printed, even if lowerUpperNum evaluates as false.

I just tested the following and got 1,000 matches exactly.

 

for (i=0; i<1000; ){
	var lowerUpperNum = false;
	while(!lowerUpperNum) {

		var password = GlideSecureRandomUtil.getSecureRandomString(8);	
		lowerUpperNum = !!((password).match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/));
		
		if(lowerUpperNum) {
			gs.print(password);
			i++;
		}

		//current.variables.password = GlideSecureRandomUtil.getSecureRandomString(8);	
		//lowerUpperNum = !!((current.variables.password).match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/));
	}
}

 

You could take it a step further and modify it for your application by the following, which guarantees that lowerUpperNum needs to be truthy before password is assigned.

 

var lowerUpperNum = false;
while(!lowerUpperNum) {

	var password = GlideSecureRandomUtil.getSecureRandomString(8);	
	lowerUpperNum = !!((password).match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/));
	
	if(lowerUpperNum) {
		current.variables.password = password;	
	}
	
}