Обновить playbooks/scan_inventory.yml
This commit is contained in:
@@ -1,14 +1,9 @@
|
|||||||
---
|
---
|
||||||
- name: Сбор инвентаря Windows (Nmap + Smart DNS)
|
- name: Сбор инвентаря Windows (Nmap SMB + DNS)
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
connection: local
|
connection: local
|
||||||
gather_facts: yes
|
gather_facts: yes
|
||||||
vars:
|
vars:
|
||||||
domain: "zag.lan"
|
|
||||||
# Ваши DNS (важен порядок)
|
|
||||||
dns_servers:
|
|
||||||
- "192.168.1.250"
|
|
||||||
- "192.168.1.254"
|
|
||||||
inventory_file: "/tmp/windows_inventory.ini"
|
inventory_file: "/tmp/windows_inventory.ini"
|
||||||
|
|
||||||
# Список подсетей
|
# Список подсетей
|
||||||
@@ -27,26 +22,14 @@
|
|||||||
- "172.19.56.0/23"
|
- "172.19.56.0/23"
|
||||||
- "172.19.58.0/23"
|
- "172.19.58.0/23"
|
||||||
|
|
||||||
# Порты: WinRM HTTP, WinRM HTTPS, SSH Std, SSH Custom
|
# Порты для проверки доступности (WinRM, SSH, SMB)
|
||||||
scan_ports:
|
scan_ports:
|
||||||
- 5985
|
- 5985
|
||||||
- 5986
|
|
||||||
- 22
|
- 22
|
||||||
- 22233
|
- 445
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: Проверка nmap
|
- name: Сканирование сети (поиск живых IP)
|
||||||
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: >
|
command: >
|
||||||
nmap -p {{ scan_ports | join(',') }}
|
nmap -p {{ scan_ports | join(',') }}
|
||||||
-Pn -n --open --min-rate 1000 -T4 -oG -
|
-Pn -n --open --min-rate 1000 -T4 -oG -
|
||||||
@@ -54,118 +37,93 @@
|
|||||||
register: nmap_result
|
register: nmap_result
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
# 2. ПАРСИНГ РЕЗУЛЬТАТОВ
|
- name: Извлечение IP адресов
|
||||||
- name: Парсинг активных IP
|
|
||||||
set_fact:
|
set_fact:
|
||||||
# Регулярка ищет строки, где открыт ХОТЯ БЫ ОДИН из нужных портов
|
|
||||||
active_ips: "{{ nmap_result.stdout | regex_findall('Host: ([0-9.]+).*Ports:.*(?:' + scan_ports | join('|') + ')/open') | unique | list }}"
|
active_ips: "{{ nmap_result.stdout | regex_findall('Host: ([0-9.]+).*Ports:.*(?:' + scan_ports | join('|') + ')/open') | unique | list }}"
|
||||||
|
|
||||||
- name: Статистика сканирования
|
- name: Статистика
|
||||||
debug:
|
debug:
|
||||||
msg: "Найдено активных хостов: {{ active_ips | length }}"
|
msg: "Найдено активных IP: {{ active_ips | length }}"
|
||||||
|
|
||||||
# 3. DNS РЕЗОЛВ (Оптимизированный Shell)
|
# ГЛАВНОЕ ИЗМЕНЕНИЕ: Получаем имя через SMB (NetBIOS) или DNS
|
||||||
- name: Определение Hostname через корпоративные DNS
|
- name: Определение имен хостов (SMB Discovery)
|
||||||
shell: |
|
shell: |
|
||||||
IP="{{ item }}"
|
IP="{{ item }}"
|
||||||
# Функция для запроса к конкретному DNS серверу
|
# 1. Пробуем узнать имя через SMB (самый надежный способ для Windows)
|
||||||
ask_dns() {
|
SMB_NAME=$(nmap -p 445 --script smb-os-discovery $IP -Pn -n | grep "Computer name:" | awk -F': ' '{print $2}')
|
||||||
nslookup -timeout=1 $1 $2 2>/dev/null | grep 'name =' | awk '{print $NF}' | sed 's/\.$//' | head -n 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Пробуем первый DNS
|
if [ ! -z "$SMB_NAME" ]; then
|
||||||
NAME=$(ask_dns $IP {{ dns_servers[0] }})
|
echo "$SMB_NAME" | tr '[:upper:]' '[:lower:]'
|
||||||
|
|
||||||
# Если пусто, пробуем второй
|
|
||||||
if [ -z "$NAME" ]; then
|
|
||||||
NAME=$(ask_dns $IP {{ dns_servers[1] }})
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Вывод результата
|
|
||||||
if [ -z "$NAME" ]; then
|
|
||||||
echo "NO_DNS"
|
|
||||||
else
|
else
|
||||||
# Переводим в нижний регистр для удобства
|
# 2. Если SMB закрыт/не ответил, пробуем DNS (как раньше)
|
||||||
echo "$NAME" | tr '[:upper:]' '[:lower:]'
|
DNS_NAME=$(nslookup -timeout=1 $IP 192.168.1.250 2>/dev/null | grep 'name =' | awk '{print $NF}' | sed 's/\.$//' | head -n 1)
|
||||||
|
if [ ! -z "$DNS_NAME" ]; then
|
||||||
|
echo "$DNS_NAME" | tr '[:upper:]' '[:lower:]'
|
||||||
|
else
|
||||||
|
echo "UNKNOWN"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
loop: "{{ active_ips }}"
|
loop: "{{ active_ips }}"
|
||||||
register: dns_results
|
register: host_names
|
||||||
changed_when: false
|
changed_when: false
|
||||||
# Не спамим в лог, если хостов много
|
no_log: true # Чтобы не засорять лог
|
||||||
no_log: true
|
|
||||||
|
|
||||||
# 4. ГРУППИРОВКА РЕЗУЛЬТАТОВ
|
# Фильтруем и готовим списки
|
||||||
- name: Обработка результатов DNS
|
- name: Сортировка хостов
|
||||||
set_fact:
|
set_fact:
|
||||||
# Хосты с правильным именем pc...zag.lan
|
# Ищем 'pc' в любом месте имени (было ^pc - только в начале)
|
||||||
pc_hosts: >-
|
pc_list: >-
|
||||||
{{ pc_hosts | default([]) +
|
{{ host_names.results
|
||||||
[{'hostname': item.stdout, 'ip': item.item}]
|
| selectattr('stdout', 'search', 'pc')
|
||||||
}}
|
| map(attribute='item') | list
|
||||||
# Хосты без имени или с левым именем
|
| zip(host_names.results | selectattr('stdout', 'search', 'pc') | map(attribute='stdout') | list)
|
||||||
other_hosts: >-
|
| list }}
|
||||||
{{ 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)
|
other_list: >-
|
||||||
set_fact:
|
{{ host_names.results
|
||||||
unknown_list: >-
|
| rejectattr('stdout', 'search', 'pc')
|
||||||
{{ dns_results.results | rejectattr('stdout', 'match', '^pc\\d+.*' + domain + '$') | map(attribute='item') | list }}
|
| map(attribute='item') | list
|
||||||
|
| zip(host_names.results | rejectattr('stdout', 'search', 'pc') | map(attribute='stdout') | list)
|
||||||
|
| list }}
|
||||||
|
|
||||||
# 5. ГЕНЕРАЦИЯ ФАЙЛА
|
|
||||||
- name: Запись инвентаря
|
- name: Запись инвентаря
|
||||||
copy:
|
copy:
|
||||||
content: |
|
content: |
|
||||||
# Автоматический инвентарь от {{ ansible_date_time.iso8601 }}
|
# === Найденные PC (по имени содержит 'pc') ===
|
||||||
|
|
||||||
# === Корпоративные PC (pcXX.zag.lan) ===
|
|
||||||
[windows_pcs]
|
[windows_pcs]
|
||||||
{% for host in pc_hosts | default([]) | sort(attribute='hostname') %}
|
{% for ip, name in pc_list %}
|
||||||
{{ host.hostname | regex_replace('\\.' + domain + '$', '') }} ansible_host={{ host.hostname }} ansible_host_ip={{ host.ip }}
|
{{ name }} ansible_host={{ ip }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
# === Остальные найденные (Unknown / IP only) ===
|
# === Остальные устройства (Servers, Unknown) ===
|
||||||
[windows_unknown]
|
[windows_other]
|
||||||
{% for res in dns_results.results if res.item in unknown_list %}
|
{% for ip, name in other_list %}
|
||||||
{% if res.stdout != "NO_DNS" %}
|
{% if name == "UNKNOWN" %}
|
||||||
# Найден по DNS как: {{ res.stdout }}
|
unknown_{{ ip | replace('.', '_') }} ansible_host={{ ip }}
|
||||||
unknown_{{ res.item | replace('.', '_') }} ansible_host={{ res.item }}
|
|
||||||
{% else %}
|
{% else %}
|
||||||
# DNS имя не найдено
|
{{ name }} ansible_host={{ ip }}
|
||||||
unknown_{{ res.item | replace('.', '_') }} ansible_host={{ res.item }}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
# === Группы и переменные ===
|
|
||||||
[windows:children]
|
[windows:children]
|
||||||
windows_pcs
|
windows_pcs
|
||||||
windows_unknown
|
windows_other
|
||||||
|
|
||||||
[windows:vars]
|
[windows:vars]
|
||||||
# Настройки подключения
|
|
||||||
ansible_connection=winrm
|
ansible_connection=winrm
|
||||||
ansible_winrm_transport=ntlm
|
ansible_winrm_transport=ntlm
|
||||||
ansible_winrm_server_cert_validation=ignore
|
ansible_winrm_server_cert_validation=ignore
|
||||||
ansible_port=5985
|
ansible_port=5985
|
||||||
|
ansible_user=Administrator
|
||||||
# Если вы хотите использовать SSH для unknown хостов, можно переопределить ниже:
|
# Пароль лучше задать в Secret Store, не здесь
|
||||||
# [windows_unknown:vars]
|
|
||||||
# ansible_port=22233
|
|
||||||
# ansible_connection=ssh
|
|
||||||
# ansible_shell_type=powershell
|
|
||||||
dest: "{{ inventory_file }}"
|
dest: "{{ inventory_file }}"
|
||||||
|
|
||||||
- name: Финальный отчет
|
- name: ПОКАЗАТЬ РЕЗУЛЬТАТ (Скопируйте это в новый инвентарь)
|
||||||
|
command: cat {{ inventory_file }}
|
||||||
|
register: cat_inventory
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Вывод в лог
|
||||||
debug:
|
debug:
|
||||||
msg:
|
var: cat_inventory.stdout_lines
|
||||||
- "Найдено всего IP: {{ active_ips | length }}"
|
|
||||||
- "Распознано как PC: {{ pc_hosts | default([]) | length }}"
|
|
||||||
- "Не распознано: {{ unknown_list | default([]) | length }}"
|
|
||||||
- "Файл сохранен: {{ inventory_file }}"
|
|
||||||
Reference in New Issue
Block a user