I have been writing a long series of articles (first four parts written, plans for the next 4 in hand, and now this article) about writing Toolkit rules in Novell Identity Manager.
You can read all about them at:
with more to follow as they get published over the next couple of weeks.
I have written some other tutorial rules, walking through a problem or task or concept, which you can see here:
The first two, how to GCV-ize a driver, takes the Active Directory driver, and modifies the default configuration that ships with IDM 3.5, and replaces all hard coded references to the container in Active Directory or eDirectory for user placement with Global Configuration Variables. Thus when you need to change the placement of users, you can change one value, instead of hunting down a dozen different instances where the string is used.
The third rule walks through the Command transform rules for Password handling that all drivers have as part of the default configuration. (As it happens I used the trace from an Identity manager 3.01 Lotus Notes driver in that one, but it is basically the same for most drivers). That is a great exercise for a beginner in Identity Manager, because it explains what the heck is going on with Password events in IDM. (Sometimes there is a <password> node, sometimes there is a <modify-attr ="nspmDistributionPassword> and yet depending where you are in the rules, one comes from the other!).
However, in the Toolkit rule series, I was looking for a really nice example of how you can use it. I started with the several examples I ran into at a client site. The case of the HR system giving me the Employee ID of a manager, and I wanted to store the Distinguished name (DN) of the manager in eDirectory, because of all the benefits DN gives me. I next moved on to talking about ACL compares, as it was on my list, but Lothar teased about not writing the topic, in his post (Setting eDirectory ACL Entries with IDM) so I had to diverge from my planned topic into looking at, comparing, and reporting on ACL values via a toolkit rule.
My next topic to talk about in later articles will be proving that UniquedID values, are really unique in the tree. But I am finding these articles are taking longer to write than I expected. Thus I want to step away from the continuing series and respond to another article that is the perfect topic for this series.
In the article: List Full Name of Members of a Specified Group the author grahamch (http://www.novell.com/communities/user/1238) gives a great way to use VBScript to take a group, list all its members, Full Name of each member, and parent OU.
Well if you have been following along my series on toolkit rules, this is a no brainer to extend the default rule we left off with at the end of part 3. In fact, it is a nice way to do it internal to the Identity Manager system itself.
The only really complicated part about this approach is how do we decide which group to report on? Building a rule that reports on every group in the scope of the query would be pretty easy, but probably a bit of over kill. Instead, lets think about how we can trigger the rule, and leverage that information to select our target.
I was thinking on a really complex approach and it is worth describing and why it is a bad idea. (Sometimes you learn from dumb ideas as much as good ideas!). I was thinking, since our trigger attribute, SomeAttributeName was never really defined, lets imagine for a second that we created as Case Ignore String syntax. (CIS, coincidentally the acronym of the company I work for, CIS Company of New York, http://www.ciscony.com go figure). Well that can basically take any text we would like. Therefore we should be able to just change the test that triggers our rule, and if we see a string that looks like a DN, lets just query for that value and use just that group.
The problem with that is that you would have to type the full DN of the group, in IDM's internal format (backslash delimited, from root most to leaf most nodes), which is a bit awkward. If we had defined our trigger as a DN syntax attribute, we could use that, which means in Console One or iManager, we would get an DN picker widget to select the group with. I suppose we could do that, I just prefer not to use DN syntax for the triggering attribute. But I guess we could.
Lets instead try a different approach, and say, set the trigger attribute to a specific value, but do it on a specific group object. Then we will assume that the object you set the trigger on, is the one you want the report for. That seems specific enough for me.
In that case, since we used 42, and 43 as the trigger values in our last set of rules, lets use 1024 since it is a nice binary number. In this context, we will not be fixing anything, nor would a Job be a good plan (since we could not provide the info on which group to target) we can really simplify the conditions, and just test for 1024 and that it is a Group object.
<if-op-attr mode="nocase" name="SomeTriggerAttribute" op="changing-to">1024</if-op-attr>
<if-class-name mode="nocase" op="equal">Group</if-class-name>
New to this approach, we need to grab the current objects DN, so that's easy, just XPATH of -dn.
<do-set-local-variable name="TARGET-GROUP" scope="policy">
Now that we have it, lets query to get the group membership list, although in fact we do not need to Query, we can use Source attribute, which for this case is about the same, but if we had queried earlier in this rule, would use the information already cached.
<do-set-local-variable name="USERSLIST" notrace="true" scope="policy">
Now we loop through our USERLIST variable, which should be a list of DN's of Group members, This is such a simple task, that really all we have to do is build our MESSAGE local variable with the values for each member. What is nice is we can use Source Attribute as well to get the values.
The article this is in response too specifically wanted the Full Name attribute, but often that is not populated, the way you would like, so lets make it a little nicer and provide, Given Name, then Surname, and finally Full Name instead for completeness.
When we use Source Attribute, we have three options for WHICH object is the source to get the attribute from, Current object, Association, or DN. Current object here would only refer to the Group object that triggered this event, though we could fiddle with that by setting the Operation Destination DN to our current target object, and then use Destination Attribute instead. That might even be an easier approach, since we need to specify the DN a bunch of times, but probably not worth the complexity it would introduce in terms of making the code harder to read. A very cute trick, that is elegant, but might not buy enough to be worth the confusion the next guy reading this rule will run into trying to figure it out. If you do decide to go that route, make sure to note what and why you did in the Description.
My boss does this to me all the time, and I have to figure it out on my own, since I cannot get him to write this stuff down! He makes some amazingly cute and elegant rule, that when you look at it the first, second, third, and often fourth time the first reaction is usually "That will never work", or "That cannot be right". By the fifth look at it, you realize, "Oh that is cute!". I just think the loss in readability may override the value of the elegance. I am fine with it, if it is documented though so that I can figure out what is going on easily.
If we were looking at a destination system, we might want to use the Association value as the second possibility.
The third object is DN, and lets assume for the moment, that we choose to use the LESS elegant approach, and just use Source Attribute three times, and specify the DN via a local variable instead. The local variable is of course the current-node of our for-each loop.
Then we need OU the object is in, which we can get easily enough with Parse DN. Parse DN is very powerful, but some what complicated at times to use, so check out these articles on the topic for more information:
To get the OU, we recall that the user we are reporting on at this moment in the loop is the local variable current-node, as a DN, so we can just ParseDN the variable to get what we need. First we want the OU of the object. So lets ParseDN the DN value in the variable, and say start at 1, which should chop off the first part of the DN, the tree name, which no one is probably interested in, and then go to the length of -2 which is one from the end, and thus we chop of the name of user, and that leaves us with just the container structure to put into our variable.
Now we could also try to reformat it if we wanted to something other than backslash format, since we are getting it from eDirectory via Identity Manager, and that will return it in backslash format. You could try and let ParseDN convert it to other formats, like LDAP but probably simplest to just leave it in backslash format.
To get the user name, probably based on CN (though you could name it based on UniqueID, (You might see this in an LDAP'y style directory, that queries for objects return the first node as uid=UserName,ou=whatever,dc=com)) we just use Parse DN again. This time, start at -1, and length of 1, which should get us just the naming attribute.
Put commas in between each of the values we are reporting, in the MESSAGE variable to make it look nice, and tune the output to be what you want.
That should set look something like: (Note the carriage return after the first token-local variable of MESSAGE, that is so the results come out on separate lines, but it looks funny in XML, thus the </token-text> node at the beginning of line by itself).
<do-set-local-variable name="MESSAGE" scope="policy">
<token-src-attr name="Given Name">
<token-src-attr name="Full Name">
<token-parse-dn dest-dn-format="src-dn" length="-2" start="1">
<token-parse-dn dest-dn-format="src-dn" length="1" start="-1">
You can use this model to get any attribute off the user to send in an email report. You could format it other than comma separated values (CSV) if you wanted, though it might be hard to do things like PDF or Word document formats here, unless you really know what those formats look like under the covers. Though I guess you could call out to a Java class that did the work for you, when you were ready. If someone knows how to do that, I would love to see it, as that could be really cool!
Anyway, this should be a nice and easy way, building on all the things discussed in the previous series of articles, to do the same thing described by grahamc, using Identity Manager itself, instead of using VBScript.
Lots more possible uses, I will keep my eye open and write some more on other uses as I see them come up.
You can find the final rule attached as an XML file to paste into your Designer or iManager.