Search code examples
ansiblejson-query

How can I search json output from tasks


I have a playbook pulling users and groups from windows 2012 using powershell and I convert it to json.

I get the following output

[
    {
        "Group": "Appsupp",
        "Members": [
            "WIN-U97DIQUENUM\\appsuport",
            "WIN-U97DIQUENUM\\userfirst"
        ]
    },
    {
        "Group": "DBAdministrators",
        "Members": {}
    },
    {
        "Group": "Techsupp",
        "Members": {}
    },
    {
        "Group": "Access Control Assistance Operators",
        "Members": {}
    },
    {
        "Group": "Administrators",
        "Members": "WIN-U97DIQUENUM\\Administrator"
    },
    {
        "Group": "Backup Operators",
        "Members": {}
    },
    {
        "Group": "Certificate Service DCOM Access",
        "Members": {}
    },
    {
        "Group": "Cryptographic Operators",
        "Members": {}
    },
    {
        "Group": "Distributed COM Users",
        "Members": {}
    },
    {
        "Group": "Event Log Readers",
        "Members": {}
    },
    {
        "Group": "Guests",
        "Members": "WIN-U97DIQUENUM\\Guest"
    },
    {
        "Group": "Hyper-V Administrators",
        "Members": {}
    },
    {
        "Group": "IIS_IUSRS",
        "Members": "NT AUTHORITY\\IUSR"
    },
    {
        "Group": "Network Configuration Operators",
        "Members": {}
    },
    {
        "Group": "Performance Log Users",
        "Members": {}
    },
    {
        "Group": "Performance Monitor Users",
        "Members": {}
    },
    {
        "Group": "Power Users",
        "Members": {}
    },
    {
        "Group": "Print Operators",
        "Members": {}
    },
    {
        "Group": "RDS Endpoint Servers",
        "Members": {}
    },
    {
        "Group": "RDS Management Servers",
        "Members": {}
    },
    {
        "Group": "RDS Remote Access Servers",
        "Members": {}
    },
    {
        "Group": "Remote Desktop Users",
        "Members": {}
    },
    {
        "Group": "Remote Management Users",
        "Members": {}
    },
    {
        "Group": "Replicator",
        "Members": {}
    },
    {
        "Group": "Users",
        "Members": [
            "NT AUTHORITY\\Authenticated Users",
            "NT AUTHORITY\\INTERACTIVE",
            "WIN-U97DIQUENUM\\userfirst",
            "WIN-U97DIQUENUM\\usersecond",
            "WIN-U97DIQUENUM\\appsupport",
            "WIN-U97DIQUENUM\\techsupport",
            "WIN-U97DIQUENUM\\sqlserveruser"
        ]
    }
]

I would like to have user compared to that data I pulled from the server. For example, I want to know if appsupport user exists and which group it belongs to.

I have tried the below json_query. FYI, getgroup.stdout is the registered result from the task pulling info from the server.

    - debug:
        msg: "{{ getgroup.stdout | from_json | json_query('guser') }}"
      vars:
        guser: "[?Members.contains(@, `appsupport`)].Group"

What I get is an empty result (while this method worked with other json). What am I doing wrong?

I assume that the problem is the Members key in my object as it my contain an empty dictionnary, a single string or a list of strings as recapped in the chosen examples below.

Single string:

{
    "Group": "IIS_IUSRS",
    "Members": "NT AUTHORITY\\IUSR"
},

List:

{
    "Group": "Users",
    "Members": [
        "NT AUTHORITY\\Authenticated Users",
        "NT AUTHORITY\\INTERACTIVE",
        "WIN-U97DIQUENUM\\userfirst",
        "WIN-U97DIQUENUM\\usersecond",
        "WIN-U97DIQUENUM\\appsupport",
        "WIN-U97DIQUENUM\\techsupport",
        "WIN-U97DIQUENUM\\sqlserveruser"
    ]
}

Empty dict:

{
    "Group": "Replicator",
    "Members": {}
}

When I use json_query('[].Members[*]') it only returns the latest member, not all Members.

How can I select the objects from my json result having a particular user in the Members field in this kind of situation?


