This solution will work even if groups are nested.
Macro 1 - TreeWalk (Once only)
SELECT @All; @Command([ToolsRunMacro]; "TreeWalkInit"); @Command([ToolsRunMacro]; "TreeWalkIterate"); @Command([ToolsRunMacro]; "TreeWalkRecur")
SELECT @All; FIELD WorkList := Members; FIELD People := ""; FIELD ChildGroups := ListName;
SELECT @All; FIELD ListDescription := ListDescription; FIELD People := People; FIELD ChildGroups := ChildGroups; REM; REM "Check for end of recursion"; REM; ToDo := @Text(@Elements(WorkList)); ENVIRONMENT TreeToDo := ToDo; @If(ToDo = "0"; @Return(0); ""); REM; REM "Get the next element in the to do list"; REM; NextItem := @Subset(WorkList; 1); REM; REM "Modify the to do list"; REM; FIELD WorkList := @If(ToDo = "1"; ""; @Subset(WorkList; -(@Elements(WorkList) - 1))); REM; REM "Skip if null next item"; REM; @If(NextItem = ""; @Return(0); ""); REM; REM "See if the item is an already processed group"; REM; @If(@If(@Matches(ChildGroups; NextItem); @Do(@If(@Left(ListDescription; "**") = "RECURSIVE"; ""; @SetField("ListDescription"; "RECURSIVE**" + ListDescription)); @Return("quit")); "ok") = "quit"; @Return(0); ""); REM; REM "See if in the list of people"; REM; @If(@Matches(People; NextItem); @Return(0); ""); REM; REM "See if the item is a person or a group"; REM; ItemLookup := @DbLookup("" : ""; ""; "Groups"; NextItem; "Members"); REM; REM "If error, then this is a person, else have the contents of the group"; REM; @If(@IsError(ItemLookup); @SetField("People"; @If(People = ""; NextItem; People : NextItem)); @Do(@SetField("ChildGroups"; ChildGroups : NextItem); @SetField("WorkList"; WorkList : ItemLookup)))
SELECT @All; REM; REM "Check if should recur"; REM; ToDo := @Environment("TreeToDo"); @If((ToDo = "0") | (ToDo = ""); @Return(0); ""); REM; REM "Process one iteration"; REM; @Command([ToolsRunMacro]; "TreeWalkIterate"); REM; REM "Recur"; REM; @Command([ToolsRunMacro]; "TreeWalkRecur")