Having trouble getting ansible to install python on windows

Trying to install Python 3.10.5 on a Windows host.

I have tried both win_package and win_powershell to run an .exe for python on a windows host and in both cases it says “changed”:true and no errors, but it didn’t actually install it. Nothing updated in registry either. I don’t get it. And if I take the path command with arguments and paste it into a powershell window, it installs just fine. For example, here’s the command I can run in powershell, pasted from the ansible output:

\\\\tsi-nas\\Approved_Software\\Everyone\\Python\\python-3.10.5-amd64.exe /quiet InstallAllUsers=0 PrependPath=0 LongPathsEnabled=1

In both cases I have made sure that I properly uninstall it first and the registry entries are removed (because if the main registry entry is there then win_package just skips over it and doesn’t even try). I will include the playbook code and output for each.

Can someone tell me what I’m doing wrong here? And how do I debug this?

    - name: Install Python 3.10
      ansible.windows.win_package:
        path: \\tsi-nas\Approved_Software\Everyone\Python\python-3.10.5-amd64.exe
        product_id: '{0FE1250F-6DD6-4948-B211-741B7CDBB335}'
        arguments: /quiet InstallAllUsers=0 PrependPath=0 LongPathsEnabled=1
        state: present
      become: true
      become_method: runas
      vars:
        ansible_become_user: "{{ username }}"
        ansible_become_pass: "{{ password }}"

Read vars_file 'secrets.yml'

TASK [Install Python 3.10] *********************************************************************************************
task path: /home/greg/ansible_quickstart/win_playbook.yaml:21
Using module file /usr/lib/python3/dist-packages/ansible_collections/ansible/windows/plugins/modules/win_package.ps1
Pipelining is enabled.
<DEVOPS-GH-VM.tridsys.com> ESTABLISH WINRM CONNECTION FOR USER: greg on PORT 5986 TO DEVOPS-GH-VM.tridsys.com
EXEC (via pipeline wrapper)
changed: [DEVOPS-GH-VM.tridsys.com] => {
    "changed": true,
    "checksum": "058C5319E77A698B185975084C7BE7D25AE021B2",
    "invocation": {
        "module_args": {
            "arguments": "/quiet InstallAllUsers=0 PrependPath=0 LongPathsEnabled=1",
            "chdir": null,
            "checksum": null,
            "checksum_algorithm": "sha1",
            "client_cert": null,
            "client_cert_password": null,
            "creates_path": null,
            "creates_service": null,
            "creates_version": null,
            "expected_return_code": [
                0,
                3010
            ],
            "follow_redirects": "safe",
            "force_basic_auth": false,
            "headers": null,
            "http_agent": "ansible-httpget",
            "log_path": null,
            "maximum_redirection": 50,
            "path": "\\\\tsi-nas\\Approved_Software\\Everyone\\Python\\python-3.10.5-amd64.exe",
            "product_id": "{0FE1250F-6DD6-4948-B211-741B7CDBB335}",
            "provider": "auto",
            "proxy_password": null,
            "proxy_url": null,
            "proxy_use_default_credential": false,
            "proxy_username": null,
            "state": "present",
            "url_method": null,
            "url_password": null,
            "url_timeout": 30,
            "url_username": null,
            "use_default_credential": false,
            "use_proxy": true,
            "validate_certs": true,
            "wait_for_children": false
        }
    },
    "rc": 0,
    "reboot_required": false
}

PLAY RECAP *************************************************************************************************************
DEVOPS-GH-VM.tridsys.com   : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    - name: Install python via powershell
      ansible.windows.win_powershell:
        script: |
          \\tsi-nas\Approved_Software\Everyone\Python\python-3.10.5-amd64.exe /quiet InstallAllUsers=0 PrependPath=0 LongPathsEnabled=1
      become: true
      become_method: runas
      vars:
        ansible_become_user: "{{ username }}"
        ansible_become_pass: "{{ password }}"
Read vars_file 'secrets.yml'

