--- - name: Prepare target host hosts: localhost gather_facts: no tasks: - name: Add target host from survey ansible.builtin.add_host: name: "{{ target_ip }}" groups: dynamic_windows ansible_connection: winrm ansible_port: "{{ winrm_port | default(5985) }}" ansible_winrm_transport: "{{ winrm_transport | default('ntlm') }}" ansible_winrm_server_cert_validation: ignore ansible_winrm_read_timeout_sec: 600 ansible_winrm_operation_timeout_sec: 580 ansible_user: "{{ win_user }}" ansible_password: "{{ win_pass }}" - name: Install Software from SMB hosts: dynamic_windows gather_facts: no vars: local_dir: 'C:\Windows\Temp\ansible_install' local_file: "{{ local_dir }}\\{{ installer_file }}" install_dir: 'C:\Program Files\FreeCAD 1.1' tasks: - name: Check running FreeCAD ansible.windows.win_powershell: script: | $Ansible.Failed = $false $list = @(Get-CimInstance Win32_Process -Filter "Name = 'FreeCAD.exe'" -ErrorAction SilentlyContinue | ForEach-Object { $o = Invoke-CimMethod -InputObject $_ -MethodName GetOwner -ErrorAction SilentlyContinue "$($o.Domain)\$($o.User) (session $($_.SessionId))" }) $Ansible.Result = $list register: running changed_when: false - name: Fail if FreeCAD is running ansible.builtin.fail: msg: "FreeCAD запущен у: {{ running.result | join(', ') }}. Закройте его или включите force_close." when: running.result | length > 0 and not (force_close | default(false) | bool) - name: Force close FreeCAD ansible.windows.win_shell: Stop-Process -Name FreeCAD -Force -ErrorAction SilentlyContinue; exit 0 when: running.result | length > 0 and (force_close | default(false) | bool) - name: Copy installer from share to local temp ansible.windows.win_powershell: parameters: Share: "{{ smb_path }}" User: "{{ smb_user }}" Pass: "{{ smb_pass }}" File: "{{ installer_file }}" Dest: "{{ local_dir }}" script: | param($Share, $User, $Pass, $File, $Dest) $ErrorActionPreference = 'Continue' $res = @{ copied = $false; files = @(); error = '' } try { & net.exe use $Share /delete /y 2>&1 | Out-Null $out = & net.exe use $Share "/user:$User" $Pass 2>&1 | Out-String if ($LASTEXITCODE -ne 0) { $res.error = "net use failed (code $LASTEXITCODE): $out" } else { $res.files = @(Get-ChildItem -LiteralPath $Share -ErrorAction Stop | Select-Object -ExpandProperty Name) $src = Join-Path $Share $File if (-not (Test-Path -LiteralPath $src)) { $res.error = "Файл $File не найден на шаре" } else { New-Item -ItemType Directory -Path $Dest -Force | Out-Null Copy-Item -LiteralPath $src -Destination $Dest -Force -ErrorAction Stop $res.copied = $true } & net.exe use $Share /delete /y 2>&1 | Out-Null } } catch { $res.error = $_.Exception.Message } $Ansible.Result = $res register: copy_result no_log: true changed_when: false failed_when: false - name: Fail if copy did not succeed ansible.builtin.fail: msg: "Не удалось скопировать {{ installer_file }}: {{ copy_result.result.error | default('неизвестная ошибка') }}" when: not (copy_result.result.copied | default(false)) - name: Install and clean up block: - name: Install {{ installer_file }} ansible.windows.win_command: '"{{ local_file }}" /S /D={{ install_dir }}' args: creates: '{{ install_dir }}\bin\FreeCAD.exe' register: inst failed_when: inst.rc not in [0, 3010] become: yes become_method: runas become_user: "{{ win_user }}" become_password: "{{ win_pass }}" no_log: true - name: Verify FreeCAD.exe exists ansible.windows.win_stat: path: '{{ install_dir }}\bin\FreeCAD.exe' register: fc_check - name: Fail if FreeCAD was not installed ansible.builtin.fail: msg: "Установщик завершился, но {{ install_dir }}\\bin\\FreeCAD.exe не найден" when: not fc_check.stat.exists always: - name: Remove local installer copy ansible.windows.win_file: path: "{{ local_dir }}" state: absent