--- - name: multi loop block: - name: Reset loop variables # without unsetting infinte loops will occur set_fact: group_present: false find_groups: [] #find_users: [] # we dont want to reset this var, this will append on each loop until exit (unexpected behaviour but works) find_group_members_tidy: [] group_members: [] member_type: [] member_attributes: [] # - name: Inspect dummy host object_attributes # debug: # msg: "{{ hostvars['DUMMY_HOST']['object_attributes'] }}" - name: Filter groups into a list - CHANGED set_fact: #find_groups: "{{ find_groups | default([]) }} + ['{{ item.name }}']" find_groups: "{{ find_groups | default([]) + [dict(name=item.name, role=item.role, type=item.type)] }}" with_items: "{{ hostvars['DUMMY_HOST']['object_attributes'] }}" when: item.type == 'Group' - name: Append users to list - CHANGED set_fact: #find_users: "{{ find_users | default([]) }} + ['{{ item.name }}']" find_users: "{{ find_users | default([]) + [dict(name=item.name, role=item.role, type=item.type)] }}" with_items: "{{ hostvars['DUMMY_HOST']['object_attributes'] }}" when: item.type == 'Person' # - debug: # msg: # - "{{ find_groups }}" # - "{{ find_users }}" # when: find_groups is defined ####### working # - name: Query group members - CHANGED # #win_shell: ([ADSISearcher] "(sAMAccountName={{ item }})").FindOne().Properties.member # win_shell: ([ADSISearcher] "(sAMAccountName={{ item.name }})").FindOne().Properties.member # register: find_group_members_result # with_items: "{{ find_groups }}" # #when: find_groups is defined # when: find_groups is defined and item.role == 'member' # - name: Query group members type owner - NEW # #win_shell: ([ADSISearcher] "(sAMAccountName={{ item }})").FindOne().Properties.member # win_shell: ([ADSISearcher] "(sAMAccountName={{ item.name }})").FindOne().Properties.member # register: find_group_members_result_type_owner # with_items: "{{ find_groups }}" # when: find_groups is defined and item.role == 'owner' # instead of owner/member this could be RW/RWX ####### working - name: Query group members win_shell: ([ADSISearcher] "(sAMAccountName={{ item.name }})").FindOne().Properties.member register: find_group_members_result with_items: "{{ find_groups }}" when: find_groups is defined # - debug: # msg: "{{ find_group_members_result }}" # when: find_group_members_result is defined ####### working # - name: Tidy group members into list - CHANGED - stuck here # set_fact: # #group_members: "{{ group_members | default([]) + [item.split(',')[0].split('CN=')[1]] }}" # group_members: "{{ group_members | default([]) + [dict(name=item.split(',')[0].split('CN=')[1], role='member')] }}" # with_items: "{{ find_group_members_result | json_query(jmesquery) }}" # vars: # jmesquery: "results[].stdout_lines" # #when: find_group_members_result.results[0].stdout | length >0 # bad check # when: find_group_members_result is defined and (item is defined and item | length >0) # - name: Tidy group members type owner into list - NEW # set_fact: # group_members: "{{ group_members | default([]) + [dict(name=item.split(',')[0].split('CN=')[1], role='owner')] }}" # with_items: "{{ find_group_members_result_type_owner | json_query(jmesquery) }}" # vars: # jmesquery: "results[].stdout_lines" # when: find_group_members_result_type_owner is defined and (item is defined and item | length >0) ####### working - name: Tidy group members into dict of names and owner set_fact: find_group_members_tidy: '{{ find_group_members_tidy | default([]) + [dict(name=item.name, role=item.role)] }}' with_items: "{{ find_group_members_result | json_query(jmesquery) }}" vars: jmesquery: "results[].{role: @.item.role, name: @.stdout_lines}" #entry: "{{ item.role }}" - name: Tidy group members into dict of name and owner set_fact: group_members: "{{ group_members | default([]) + [dict(name=item.1.split(',')[0].split('CN=')[1], role=item.0.role)] }}" with_subelements: - "{{ find_group_members_tidy }}" - name # - name: Tidy group members type owner into list - NEW (sort into dictionary with role as key) # set_fact: # group_members: '{{ group_members | default([]) + [dict(entry)] }}' # works cool # with_items: "{{ find_group_members_result | json_query(jmesqueryC) }}" # vars: # jmesqueryC: "results[].{role: @.item.role, name: @.stdout_lines}" # entry: '{"{{ item.role }}":"{{ item.name }}"}' # - debug: # msg: "{{ group_members }}" # when: group_members is defined - name: Check AD object is user or group - CHANGED #win_shell: ([ADSISearcher] "(sAMAccountName={{ item }})").FindOne().Properties.objectcategory win_shell: ([ADSISearcher] "(sAMAccountName={{ item.name }})").FindOne().Properties.objectcategory register: member_type_result with_items: "{{ group_members }}" when: group_members is defined # - debug: # msg: "{{ member_type_result }}" # when: group_members is defined - name: Build list of AD object type set_fact: member_type: "{{ member_type | default([]) + [(item.stdout.split(',')[0].split('CN=')[1])] }}" with_items: "{{ member_type_result.results }}" when: group_members is defined # - debug: # msg: "{{ member_type }}" # when: group_members is defined - name: Build dict of object names and types - CHANGED set_fact: #member_attributes: "{{ member_attributes | default([]) + [ dict(name=item[0], type=item[1]) ] }}" member_attributes: "{{ member_attributes | default([]) + [ dict(name=item[0].name, role=item[0].role, type=item[1]) ] }}" # effectively adding a new positional field from the list to the dict loop: "{{ group_members|zip(member_type)|list }}" when: group_members is defined # - debug: # msg: "{{ member_attributes }}" # when: group_members is defined - name: Reset/Add variable object_attributes to dummy host for next loop add_host: name: "DUMMY_HOST" object_attributes: "{{ member_attributes }}" when: member_attributes is defined - name: Set flag to notify there are nested groups set_fact: group_present: true with_items: "{{ member_attributes }}" when: member_attributes is defined and item.type == 'Group' #when: member_attributes is defined and item.type == 'GroupA' # used to break loop with test for no group_present - name: Nested group present? fail: msg: Nested group detected when: group_present # the following tasks only run on the last run of the loop where there are no more groups detected # append the users from the last run of the loop to find_users # set find_users as a DUMMY_HOST variable to be retrieved from the calling script - this is how you pass variables back from different plays also works for include_tasks - name: Append users to list - CHANGED set_fact: #find_users: "{{ find_users | default([]) + [dict(name=item.name, type=member)] }}" find_users: "{{ find_users | default([]) + [dict(name=item.name, type=item.type, role=item.role)] }}" with_items: "{{ member_attributes }}" when: item.type == 'Person' - name: Add users to variable find_users for dummy host on final loop add_host: name: "DUMMY_HOST" find_users: "{{ find_users }}" when: find_users is defined rescue: - include_tasks: group_lookup.yml