--- - name: Сбор инвентаря Windows машин (nmap) hosts: localhost connection: local gather_facts: yes vars: domain: "zag.lan" dns_servers: - "192.168.1.250" - "192.168.1.254" inventory_file: "/tmp/windows_inventory.ini" subnets: - "192.168.0.0/24" - "192.168.1.0/24" - "192.168.2.0/24" - "192.168.3.0/24" - "172.19.8.0/23" - "172.19.10.0/23" - "172.19.24.0/23" - "172.19.26.0/23" - "172.19.40.0/23" - "172.19.42.0/23" - "172.19.56.0/23" - "172.19.58.0/23" winrm_ports: - 5985 - 5986 tasks: - name: Проверка установки nmap command: which nmap register: nmap_check failed_when: false changed_when: false - name: Ошибка если nmap не установлен fail: msg: "nmap не установлен!" when: nmap_check.rc != 0 - name: Сканирование подсетей command: "nmap -p {{ winrm_ports | join(',') }} --open -T4 -oG - {{ subnets | join(' ') }}" register: nmap_result changed_when: false - name: Извлечение IP с WinRM set_fact: active_ips: "{{ nmap_result.stdout | regex_findall('Host: ([0-9.]+).*Ports:.*(?:5985|5986)/open') | unique | list }}" - name: Найдено IP debug: msg: "Найдено {{ active_ips | length }} IP с WinRM" # ИЗМЕНЕНО: Попытка резолва через оба DNS сервера - name: DNS резолв через корпоративные DNS shell: | # Пробуем первый DNS result=$(nslookup {{ item }} {{ dns_servers[0] }} 2>/dev/null | grep 'name =' | awk '{print $NF}' | sed 's/\.$//') # Если не получилось, пробуем второй DNS if [ -z "$result" ]; then result=$(nslookup {{ item }} {{ dns_servers[1] }} 2>/dev/null | grep 'name =' | awk '{print $NF}' | sed 's/\.$//') fi # Если оба не сработали if [ -z "$result" ]; then echo "NO_DNS" else echo "$result" fi loop: "{{ active_ips }}" register: dns_lookup changed_when: false when: active_ips | length > 0 - name: Формирование PC хостов set_fact: pc_hosts: "{{ pc_hosts | default([]) + [{'hostname': item.stdout | trim, 'ip': item.item}] }}" loop: "{{ dns_lookup.results | default([]) }}" when: - active_ips | length > 0 - item.stdout is defined - item.stdout != "NO_DNS" - item.stdout | trim is match('^pc\\d+.*' + domain + '$') - name: Фильтрация PC (pc01-pc500 / pc001-pc500) set_fact: filtered_hosts: "{{ pc_hosts | default([]) | selectattr('hostname', 'match', '^pc(\\d{2,3})\\.' + domain + '$') | list }}" - name: Неопознанные хосты set_fact: unknown_ips: "{{ active_ips | difference(filtered_hosts | default([]) | map(attribute='ip') | list) }}" - name: Создание инвентаря copy: content: | # ========================================== # Инвентарь Windows PC # Дата: {{ ansible_date_time.iso8601 }} # DNS серверы: {{ dns_servers | join(', ') }} # Подсети: {{ subnets | join(', ') }} # Найдено IP с WinRM: {{ active_ips | length }} # PC хостов в домене: {{ filtered_hosts | default([]) | length }} # Неопознанных: {{ unknown_ips | default([]) | length }} # ========================================== [windows_pcs] {% for host in filtered_hosts | default([]) | sort(attribute='hostname') %} {{ host.hostname | regex_replace('\\.' + domain + '$', '') }} ansible_host={{ host.hostname }} {% endfor %} {% if unknown_ips | length > 0 %} # Хосты с WinRM, но без DNS имён или не PC* [windows_unknown] {% for ip in unknown_ips %} unknown_{{ ip | replace('.', '_') }} ansible_host={{ ip }} {% endfor %} [windows:children] windows_pcs windows_unknown {% else %} [windows:children] windows_pcs {% endif %} [windows:vars] ansible_connection=winrm ansible_winrm_transport=ntlm ansible_winrm_server_cert_validation=ignore ansible_port=5985 dest: "{{ inventory_file }}" - name: Итоговая статистика debug: msg: - "==========================================" - "Просканировано подсетей: {{ subnets | length }}" - "Найдено IP с WinRM: {{ active_ips | length }}" - "PC хостов (pc01-pc500): {{ filtered_hosts | default([]) | length }}" - "Неопознанных хостов: {{ unknown_ips | default([]) | length }}" - "Файл: {{ inventory_file }}" - "==========================================" - name: Список найденных PC debug: msg: "{{ filtered_hosts | default([]) | map(attribute='hostname') | list }}" when: - filtered_hosts is defined - filtered_hosts | length > 0