TASK [Install python via powershell] ***********************************************************************************
task path: /home/greg/ansible_quickstart/powershell_python.yaml:6
Using module file /usr/lib/python3/dist-packages/ansible_collections/ansible/windows/plugins/modules/win_powershell.ps1
Pipelining is enabled.
<DEVOPS-GH-VM.tridsys.com> ESTABLISH WINRM CONNECTION FOR USER: greg on PORT 5986 TO DEVOPS-GH-VM.tridsys.com
EXEC (via pipeline wrapper)
changed: [DEVOPS-GH-VM.tridsys.com] => {
    "changed": true,
    "debug": [],
    "error": [],
    "host_err": "",
    "host_out": "",
    "information": [],
    "invocation": {
        "module_args": {
            "arguments": null,
            "chdir": null,
            "creates": null,
            "depth": 2,
            "error_action": "continue",
            "executable": null,
            "parameters": null,
            "removes": null,
            "script": "\\\\tsi-nas\\Approved_Software\\Everyone\\Python\\python-3.10.5-amd64.exe /quiet InstallAllUsers=0 PrependPath=0 LongPathsEnabled=1\n",
            "sensitive_parameters": null
        }
    },
    "output": [],
    "result": {},
    "verbose": [],
    "warning": []
}

PLAY RECAP *************************************************************************************************************
DEVOPS-GH-VM.tridsys.com   : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

It’s probably not it but are you 100% sure you aren’t running the win_package version in check mode? Does the Python installer have any logging available in it’s arguments you could possible enable to see what might be going wrong?

While I don’t install it from a UNC path I’ve used this very successfully in the past to install various python versions pyspnego/tests/integration/main.yml at 57ff8d2c177a453c4a032df71f80e6bfc9a8ca5c · jborean93/pyspnego · GitHub. While I use separate arguments they both should work. The fact it also works with win_powershell which runs in the same context as the win_package module is a bit weird.

Does the Python installer have any logging available in it’s arguments you could possible enable to see what might be going wrong?

Looking at 4. Using Python on Windows — Python 3.13.7 documentation it seems like you can add /log as one of the arguments

- name: Install Python 3.10
  ansible.windows.win_package:
    path: \\tsi-nas\Approved_Software\Everyone\Python\python-3.10.5-amd64.exe
    product_id: '{0FE1250F-6DD6-4948-B211-741B7CDBB335}'
    arguments: >-
      /quiet
      /log C:\Windows\TEMP\Python-install.log
      InstallAllUsers=0
      PrependPath=0
      LongPathsEnabled=1
    state: present
  become: true
  become_method: runas
  vars:
    ansible_become_user: "{{ username }}"
    ansible_become_pass: "{{ password }}"

Jordan,
Thank you for the insight. I had my mind set on troubleshooting Ansible with the logging that I completely forgot to focus on logging for Python.
So, this allowed me to discover a few things. I created logs for both a good and bad install with powershell directly and then the same command in ansible with powershell. The key thing that I saw that was off with ansible doing it was instead of it “Setting string variable ‘ActionLikeInstalling’ to value ‘Installing’”, it was setting the value to ‘Updating’ even though I had uninstalled it before. And I was trying to clear out the installation more by removing all the Python related entries in the registry under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall. But there are so many other registry entries sprinkled all over and I saw it was referencing this one “Registering dependency: {e15803b8-d809-47f3-8818-73f0d155cf58} on package provider” but that doesn’t exist in the Uninstall folder and I saw it was in several other places for different users.
So I realize a big thing here. I’m trying install with InstallAllUsers=0 and because I’m running the installer off of a shared network folder, I have to run as a particular user that has LDAP access to that drive, which in turn is also installing as that user which is not the user I’m logged in as and want to install under. So I think I need to copy the installer locally and run it that way if I want to install under that other user. Unless you can tell me if there is a different way to do this in one command where you access the path via one user and run the operation as another.

Glad the logging was able to identify what was going on here. Just as an FYI you can use become to specify credentials for outbound connections but still run the tasks locally as your normal user. See the examples under Understanding privilege escalation: become — Ansible Community Documentation specifically the win_copy task with the become flags logon_type=new_credentials logon_flags=netcredentials_only.