Parse JSON string from Microsoft AD Spoke Lookup User

Dazler
Mega Sage

Hi,

 

When using the Microsoft AD Spoke, Lookup User action in Flow Designer, I set the property list to return the user's groups from AD.  The attribute in AD is MemberOf.

 

The lookup is working and I retrieve the user's memberof groups in a JSON String.  This string can't be used in a for each loop, so I created a custom action to parse the JSON string.  However, I am having a hard time.

 

Some users are only in 1 group, so the JSON looks like this.

{
   "MemberOf":"CN=Bright Executives,OU=SNOW,OU=Groups,OU=Connected,DC=Dev,DC=Green,DC=com"
}

 

Then there are some that have multiple groups and this is how the return looks.

{
"MemberOf":
	[
	"CN=Group_22c6,OU=MGroups,OU=Groups,OU=Resources,OU=Context,DC=Green,DC=com",
	"CN=Bright Executives,OU=SNOW,OU=Groups,OU=Connected,DC=Dev,DC=Green,DC=com"
]
}

 

I tried to use the Parser step action in flow, but it is based on a structure and either option doesn't fit the other.  I even tried just coding it directly in a script but my return looks like this.

 

CN=Group_22c6,OU=MGroups,OU=Groups,OU=Resources,OU=Context,DC=Green,DC=com,CN=Bright Executives,OU=SNOW,OU=Groups,OU=Connected,DC=Dev,DC=Green,DC=com

If I tried to turn this into an array, it would loop through all the items, separated by comma.  That could get long especially if they have more than 10 groups.

Because when you return groups from Active Directory, it returns as the distinguishedname and not just the display name.  The real information that I need from these are the CN= text.

 

I need to be able to push the items into an array, no matter if it is just 1 group or multiple so that I can use the foreach loop.

 

Does anyone have any ideas, how I can go about this?

1 ACCEPTED SOLUTION

jaheerhattiwale
Mega Sage
Mega Sage

@Dazler Tried and tested solution. Parse it using the code

 

var result = [];
var object = {
   "MemberOf":"CN=Bright Executives,OU=SNOW,OU=Groups,OU=Connected,DC=Dev,DC=Green,DC=com"
}

/*var object = {
"MemberOf":
    [
    "CN=Group_22c6,OU=MGroups,OU=Groups,OU=Resources,OU=Context,DC=Green,DC=com",
    "CN=Bright Executives,OU=SNOW,OU=Groups,OU=Connected,DC=Dev,DC=Green,DC=com"
]
}*/

if(typeof(object.MemberOf) == "string"){
    var element = object.MemberOf;
    element = element.split(",");

    for(var j=0; j<element.length; j++){
        if(element[j].startsWith("CN=")){
            result.push(element[j]);
        }
    }
}else if(typeof(object.MemberOf) == "object"){
    var innerArray = object.MemberOf;

    for(var i=0; i<innerArray.length; i++){
        var element = innerArray[i];
        element = element.split(",");

        for(var j=0; j<element.length; j++){
            if(element[j].startsWith("CN=")){
                result.push(element[j]);
            }
        }
    }
}

gs.info(result.toString())
 
Result 1 (when users only in one group):
jaheerhattiwale_0-1670057130394.png

 

Result 2 (when user is part of multiple group):

jaheerhattiwale_1-1670057190930.png

 

 

Please mark as correct answer if this solves your issue.

 
Please mark the answer as correct or helpful based on impact
ServiceNow Community Rising Star, Class of 2023

View solution in original post

10 REPLIES 10

@Dazler You are welcome. Just a small addition in the code to improve the performance.

 

We will add a break; statement to come out of for loop if we get "CN=" text in any of the element.

 

Just you can add break; as below:

 

var result = [];
var object = {
   "MemberOf":"CN=Bright Executives,OU=SNOW,OU=Groups,OU=Connected,DC=Dev,DC=Green,DC=com"
}

/*var object = {
"MemberOf":
    [
    "CN=Group_22c6,OU=MGroups,OU=Groups,OU=Resources,OU=Context,DC=Green,DC=com",
    "CN=Bright Executives,OU=SNOW,OU=Groups,OU=Connected,DC=Dev,DC=Green,DC=com"
]
}*/

if(typeof(object.MemberOf) == "string"){
    var element = object.MemberOf;
    element = element.split(",");

    for(var j=0; j<element.length; j++){
        if(element[j].startsWith("CN=")){
            result.push(element[j]);
            break;
        }
    }
}else if(typeof(object.MemberOf) == "object"){
    var innerArray = object.MemberOf;

    for(var i=0; i<innerArray.length; i++){
        var element = innerArray[i];
        element = element.split(",");

        for(var j=0; j<element.length; j++){
            if(element[j].startsWith("CN=")){
                result.push(element[j]);
                break;
            }
        }
    }
}

gs.info(result.toString())

 

Please mark the answer as correct or helpful based on impact
ServiceNow Community Rising Star, Class of 2023

Shane J
Tera Guru

@Dazler - can provide details on how you ended up using this in Flow?  I've got a Custom Action built using the script and producing an output, but my For Each isn't picking anything up to run against.

Hi @Shane J

 

Action Input

 

Dazler_1-1682543869598.png

 

I had to make a couple additions to the script.

 

