Restore from Gitea ZIP snapshot (12.08.2026) after full instance reinstall

Git history was lost when the previous Gitea instance was wiped and
reinstalled due to an unresolved corruption bug — this commit is the
last known-good file content, exported before the reinstall. Prior
commit history is not recoverable through this path.
This commit is contained in:
Claude Sonnet 5
2026-08-12 19:24:02 +00:00
commit 8ff6d59ba6
34 changed files with 2239 additions and 0 deletions
+225
View File
@@ -0,0 +1,225 @@
---
- name: Prepare Dynamic Inventory
hosts: localhost
gather_facts: yes
tasks:
- name: Set target host variable
set_fact:
target_host: "{{ target_ip }}"
when: target_ip is defined and target_ip != ''
- name: Validate target host
fail:
msg: "Please provide target host IP address or domain name"
when: target_host is not defined or target_host == ''
- name: Display target information
debug:
msg: |
============================================
Target Host: {{ target_host }}
============================================
- name: Test connectivity to target (WinRM port)
ansible.builtin.wait_for:
host: "{{ target_host }}"
port: 5985
timeout: 10
ignore_errors: yes
register: connectivity_test
- name: Warn if WinRM is not accessible
debug:
msg: |
WARNING: Cannot connect to WinRM port 5985 on {{ target_host }}
Please check if the host is accessible and WinRM is enabled
when: connectivity_test is defined and connectivity_test.failed
- name: Add target VM from Semaphore Survey to inventory
add_host:
name: "{{ target_host }}"
groups: windows_vms
ansible_user: "{{ ansible_user }}"
ansible_password: "{{ ansible_password }}"
ansible_connection: winrm
ansible_port: 5985
ansible_winrm_transport: ntlm
ansible_winrm_server_cert_validation: ignore
- name: Deploy and run activations
hosts: windows_vms
gather_facts: no
vars:
activation_map:
windows_only:
- windows
office_only:
- office
windows_office:
- windows
- office
autodesk_only:
- autodesk
all:
- windows
- office
- autodesk
tasks:
# Debug - проверим значение activation_type
- name: Debug activation_type
debug:
msg: "activation_type = {{ activation_type }}"
- name: 1. Create distr directory
ansible.windows.win_file:
path: C:\distr
state: directory
when: activation_type is defined and activation_type in activation_map.keys()
- name: 2. Copy activation files from network share
block:
- name: 2a. Copy MAS_AIO.cmd
ansible.windows.win_copy:
src: \\fs\alls\MAS_AIO.cmd
dest: C:\distr\MAS_AIO.cmd
remote_src: yes
become: yes
become_method: runas
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: "{{ domain_user }}"
ansible_become_pass: "{{ domain_password }}"
when: activation_type is defined and activation_type in ['windows_only', 'windows_office', 'all']
- name: 2b. Copy AdskNLM.exe
ansible.windows.win_copy:
src: \\fs\alls\AdskNLM.exe
dest: C:\distr\AdskNLM.exe
remote_src: yes
become: yes
become_method: runas
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: "{{ domain_user }}"
ansible_become_pass: "{{ domain_password }}"
when: activation_type is defined and activation_type in ['autodesk_only', 'all']
# Windows Activation
- name: 3. Activate Windows
block:
- name: 3a. Execute MAS_AIO.cmd for Windows
ansible.windows.win_shell: C:\distr\MAS_AIO.cmd /HWID
become: yes
become_method: runas
become_user: SYSTEM
async: 600
poll: 30
register: windows_activation
- name: 3b. Check Windows activation status
ansible.windows.win_shell: |
$status = Get-WmiObject -Class SoftwareLicensingProduct | Where-Object {$_.PartialProductKey} | Select-Object -First 1
Write-Host "Windows Activation Status: $($status.LicenseStatus)"
if ($status.LicenseStatus -eq 1) {
Write-Host "SUCCESS: Windows activated"
} else {
Write-Host "WARNING: Windows not activated"
}
register: windows_status
ignore_errors: yes
- name: 3c. Display Windows activation result
debug:
var: windows_status.stdout_lines
when: activation_type is defined and activation_type in ['windows_only', 'windows_office', 'all']
# Office Activation
- name: 4. Activate Office
block:
- name: 4a. Execute MAS_AIO.cmd for Office
ansible.windows.win_shell: C:\distr\MAS_AIO.cmd /Ohook
become: yes
become_method: runas
become_user: SYSTEM
async: 600
poll: 30
register: office_activation
- name: 4b. Check Office activation status
ansible.windows.win_shell: |
$office = Get-WmiObject -Class SoftwareLicensingProduct | Where-Object {$_.Name -like "*Office*" -and $_.PartialProductKey}
if ($office) {
Write-Host "Office found: $($office.Name)"
Write-Host "Office Activation Status: $($office.LicenseStatus)"
if ($office.LicenseStatus -eq 1) {
Write-Host "SUCCESS: Office activated"
} else {
Write-Host "WARNING: Office not activated"
}
} else {
Write-Host "INFO: Office not installed"
}
register: office_status
ignore_errors: yes
- name: 4c. Display Office activation result
debug:
var: office_status.stdout_lines
when: activation_type is defined and activation_type in ['office_only', 'windows_office', 'all']
# Autodesk Activation
- name: 5. Activate Autodesk
block:
- name: 5a. Start AdskNLM and wait for activation
ansible.windows.win_shell: |
Write-Host "Starting Autodesk activation at $(Get-Date)" -ForegroundColor Green
$process = Start-Process -FilePath "C:\distr\AdskNLM.exe" -WindowStyle Hidden -PassThru
Start-Sleep -Seconds 15
$process | Stop-Process -Force
Get-Process -Name "AdskNLM" -ErrorAction SilentlyContinue | Stop-Process -Force
Write-Host "Autodesk activation completed at $(Get-Date)" -ForegroundColor Green
become: yes
become_method: runas
become_user: SYSTEM
register: autodesk_activation
ignore_errors: yes
- name: 5b. Clean up AdskNLM processes
ansible.windows.win_shell: |
Get-Process -Name "AdskNLM*" -ErrorAction SilentlyContinue | Stop-Process -Force
become: yes
become_method: runas
become_user: SYSTEM
ignore_errors: yes
- name: 5c. Verify Autodesk activation
ansible.windows.win_shell: |
$autodeskProducts = Get-ChildItem "C:\Program Files\Autodesk" -ErrorAction SilentlyContinue
if ($autodeskProducts) {
Write-Host "Autodesk products found:"
$autodeskProducts | ForEach-Object { Write-Host " - $($_.Name)" }
Write-Host "SUCCESS: Autodesk activation attempted"
} else {
Write-Host "WARNING: No Autodesk products found"
}
register: autodesk_status
ignore_errors: yes
- name: 5d. Display Autodesk activation result
debug:
var: autodesk_status.stdout_lines
when: activation_type is defined and activation_type in ['autodesk_only', 'all']
# Summary
- name: 6. Activation Summary
debug:
msg: |
============================================
ACTIVATION SUMMARY
============================================
Target Host: {{ inventory_hostname }}
Activation Type: {{ activation_type }}
============================================
when: activation_type is defined and activation_type in activation_map.keys()
+199
View File
@@ -0,0 +1,199 @@
---
- name: Stage 1 - Add Ubuntu VM to in-memory inventory
hosts: localhost
connection: local
gather_facts: false
become: false
tasks:
- name: Add Ubuntu VM to in-memory inventory
ansible.builtin.add_host:
name: ubuntu-resize-target
groups: ubuntu_resize_group
ansible_host: "{{ vm_ip }}"
ansible_user: "{{ ansible_user }}"
ansible_password: "{{ ansible_password }}"
ansible_become: true
ansible_become_password: "{{ ansible_become_password }}"
ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
- name: Stage 2 - Wait for SSH port
hosts: localhost
connection: local
gather_facts: false
become: false
tasks:
- name: Wait for SSH port on Ubuntu VM
ansible.builtin.wait_for:
host: "{{ vm_ip }}"
port: 22
timeout: 60
sleep: 2
- name: Stage 3 - Read current guest disk size
hosts: ubuntu_resize_group
gather_facts: false
become: true
vars:
ansible_python_interpreter: /usr/bin/python3
tasks:
- name: Get current size of /dev/sda in bytes
ansible.builtin.command: lsblk -b -dn -o SIZE /dev/sda
register: sda_size_bytes
changed_when: false
- name: Calculate current and target disk size in GB
ansible.builtin.set_fact:
current_disk_gb: "{{ (sda_size_bytes.stdout | int) // 1024 // 1024 // 1024 }}"
target_disk_gb: "{{ ((sda_size_bytes.stdout | int) // 1024 // 1024 // 1024) + (increase_gb | int) }}"
- name: Stage 4 - Power off VM in vCenter
hosts: localhost
connection: local
gather_facts: false
become: false
vars:
ansible_python_interpreter: /opt/semaphore/apps/ansible/11.1.0/venv/bin/python3
tasks:
- name: Show resize plan
ansible.builtin.debug:
msg:
- "VM: {{ vm_name }}"
- "VM IP: {{ vm_ip }}"
- "Current disk: {{ hostvars['ubuntu-resize-target']['current_disk_gb'] }} GB"
- "Target disk: {{ hostvars['ubuntu-resize-target']['target_disk_gb'] }} GB"
- name: Power off VM gracefully
community.vmware.vmware_guest_powerstate:
hostname: "{{ vsphere_server }}"
username: "{{ vsphere_user }}"
password: "{{ vsphere_password }}"
validate_certs: false
datacenter: "{{ vsphere_datacenter }}"
name: "{{ vm_name }}"
state: powered-off
delegate_to: localhost
- name: Wait until SSH port is closed
ansible.builtin.wait_for:
host: "{{ vm_ip }}"
port: 22
state: drained
timeout: 180
- name: Expand VMware disk
community.vmware.vmware_guest_disk:
hostname: "{{ vsphere_server }}"
username: "{{ vsphere_user }}"
password: "{{ vsphere_password }}"
validate_certs: false
datacenter: "{{ vsphere_datacenter }}"
name: "{{ vm_name }}"
disk:
- state: present
unit_number: 0
controller_number: 0
size_gb: "{{ hostvars['ubuntu-resize-target']['target_disk_gb'] }}"
delegate_to: localhost
- name: Power on VM
community.vmware.vmware_guest_powerstate:
hostname: "{{ vsphere_server }}"
username: "{{ vsphere_user }}"
password: "{{ vsphere_password }}"
validate_certs: false
datacenter: "{{ vsphere_datacenter }}"
name: "{{ vm_name }}"
state: powered-on
delegate_to: localhost
- name: Wait for SSH port to return
ansible.builtin.wait_for:
host: "{{ vm_ip }}"
port: 22
timeout: 300
sleep: 5
- name: Stage 5 - Wait for SSH session after reboot
hosts: ubuntu_resize_group
gather_facts: false
vars:
ansible_python_interpreter: /usr/bin/python3
tasks:
- name: Wait for SSH connection
ansible.builtin.wait_for_connection:
timeout: 300
- name: Stage 6 - Expand partition, LVM and filesystem inside Ubuntu
hosts: ubuntu_resize_group
gather_facts: false
become: true
vars:
ansible_python_interpreter: /usr/bin/python3
root_disk: /dev/sda
root_partition_number: 3
root_partition: /dev/sda3
root_lv: /dev/mapper/ubuntu--vg-ubuntu--lv
tasks:
- name: Rescan SCSI bus
ansible.builtin.shell: |
for host in /sys/class/scsi_host/host*; do
echo "- - -" > "$host/scan"
done
args:
executable: /bin/bash
changed_when: true
- name: Wait after rescan
ansible.builtin.pause:
seconds: 5
- name: Ensure growpart is installed
ansible.builtin.apt:
name: cloud-guest-utils
state: present
update_cache: yes
- name: Expand partition if needed
ansible.builtin.command: "growpart {{ root_disk }} {{ root_partition_number }}"
register: growpart_result
changed_when: "'CHANGED:' in growpart_result.stdout"
failed_when: >
growpart_result.rc != 0 and
'NOCHANGE:' not in growpart_result.stdout
- name: Resize LVM physical volume
ansible.builtin.command: "pvresize {{ root_partition }}"
register: pvresize_result
failed_when: false
changed_when: true
- name: Extend root logical volume and filesystem
ansible.builtin.command: "lvextend -r -l +100%FREE {{ root_lv }}"
register: lvextend_result
failed_when: false
changed_when: true
- name: Show final disk state
ansible.builtin.shell: |
pvs
vgs
lvs
df -h /
args:
executable: /bin/bash
register: final_state
changed_when: false
- name: Print final disk state
ansible.builtin.debug:
var: final_state.stdout_lines
+93
View File
@@ -0,0 +1,93 @@
---
- name: Prepare Dynamic Inventory
hosts: localhost
gather_facts: no
tasks:
- name: Add target VM from Semaphore Survey to inventory
add_host:
name: "{{ target_ip }}"
groups: windows_vms
ansible_user: "o.grechko"
ansible_password: "IrZTON3232"
ansible_connection: winrm
ansible_port: 5985
ansible_winrm_transport: ntlm
ansible_winrm_server_cert_validation: ignore
- name: Install and Configure Radmin Server
hosts: windows_vms
gather_facts: no
tasks:
- name: 1. Remove existing file if it exists
ansible.windows.win_file:
path: C:\Windows\SysWOW64\rserver30
state: absent
register: remove_result
ignore_errors: yes
- name: 2. Create directories for Antivirus exclusions
ansible.windows.win_file:
path: "{{ item }}"
state: directory
loop:
- C:\distr
- C:\Windows\SysWOW64\rserver30
- name: 3. Add Windows Defender exclusions
ansible.windows.win_shell: |
Add-MpPreference -ExclusionPath "C:\distr"
Add-MpPreference -ExclusionPath "C:\Windows\SysWOW64\rserver30"
- name: 4. Copy Radmin MSI directly from network share
ansible.windows.win_copy:
src: \\fs\alls\rs352.msi
dest: C:\distr\rs352.msi
remote_src: yes
become: yes
become_method: runas
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: "{{ domain_user }}"
ansible_become_pass: "{{ domain_password }}"
- name: 5. Install Radmin silently (this will auto-start the service)
ansible.windows.win_package:
path: C:\distr\rs352.msi
state: present
arguments: /qn
- name: 6. STOP Radmin Server service to unlock files
ansible.windows.win_service:
name: rserver3
state: stopped
- name: 7. Extract wsock32.zip from network share directly to rserver30
community.windows.win_unzip:
src: \\fs\alls\wsock32.zip
dest: C:\Windows\SysWOW64\rserver30\
become: yes
become_method: runas
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: "{{ domain_user }}"
ansible_become_pass: "{{ domain_password }}"
- name: 8. Copy radmin_settings.reg from network share
ansible.windows.win_copy:
src: \\fs\alls\radmin_settings.reg
dest: C:\distr\radmin_settings.reg
remote_src: yes
become: yes
become_method: runas
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: "{{ domain_user }}"
ansible_become_pass: "{{ domain_password }}"
- name: 9. Apply Radmin registry settings (AD permissions)
ansible.windows.win_command: regedit.exe /s C:\distr\radmin_settings.reg
- name: 10. START Radmin Server service to apply patch and settings
ansible.windows.win_service:
name: rserver3
state: started
+208
View File
@@ -0,0 +1,208 @@
---
- name: "Установка Mango Talker для другого пользователя через планировщик"
hosts: localhost
gather_facts: false
vars:
target_hosts: "{{ target_ips.split(',') | map('trim') | list }}"
ansible_connection: winrm
ansible_winrm_server_cert_validation: ignore
ansible_winrm_transport: ntlm
ansible_port: 5985
source_file: "\\\\fs\\alls\\mango-talker-setup.exe"
local_dir: "C:\\distr"
local_file: "C:\\distr\\mango-talker-setup.exe"
install_args: "--silent"
target_user_name: "{{ target_user | default('aturenkov') }}"
target_user_password: "{{ target_password }}"
app_check_path: "C:\\Users\\{{ target_user_name }}\\AppData\\Roaming\\Mango Telecom\\M.TALKER\\application\\mango-talker.exe"
tasks:
- name: "Создать динамический инвентарь"
add_host:
name: "{{ item }}"
groups: target_group
ansible_connection: winrm
ansible_winrm_server_cert_validation: ignore
ansible_winrm_transport: ntlm
ansible_port: 5985
ansible_user: "{{ ansible_user }}"
ansible_password: "{{ ansible_password }}"
loop: "{{ target_hosts }}"
when: target_hosts | length > 0
- name: "Проверить, что есть хосты"
fail:
msg: "❌ Не указаны IP-адреса для установки"
when: target_hosts | length == 0
- name: "Показать информацию"
debug:
msg:
- "Установка будет выполнена на: {{ target_hosts }}"
- "Установка от имени: {{ ansible_user.split('@')[0] }}"
- "Установка ДЛЯ пользователя: {{ target_user_name }}"
- name: "Выполнить установку"
hosts: target_group
gather_facts: true
vars:
source_file: "\\\\fs\\alls\\mango-talker-setup.exe"
local_dir: "C:\\distr"
local_file: "C:\\distr\\mango-talker-setup.exe"
install_args: "--silent"
target_user_name: "{{ target_user | default('aturenkov') }}"
target_user_password: "{{ target_password }}"
app_check_path: "C:\\Users\\{{ target_user_name }}\\AppData\\Roaming\\Mango Telecom\\M.TALKER\\application\\mango-talker.exe"
tasks:
- name: "1. Проверить доступность"
ansible.windows.win_ping:
- name: "2. Создать папку C:\\distr"
ansible.windows.win_file:
path: "{{ local_dir }}"
state: directory
- name: "3. Скопировать файл"
ansible.windows.win_shell: |
$source = "{{ source_file }}"
$dest = "{{ local_file }}"
$username = "{{ ansible_user }}"
$password = "{{ ansible_password }}"
$secpass = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($username, $secpass)
$drive = New-PSDrive -Name "TempDrive" -PSProvider FileSystem -Root (Split-Path $source) -Credential $cred
Copy-Item -Path $source -Destination $dest -Force
Remove-PSDrive -Name "TempDrive"
register: copy_result
ignore_errors: true
- name: "4. Проверить файл"
ansible.windows.win_stat:
path: "{{ local_file }}"
register: local_stat
- name: "5. Остановить, если файл не скопирован"
fail:
msg: "❌ Не удалось скопировать файл"
when: not local_stat.stat.exists
- name: "6. Запустить установку через планировщик задач"
ansible.windows.win_shell: |
$domain = "{{ ansible_user.split('@')[1] }}"
$user = "{{ target_user_name }}"
$password = "{{ target_user_password }}"
$taskName = "MangoTalkerInstall_$(Get-Date -Format 'yyyyMMddHHmmss')"
# Создаём действие
$action = New-ScheduledTaskAction -Execute "{{ local_file }}" -Argument "{{ install_args }}" -WorkingDirectory "{{ local_dir }}"
# Создаём триггер (однократно)
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1)
# Создаём principal с паролем
$principal = New-ScheduledTaskPrincipal -UserId "$domain\\$user" -LogonType Password -RunLevel Highest
# Создаём настройки
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
# Регистрируем задачу
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Password $password -Force
# Ждём 5 секунд и запускаем задачу
Start-Sleep -Seconds 5
Start-ScheduledTask -TaskName $taskName
# Ждём завершения (максимум 5 минут)
$timeout = 300
$elapsed = 0
$exitCode = $null
do {
$task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
if ($task) {
$taskInfo = $task | Get-ScheduledTaskInfo
if ($taskInfo.LastTaskResult -ne $null -and $taskInfo.LastTaskResult -ne 0) {
$exitCode = $taskInfo.LastTaskResult
break
}
# Проверяем, завершилась ли задача
$taskState = (Get-ScheduledTask -TaskName $taskName).State
if ($taskState -eq "Ready") {
$exitCode = $taskInfo.LastTaskResult
break
}
}
Start-Sleep -Seconds 5
$elapsed += 5
} while ($elapsed -lt $timeout)
# Если таймаут
if ($exitCode -eq $null) {
$exitCode = 0
}
# Удаляем задачу
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
Write-Host "Exit code: $exitCode"
exit $exitCode
register: install_result
failed_when: install_result.rc not in [0, 3010]
changed_when: install_result.rc == 0
- name: "7. Подождать завершения"
ansible.windows.win_shell: |
Start-Sleep -Seconds 10
when: install_result.rc == 0
- name: "8. Проверить установку для пользователя {{ target_user_name }}"
ansible.windows.win_stat:
path: "{{ app_check_path }}"
register: app_check
- name: "9. Поиск установки у всех пользователей"
ansible.windows.win_shell: |
Get-ChildItem -Path "C:\\Users" -Directory -ErrorAction SilentlyContinue | ForEach-Object {
$path = Join-Path $_.FullName "AppData\\Roaming\\Mango Telecom\\M.TALKER\\application\\mango-talker.exe"
if (Test-Path $path) {
Write-Host $_.Name
}
}
register: found_users
ignore_errors: true
when: not app_check.stat.exists
- name: "10. Результат"
debug:
msg:
- "=========================================="
- "✅ Хост: {{ inventory_hostname }}"
- "👤 Установка от: {{ ansible_user.split('@')[0] }}"
- "👤 Установка для: {{ target_user_name }}"
- "📊 Код возврата: {{ install_result.rc }}"
- "📁 Приложение установлено для {{ target_user_name }}: {{ app_check.stat.exists | default(false) }}"
- "📁 Найдено у других: {{ found_users.stdout_lines | default('Нет') }}"
- "=========================================="
- name: "11. Удалить установщик"
ansible.windows.win_shell: |
Start-Sleep -Seconds 5
Remove-Item "{{ local_file }}" -Force -ErrorAction SilentlyContinue
when: install_result.rc == 0
ignore_errors: true
- name: "12. Перезагрузить, если требуется"
ansible.windows.win_reboot:
reboot_timeout: 600
post_reboot_delay: 30
when:
- install_result is defined
- install_result.rc == 3010
+65
View File
@@ -0,0 +1,65 @@
---
- name: Setup Windows Server 2025 as Additional Domain Controller
hosts: all
gather_facts: yes
tasks:
- name: Expand C drive if disk was increased
ansible.windows.win_shell: |
$size = Get-PartitionSupportedSize -DriveLetter C
Resize-Partition -DriveLetter C -Size $size.SizeMax
register: resize_partition_result
failed_when: >
resize_partition_result.rc != 0 and
'already the requested size' not in (resize_partition_result.stderr | default(''))
changed_when: resize_partition_result.rc == 0
- name: Set primary DC as DNS server
ansible.windows.win_dns_client:
adapter_names: "*"
ipv4_addresses:
- "{{ primary_dc_ip }}"
- "127.0.0.1"
- name: Install Active Directory Domain Services & Management Tools
ansible.windows.win_feature:
name: AD-Domain-Services
state: present
include_management_tools: yes
- name: Promote server to additional domain controller
microsoft.ad.domain_controller:
dns_domain_name: "{{ domain_name }}"
domain_admin_user: "{{ domain_admin_user }}"
domain_admin_password: "{{ domain_admin_password }}"
safe_mode_password: "{{ safe_mode_password }}"
state: domain_controller
register: dc_promotion
- name: Reboot after promotion
ansible.windows.win_reboot:
msg: "Rebooting to apply Domain Controller promotion"
reboot_timeout: 3600
connect_timeout: 30
post_reboot_delay: 180
when: dc_promotion.reboot_required
- name: Wait for Active Directory Domain Services to be running
ansible.windows.win_service_info:
name: NTDS
register: ntds_service
retries: 20
delay: 30
until:
- ntds_service.exists
- ntds_service.services[0].state == "running"
- name: Force Active Directory replication
ansible.windows.win_command: repadmin /syncall /A /e /d
register: repadmin_result
changed_when: false
failed_when: false
- name: Show replication status
ansible.builtin.debug:
var: repadmin_result.stdout_lines
+8
View File
@@ -0,0 +1,8 @@
---
collections:
- name: ansible.windows
- name: microsoft.ad
- name: community.windows
- name: community.vmware
- name: ansible.posix
- name: community.general
+214
View File
@@ -0,0 +1,214 @@
---
- name: Prepare Dynamic Inventory
hosts: localhost
gather_facts: no
tasks:
- name: Add target VM from Semaphore Survey to inventory
add_host:
name: "{{ target_ip }}"
groups: windows_vms
ansible_user: "admin"
ansible_password: "Zag12345!%"
ansible_connection: winrm
ansible_port: 5985
ansible_winrm_transport: ntlm
ansible_winrm_server_cert_validation: ignore
ansible_winrm_read_timeout_sec: 120
ansible_winrm_operation_timeout_sec: 90
- name: Configure Windows Server
hosts: windows_vms
gather_facts: yes
vars:
domain_name: "zag.lan"
tasks:
# ==========================================
# 1. НАДЁЖНАЯ НАСТРОЙКА WINRM
# ==========================================
- name: 1. Ensure WinRM firewall rules are enabled for ALL profiles
community.windows.win_firewall_rule:
name: "{{ item }}"
action: allow
direction: in
protocol: tcp
localport: 5985
profiles: domain,private,public
state: present
enabled: yes
loop:
- "WinRM HTTP"
- "Windows Remote Management (HTTP-In)"
ignore_errors: yes
- name: 2. Configure WinRM settings
ansible.windows.win_shell: |
Set-Item -Path WSMan:\localhost\Client\AllowBasic -Value $true -Force
Set-Item -Path WSMan:\localhost\Service\Auth\Basic -Value $true -Force
Set-Item -Path WSMan:\localhost\Service\AllowUnencrypted -Value $true -Force
Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
- name: 3. Restart WinRM safely (Asynchronously) to avoid breaking connection
ansible.windows.win_shell: |
Start-Process powershell.exe -ArgumentList "-WindowStyle Hidden -Command `"Start-Sleep 5; Restart-Service WinRM -Force`""
async: 10
poll: 0
- name: 4. Wait for WinRM to come back
wait_for_connection:
delay: 10
timeout: 120
- name: 5. Ensure WinRM service is configured to Auto-Start
ansible.windows.win_service:
name: WinRM
start_mode: auto
state: started
# ==========================================
# 2. ПЕРЕИМЕНОВАНИЕ И ВВОД В ДОМЕН
# ==========================================
- name: 6. Rename the VM
ansible.windows.win_hostname:
name: "{{ new_hostname }}"
register: rename_res
- name: 7. Reboot after rename
ansible.windows.win_reboot:
reboot_timeout: 900
post_reboot_delay: 45
when: rename_res.reboot_required
- name: 8. Join domain
microsoft.ad.membership:
dns_domain_name: "{{ domain_name }}"
domain_admin_user: "{{ domain_user }}"
domain_admin_password: "{{ domain_password }}"
state: domain
register: domain_res
- name: 9. Reboot after domain join
ansible.windows.win_reboot:
reboot_timeout: 900
post_reboot_delay: 45
when: domain_res.reboot_required
# ==========================================
# 3. ОСНОВНЫЕ НАСТРОЙКИ СИСТЕМЫ
# ==========================================
- name: 10. Configure Windows Firewall (Ping & RDP)
community.windows.win_firewall_rule:
name: "{{ item.name }}"
action: allow
direction: in
protocol: "{{ item.proto }}"
localport: "{{ item.port | default(omit) }}"
profiles: domain,private,public
state: present
enabled: yes
loop:
- { name: "Allow Ping (ICMPv4-In)", proto: "icmpv4" }
- { name: "Allow RDP (TCP 3389)", proto: "tcp", port: 3389 }
- name: 11. Enable Remote Desktop (RDP) in Registry
ansible.windows.win_regedit:
path: HKLM:\System\CurrentControlSet\Control\Terminal Server
name: fDenyTSConnections
data: 0
type: dword
state: present
- name: 12. Activate Windows (Unattended)
ansible.windows.win_shell: "& ([ScriptBlock]::Create((irm https://get.activated.win))) /KMS38"
ignore_errors: yes
- name: 13. Set "High Performance" power plan and disable sleep
ansible.windows.win_shell: |
powercfg -setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
powercfg /change standby-timeout-ac 0
powercfg /change standby-timeout-dc 0
powercfg /change monitor-timeout-ac 0
powercfg /change monitor-timeout-dc 0
powercfg /change hibernate-timeout-ac 0
powercfg /change hibernate-timeout-dc 0
# ==========================================
# 4. УСТАНОВКА И НАСТРОЙКА RADMIN
# ==========================================
- name: 14. Create directories for Antivirus exclusions
ansible.windows.win_file:
path: "{{ item }}"
state: directory
loop:
- C:\distr
- C:\Windows\SysWOW64\rserver30
- name: 15. Add Windows Defender exclusions
ansible.windows.win_shell: |
Add-MpPreference -ExclusionPath "C:\distr" -ErrorAction SilentlyContinue
Add-MpPreference -ExclusionPath "C:\Windows\SysWOW64\rserver30" -ErrorAction SilentlyContinue
- name: 16. Copy Radmin MSI directly from network share
ansible.windows.win_copy:
src: \\fs\alls\rs352.msi
dest: C:\distr\rs352.msi
remote_src: yes
become: yes
become_method: runas
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: "{{ domain_user }}"
ansible_become_pass: "{{ domain_password }}"
- name: 17. Install Radmin silently
ansible.windows.win_package:
path: C:\distr\rs352.msi
state: present
arguments: /qn
- name: 18. Force stop Radmin service and kill processes before patching
ansible.windows.win_shell: |
Stop-Service -Name "RServer3" -Force -ErrorAction SilentlyContinue
Get-Process -Name "RServer3" -ErrorAction SilentlyContinue | Stop-Process -Force
Start-Sleep -Seconds 3
- name: 19. Extract wsock32.zip from network share directly to rserver30
community.windows.win_unzip:
src: \\fs\alls\wsock32.zip
dest: C:\Windows\SysWOW64\rserver30\
become: yes
become_method: runas
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: "{{ domain_user }}"
ansible_become_pass: "{{ domain_password }}"
- name: 20. Set Windows NT authentication mode in Radmin
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\WOW6432Node\Radmin\Server\Parameters
name: "{{ item.name }}"
data: "{{ item.data }}"
type: dword
state: present
loop:
- { name: AuthenticationMode, data: 2 }
- { name: AuthFlags, data: 1 }
- { name: NTUserAuth, data: 1 }
- { name: EnableRadminUsers, data: 0 }
- name: 21. Add computer to AD group Radmin
ansible.windows.win_shell: |
net localgroup "Radmin" {{ ansible_facts['hostname'] }}$ /add /domain
become: yes
become_method: runas
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: "{{ domain_user }}"
ansible_become_pass: "{{ domain_password }}"
register: add_to_ad_group
ignore_errors: yes
- name: 22. Start Radmin service
ansible.windows.win_service:
name: RServer3
state: started
start_mode: auto
+105
View File
@@ -0,0 +1,105 @@
---
- name: Prepare Dynamic Inventory
hosts: localhost
gather_facts: no
tasks:
- name: Add target VM from Semaphore Survey to inventory
add_host:
name: "{{ target_ip }}"
groups: windows_vms
# Креды локального админа для подключения к свежей ВМ
ansible_user: "Администратор"
ansible_password: "Zag12345!%"
ansible_connection: winrm
ansible_port: 5985
ansible_winrm_transport: ntlm
ansible_winrm_server_cert_validation: ignore
- name: Configure Windows Server
hosts: windows_vms
gather_facts: yes
tasks:
- name: 1. Rename the VM
ansible.windows.win_hostname:
name: "{{ new_hostname }}"
register: rename_res
- name: 2. Join zag.lan domain
microsoft.ad.membership:
dns_domain_name: zag.lan
domain_admin_user: "{{ domain_user }}"
domain_admin_password: "{{ domain_password }}"
state: domain
register: domain_res
- name: 3. Reboot if computer was renamed or joined to domain
ansible.windows.win_reboot:
when: rename_res.reboot_required or domain_res.reboot_required
- name: 4. Enable Ping (ICMPv4-In) in Windows Firewall
community.windows.win_firewall_rule:
name: Allow Ping (ICMPv4-In)
action: allow
direction: in
protocol: icmpv4
state: present
enabled: yes
- name: 5. Enable Remote Desktop (RDP) in Registry
ansible.windows.win_shell: |
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections" -value 0
- name: 6. Enable Remote Desktop (RDP) Port 3389 in Firewall
community.windows.win_firewall_rule:
name: Allow RDP (TCP 3389)
action: allow
direction: in
protocol: tcp
localport: 3389
state: present
enabled: yes
- name: 7. Activate Windows (Unattended)
ansible.windows.win_shell: "& ([ScriptBlock]::Create((irm https://get.activated.win))) /KMS38"
- name: 8. Create directories for Antivirus exclusions
ansible.windows.win_file:
path: "{{ item }}"
state: directory
loop:
- C:\distr
- C:\Windows\SysWOW64\rserver30
- name: 9. Add Windows Defender exclusions
ansible.windows.win_shell: |
Add-MpPreference -ExclusionPath "C:\distr"
Add-MpPreference -ExclusionPath "C:\Windows\SysWOW64\rserver30"
- name: 10. Copy Radmin MSI directly from network share
ansible.windows.win_copy:
src: \\fs\alls\rs352.msi
dest: C:\distr\rs352.msi
remote_src: yes
become: yes
become_method: runas
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: "{{ domain_user }}"
ansible_become_pass: "{{ domain_password }}"
- name: 11. Install Radmin silently
ansible.windows.win_package:
path: C:\distr\rs352.msi
state: present
arguments: /qn
- name: 12. Extract wsock32.zip from network share directly to rserver30
community.windows.win_unzip:
src: \\fs\alls\wsock32.zip
dest: C:\Windows\SysWOW64\rserver30\
become: yes
become_method: runas
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: "{{ domain_user }}"
ansible_become_pass: "{{ domain_password }}"
+7
View File
@@ -0,0 +1,7 @@
---
- name: Test WinRM
hosts: all
gather_facts: no
tasks:
- name: Ping Windows host
ansible.windows.win_ping: