--- - name: Сбор инвентаря Windows (Nmap + Smart DNS) hosts: localhost connection: local gather_facts: yes vars: domain: "zag.lan" # Ваши DNS (важен порядок) 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.9.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 HTTP, WinRM HTTPS, SSH Std, SSH Custom scan_ports: - 5985 - 5986 - 22 - 22233 tasks: - name: Проверка nmap command: which nmap register: nmap_check failed_when: nmap_check.rc != 0 changed_when: false # 1. СКАНИРОВАНИЕ # -Pn : Не пинговать (считать хост живым). РЕШАЕТ ПРОБЛЕМУ "НЕ ВИДИТ ХОСТЫ" # -n : Не делать Reverse DNS самим nmap-ом (сделаем сами точнее) # --min-rate : Ускоряет процесс # --open : Показать только открытые - name: Сканирование сети (Nmap) command: > nmap -p {{ scan_ports | join(',') }} -Pn -n --open --min-rate 1000 -T4 -oG - {{ subnets | join(' ') }} register: nmap_result changed_when: false # 2. ПАРСИНГ РЕЗУЛЬТАТОВ - name: Парсинг активных IP set_fact: # Регулярка ищет строки, где открыт ХОТЯ БЫ ОДИН из нужных портов active_ips: "{{ nmap_result.stdout | regex_findall('Host: ([0-9.]+).*Ports:.*(?:' + scan_ports | join('|') + ')/open') | unique | list }}" - name: Статистика сканирования debug: msg: "Найдено активных хостов: {{ active_ips | length }}" # 3. DNS РЕЗОЛВ (Оптимизированный Shell) - name: Определение Hostname через корпоративные DNS shell: | IP="{{ item }}" # Функция для запроса к конкретному DNS серверу ask_dns() { nslookup -timeout=1 $1 $2 2>/dev/null | grep 'name =' | awk '{print $NF}' | sed 's/\.$//' | head -n 1 } # Пробуем первый DNS NAME=$(ask_dns $IP {{ dns_servers[0] }}) # Если пусто, пробуем второй if [ -z "$NAME" ]; then NAME=$(ask_dns $IP {{ dns_servers[1] }}) fi # Вывод результата if [ -z "$NAME" ]; then echo "NO_DNS" else # Переводим в нижний регистр для удобства echo "$NAME" | tr '[:upper:]' '[:lower:]' fi loop: "{{ active_ips }}" register: dns_results changed_when: false # Не спамим в лог, если хостов много no_log: true # 4. ГРУППИРОВКА РЕЗУЛЬТАТОВ - name: Обработка результатов DNS set_fact: # Хосты с правильным именем pc...zag.lan pc_hosts: >- {{ pc_hosts | default([]) + [{'hostname': item.stdout, 'ip': item.item}] }} # Хосты без имени или с левым именем other_hosts: >- {{ other_hosts | default([]) + [{'ip': item.item, 'resolved_name': item.stdout}] }} loop: "{{ dns_results.results }}" when: - item.stdout is defined - item.stdout != "NO_DNS" - item.stdout | trim is match('^pc\\d+.*' + domain + '$') # Собираем тех, кто не попал в pc_hosts (включая NO_DNS и странные имена) - name: Сбор остальных (Unknown) set_fact: unknown_list: >- {{ dns_results.results | rejectattr('stdout', 'match', '^pc\\d+.*' + domain + '$') | map(attribute='item') | list }} # 5. ГЕНЕРАЦИЯ ФАЙЛА - name: Запись инвентаря copy: content: | # Автоматический инвентарь от {{ ansible_date_time.iso8601 }} # === Корпоративные PC (pcXX.zag.lan) === [windows_pcs] {% for host in pc_hosts | default([]) | sort(attribute='hostname') %} {{ host.hostname | regex_replace('\\.' + domain + '$', '') }} ansible_host={{ host.hostname }} ansible_host_ip={{ host.ip }} {% endfor %} # === Остальные найденные (Unknown / IP only) === [windows_unknown] {% for res in dns_results.results if res.item in unknown_list %} {% if res.stdout != "NO_DNS" %} # Найден по DNS как: {{ res.stdout }} unknown_{{ res.item | replace('.', '_') }} ansible_host={{ res.item }} {% else %} # DNS имя не найдено unknown_{{ res.item | replace('.', '_') }} ansible_host={{ res.item }} {% endif %} {% endfor %} # === Группы и переменные === [windows:children] windows_pcs windows_unknown [windows:vars] # Настройки подключения ansible_connection=winrm ansible_winrm_transport=ntlm ansible_winrm_server_cert_validation=ignore ansible_port=5985 # Если вы хотите использовать SSH для unknown хостов, можно переопределить ниже: # [windows_unknown:vars] # ansible_port=22233 # ansible_connection=ssh # ansible_shell_type=powershell dest: "{{ inventory_file }}" - name: Финальный отчет debug: msg: - "Найдено всего IP: {{ active_ips | length }}" - "Распознано как PC: {{ pc_hosts | default([]) | length }}" - "Не распознано: {{ unknown_list | default([]) | length }}" - "Файл сохранен: {{ inventory_file }}"