Convert win_service_info dictionary to lowercase

74 Views Asked by At

I am using the win_service_info module to store the services of a Windows machine into a dictionary. But, later, I want to search for a specific service by the path to the executable. I want this to be a case insensitive match because part of the path variable is going to be entered in by a user.

I have tried tons of stuff: map, combine, etc. But, it always fails because my set_fact always seems to set my variable type as something other than a dictionary (a list, a string, etc.).

I just want to do a simple lowercase to lowercase comparison to find a match to the executable path in the list of services.

- name: Getting services...
  ansible.windows.win_service_info:
  register: services

- name: Converting to lowercase...
  set_fact:
    lower_services: "{{ services | lower }}"

- name: Locating service by installation path...
  set_fact:
    target_service: "{{ lower_services |
                        selectattr('path', 'equalto', SchedulerPath | lower) |
                        first }}"

  when: lower_services |
        selectattr('path', 'equalto', SchedulerPath | lower) |
        list | length > 0
2

There are 2 best solutions below

1
On BEST ANSWER

You can use the Jinja match test along with its parameter ignorecase in order to make case insensitive search.

But, since you are now making a regex search, you will have to escape the regex tokens out of your search string. This can be achieved with the regex_escape filter.

So, your set_fact ends up being something like:

- set_fact:
    target_service: >-
      {{
        services.services
          | selectattr(
            'path',
            'match',
            SchedulerPath | regex_escape ~ '$',
            ignorecase=True
          )
      }}

For example, given:

- set_fact:
    target_service: >-
      {{
        services.services
          | selectattr(
            'path',
            'match',
            SchedulerPath | regex_escape ~ '$',
            ignorecase=True
          )
      }}
  vars:
    SchedulerPath: c:\windows\system32\foo.exe
    services:
      services:
        - name: foo
          path: C:\Windows\system32\FOO.exe
        - name: bar
          path: C:\Windows\system32\BAR.exe

This yields:

ok: [localhost] => changed=false 
  ansible_facts:
    target_service:
    - name: foo
      path: C:\Windows\system32\FOO.exe

Note: the above output was generated running the playbook with the option -v, which, amongst other useful information, shows the result of a set_fact task.

0
On

Q: "Given the dictionary d1 search items from the list test case insensitive."

  test: [key_A, kEY_b, key_x]
  d1:
    key_a: 1
    KEY_B: 2
    kEy_C: 3

A: Update lowercase keys

  d2: "{{ dict(d1.keys()|map('lower')|
               zip(d1.values())) }}"

gives

  d2:
    key_a: 1
    key_b: 2
    key_c: 3

and convert the searched items to lowercase too. For example,

    - debug:
        var: d2[item|lower]
      loop: "{{ test }}"

gives

ok: [test_01] => (item=key_A) => 
  ansible_loop_var: item
  d2[item|lower]: '1'
  item: key_A
ok: [test_01] => (item=kEY_b) => 
  ansible_loop_var: item
  d2[item|lower]: '2'
  item: kEY_b
ok: [test_01] => (item=key_x) => 
  ansible_loop_var: item
  d2[item|lower]: VARIABLE IS NOT DEFINED!
  item: key_x

Example of a complete playbook for testing

- hosts: all

  vars:

    test: [key_A, kEY_b, key_x]
    d1:
      key_a: 1
      KEY_B: 2
      kEy_C: 3

    d2: "{{ dict(d1.keys()|map('lower')|
                 zip(d1.values())) }}"

  tasks:

    - debug:
        var: d2

    - debug:
        var: d2[item|lower]
      loop: "{{ test }}"