(function execute(inputs, outputs) {

var result = [];
var object = inputs.jsonString;
  
if(typeof(object.MemberOf) == "string"){

    var element = object.MemberOf;
    element = element.split(",");

    for(var j=0; j<element.length; j++){
        if(element[j].startsWith("CN=")){
          if((element[j].toLowerCase().indexOf('_access_') > 0) || (element[j].toLowerCase().indexOf('ven_') > 0)){
            result.push(element[j]);
          }
        }
    }
}else if(typeof(object.MemberOf) == "object"){
    
    var innerArray = object.MemberOf;

    for(var i=0; i<innerArray.length; i++){
        var element = innerArray[i];
        element = element.split(",");

        for(var j=0; j<element.length; j++){
            if(element[j].startsWith("CN=")){
              if((element[j].toLowerCase().indexOf('_access_') > 0) || (element[j].toLowerCase().indexOf('ven_') > 0)){
                result.push(element[j]);
              }
            }
        }
    }
}

 outputs.memberof = result;
  
})(inputs, outputs);

 

Then I set my output as an array string and was able to use it within the For Each. 

 

Dazler_0-1682543570015.png

 

What are you feeding this Action with?  I see you set it as JSON but I've been trying to do it as a String, using the output from the Lookup User OOTB MS AD Action. 

 

Is that the Output for the Script Step only?

 

I'm basically getting 0 groups (I should see three in this case) as output using your Action settings.

Community Alums
Not applicable

Hi Shane, 

 

I finally figured out how to do this. It's worth noting that SN agreed this is an issue and will be fixing it in Yokohama. PRB1633191

 

What I did was copy the Look up User action so that I could modify the code. I kept it in the correct scope so that it would be found under Microsoft Active Directory spoke. From there I modified the code as follows. 

 

Post Processing & Error Handling

 

(function execute(inputs, outputs) {
    function handleError(error_message) {
        var errMessage = error_message;
        var resource_name;
        var actionErrors = {
            CANT_FIND_OBJECT: "Cannot find an object with identity"
        };
        var commErrors = {
            AUTH_FAILURE: "Authentication failure with the user",
            SERVER_UNAVAILABLE: "The RPC server is unavailable",
            UNREACHABLE_STATUS: "Failed to access target system.  Please check credentials and firewall settings on the target system to ensure accessibility: Access is denied."
        };
        var errorMessages = {
            INVALID_OBJECT_IDENTITY: "Invalid resource name",
            CREDENTIALS_FAILED: "Invalid credentials for host",
            ACCOUNT_LOCKED_OUT: "The referenced account is currently locked out and may not be logged on to",
            INVALID_HOST: "Invalid hostname in connection or host not reachable from MID Server",
            AUTH_FAILED_WITH_MID: "Host credentials incorrect. Authentication error in MID Server"
        };

        if (error_message.indexOf(commErrors.AUTH_FAILURE) != -1)
            error_message = errorMessages.CREDENTIALS_FAILED;
        else if (error_message.indexOf(actionErrors.CANT_FIND_OBJECT) != -1) {
            resource_name = (errMessage.split("' under:"))[0];
            resource_name = (resource_name.split("identity: '")[1]).trim();
            if (resource_name == inputs.user_name)
                error_message = "Invalid User Name : " + resource_name;
            else
                error_message = errorMessages.INVALID_OBJECT_IDENTITY + " : " + resource_name;
        } else if (error_message.indexOf(commErrors.SERVER_UNAVAILABLE) != -1)
            error_message = errorMessages.INVALID_HOST;
        else if (error_message.indexOf(commErrors.UNREACHABLE_STATUS) != -1)
            error_message = errorMessages.AUTH_FAILED_WITH_MID;

        throw new Error(error_message);

    }

    if (inputs.errorMessage)
        handleError(inputs.errorMessage);
    else {
        var responseBody = JSON.parse(inputs.responseBody);
        if (responseBody.status == "Success") {
             var result = [];
             var object = responseBody.body.MemberOf;

            if(typeof(object) == "string"){
                var element = object;
                element = element.split(",");

                for(var j=0; j<element.length; j++){
                    if(element[j].startsWith("CN=")){
                        if(element[j].startsWith("CN=")){
                            result.push(element[j].substr(3));
                        }
                    }
                }
        }else if(typeof(object) == "object"){
            var innerArray = object;
            gs.info("XX: object loop");
            for(var i=0; i<innerArray.length; i++){
                var element = innerArray[i];
                element = element.split(",");

                for(var j=0; j<element.length; j++){
                    if(element[j].startsWith("CN=")){
                        result.push(element[j].substr(3));
                    }
                }
            }
        }
            outputs.memberof = result;
        } else if (responseBody.status == "Error")
            if (responseBody.body)
                handleError(responseBody.body);
            else
                handleError("Unknown error. Please check error log for more information");
        else
            handleError("Unknown error. Please check error log for more information");
    }
})(inputs, outputs);
 
You will notice that I removed all the other elements and I am only outputting an array of strings. I deleted the output and updated it accordingly.
 
ChrisDoernbrac_0-1720645988230.png

 

Outputs

 

I deleted the outputs and created just one called membership which is nothing more than the array from Post Processing & Error Handling. 

 

ChrisDoernbrac_1-1720646098213.png

 

You will need to update the parsing code to handle what you need to strip out. For me I just needed the CN piece so I updated the code to strip that element out only and it also strips off CN= so that I just get the group names. Attached the xml as well