Solution

  • Without json_query.

    For testing, given the output in the file, read it and convert the Members to lists, e.g.

        - set_fact:
            output: "{{ lookup('file', 'test.data')|from_yaml }}"
        - set_fact:
            mlist: "{{ mlist|d([]) +
                       [item|combine({'Members': _Members|from_yaml})] }}"
          loop: "{{ output }}"
          vars:
            _Members: |-
              {% if item.Members is mapping %}
              {{ item.Members.keys()|list }}
              {% elif item.Members is string %}
              [{{ item.Members }}]
              {% else %}
              {{ item.Members }}
              {% endif %}
        - debug:
            var: mlist
    

    gives

      mlist:
      - Group: Appsupp
        Members:
        - WIN-U97DIQUENUM\appsuport
        - WIN-U97DIQUENUM\userfirst
      - Group: DBAdministrators
        Members: []
      - Group: Techsupp
        Members: []
      - Group: Access Control Assistance Operators
        Members: []
      - Group: Administrators
        Members:
        - WIN-U97DIQUENUM\Administrator
      - Group: Backup Operators
        Members: []
      - Group: Certificate Service DCOM Access
        Members: []
      - Group: Cryptographic Operators
        Members: []
      - Group: Distributed COM Users
        Members: []
      - Group: Event Log Readers
        Members: []
      - Group: Guests
        Members:
        - WIN-U97DIQUENUM\Guest
      - Group: Hyper-V Administrators
        Members: []
      - Group: IIS_IUSRS
        Members:
        - NT AUTHORITY\IUSR
      - Group: Network Configuration Operators
        Members: []
      - Group: Performance Log Users
        Members: []
      - Group: Performance Monitor Users
        Members: []
      - Group: Power Users
        Members: []
      - Group: Print Operators
        Members: []
      - Group: RDS Endpoint Servers
        Members: []
      - Group: RDS Management Servers
        Members: []
      - Group: RDS Remote Access Servers
        Members: []
      - Group: Remote Desktop Users
        Members: []
      - Group: Remote Management Users
        Members: []
      - Group: Replicator
        Members: []
      - Group: Users
        Members:
        - NT AUTHORITY\Authenticated Users
        - NT AUTHORITY\INTERACTIVE
        - WIN-U97DIQUENUM\userfirst
        - WIN-U97DIQUENUM\usersecond
        - WIN-U97DIQUENUM\appsupport
        - WIN-U97DIQUENUM\techsupport
        - WIN-U97DIQUENUM\sqlserveruser
    

    Now, you can search for the members, e.g.

        - debug:
            msg: "{{ mlist|selectattr('Members', 'contains', my_user) }}"
          vars:
            my_user: 'WIN-U97DIQUENUM\Administrator'
    

    gives

      msg:
      - Group: Administrators
        Members:
        - WIN-U97DIQUENUM\Administrator
    

    Next, create a dictionary of all members and the groups they belong to

        - set_fact:
            members: "{{ members|d({})|combine({item: _groups}) }}"
          loop: "{{ mlist|map(attribute='Members')|flatten|unique }}"
          vars:
            _groups: "{{ mlist|selectattr('Members', 'contains', item)|
                              map(attribute='Group')|
                              list }}"
        - debug:
            var: members
    

    gives

      members:
        NT AUTHORITY\Authenticated Users:
        - Users
        NT AUTHORITY\INTERACTIVE:
        - Users
        NT AUTHORITY\IUSR:
        - IIS_IUSRS
        WIN-U97DIQUENUM\Administrator:
        - Administrators
        WIN-U97DIQUENUM\Guest:
        - Guests
        WIN-U97DIQUENUM\appsuport:
        - Appsupp
        WIN-U97DIQUENUM\appsupport:
        - Users
        WIN-U97DIQUENUM\sqlserveruser:
        - Users
        WIN-U97DIQUENUM\techsupport:
        - Users
        WIN-U97DIQUENUM\userfirst:
        - Appsupp
        - Users
        WIN-U97DIQUENUM\usersecond:
        - Users
    

    Then, the searching is trivial, e.g.

        - debug:
            msg: "{{ my_user }} is member of the group(s): {{ members[my_user] }}"
          vars:
            my_user: 'WIN-U97DIQUENUM\Administrator'
    

    gives

      msg: 'WIN-U97DIQUENUM\Administrator is member of the group(s): [''Administrators'']'
    

    It's possible to search among the members, e.g.

        - debug:
            msg: "{{ my_user }} is member of the group(s): {{ _groups }}"
          vars:
            my_user: appsuport
            _keys: "{{ members.keys()|list|select('search', my_user)|list }}"
            _groups: "{{ _keys|map('extract', members)|flatten }}"
    

    gives

      msg: 'appsuport is member of the group(s): [''Appsupp'']'