Repository: ansible/ansible

Issue:
win_chocolatey: Cannot install hotfixes (KB####) over WinRM
##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
- `win_chocolatey`

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.3.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.12 (default, May  5 2017, 21:21:54) [GCC 6.3.0]
```

##### CONFIGURATION
- Default

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
- Ansible on **Gentoo**
- Target system is **Windows via WinRM**

##### SUMMARY
[Microsoft does not support](https://support.microsoft.com/en-us/help/2773898/windows-update-standalone-installer-wusa-returns-0x5-error-access-deni) using WUSA over a WinRM connection. If WUSA.exe has a WinRM session for an ancestor, it will exit immediately with "Access denied."

Chocolatey packages that install Windows hotfixes (kb######) use WUSA to install the update after downloading it. If the Chocolatey command is running within a WinRM session, it encounters the same problem.

Special-casing win_chocolatey for names beginning with "kb" is no solution either; some Chocolatey packages depend on these hotfix packages, perhaps even indirectly.

This could be argued as a bug with the Chocolatey packages themselves, as there exists some condition under which installation will fail. However, I believe this is appropriate as an Ansible bug, because the `win_chocolatey` task cannot install hotfixes (or packages depending on them) at all.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: Demonstrate bug with installing hotfixes over WinRM
  hosts: all
  tasks:
    - name: Install Chocolatey
      raw: "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))"
    - name: Attempt to install KB3033929
      win_chocolatey: name=kb3033929
```

<!--- You can also paste gist.github.com links for larger files -->
Please see [this gist](https://gist.github.com/CFSworks/490cf68574739df11b9deaaee1fcaa67) if you would like to reproduce the bug in Vagrant.

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
Hotfix package should install like any other Chocolatey package.

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
==> default: Running provisioner: ansible...
    default: Running ansible-playbook...

PLAY [Demonstrate bug with installing hotfixes over WinRM] *********************

TASK [Gathering Facts] *********************************************************
ok: [default]

TASK [Install Chocolatey] ******************************************************
changed: [default]

TASK [Attempt to install KB3033929] ********************************************
fatal: [default]: FAILED! => {"changed": false, "choco_error_cmd": "choco.exe install -dv -y kb3033929 -timeout 2700", "choco_error_log": null, "failed": true, "msg": "Error installing kb3033929", "rc": 5}
        to retry, use: --limit @/home/cfsworks/Desktop/winbug/playbook.retry

PLAY RECAP *********************************************************************
default                    : ok=2    changed=1    unreachable=0    failed=1   

Ansible failed to complete successfully. Any error output should be
visible above. Please fix these errors and try again.
```



Discussion:
cc @smadam813 @nitzmahone
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
I am not sure where the best place to fix this is (in chocolatey, or in ansible module), but there is a workaround.  From what you are saying it might need to be fixed in chocolatey as the ansible module would likely be unmanageable if it also included (and replicated exactly) chocolatey's dependency management.

Although you can't install using WUSA you can extract the contents of a .msu using WUSA and then use DISM to install the cab.

Here's an example from one of my roles:

```yaml
- name: check if Windows8.1-KB2999226-x64.msu hotfix has been applied
  win_shell: Get-Hotfix -Id KB2999226
  register: hotfix_status
  ignore_errors: true

- name: show hotfix status
  debug:
    var: hotfix_status

# Unfortunately you can't use wusa directly to install windows updates.
# see https://support.microsoft.com/en-us/kb/2773898 for details
# you have to unpack the update file and then use dism.exe to install the cab

- name: unpack the hotfix if needed
  win_shell: 'wusa C:\deployment\current\Windows8.1-KB2999226-x64.msu /extract:C:\deployment\archive'
  when: hotfix_status.rc == 1

- name: use dism to install the cab containing the hotfix
  win_shell: 'dism.exe /online /add-package /PackagePath:C:\deployment\archive\Windows8.1-KB2999226-x64.cab'
  when: hotfix_status.rc == 1
```




Another option is to use **win_psexec** to perform this task.

PS I noticed you are installing chocolatey with some powershell fu, but that's not needed. The **win_chocolatey** module will install Chocolatey automatically.
It should work if you run the task under `become_method: runas`- I've been considering how to support hotfix installation in general... We could do more shenanigans with scheduled tasks, make a scheduled_task runas method, or bake that all into the module (detect if we're running under an interactive session via become, and if not, use a scheduled task). 
That's awesome about the automatic installation @dagwieers - apparently I just missed that in the documentation.

At a bare minimum it might be a good idea to react to rc=0x5 and use a clearer msg - like `Error installing kb3033929 - Chocolatey reports 'Access denied'. Make sure you're running this task as a system administrator. It's also possible that the Chocolatey package is attempting to install a Windows hotfix (KB#######), in which case you must use "become_method: runas".`

@nitzmahone - I guess my only two cents I can offer on this would be to move the scheduled job logic from win_updates into `powershell.ps1` and provide an interface to modules that says "I need to run with scheduled/interactive permissions" since I doubt win_chocolatey and win_updates are going to be the only modules that need to escape the WinRM context. It also helps support the expectation that any playbook that works locally should also work remotely without modification.
cc @elventear @petemounce @trondhindenes
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
I can feel this coming:
```yaml
  become_method: scheduled_task
```
:-)
Now we have win_hotfix module http://docs.ansible.com/ansible/devel/win_hotfix_module.html maybe we can 'fix' this one by documenting that you should use win_hotfix to install hotfixes (due to the way chocolatey works which effectively requires an interactive session)?

@CFSworks Would the above be a reasonable fix?
@jhawkesworth I'm not opposed to a strongly-worded notice, either in documentation and/or at runtime when trying to manage a kb### package, reminding users that installing hotfixes through Chocolatey isn't recommended (especially as it's a really roundabout way of doing it).

However, I encountered this problem myself when trying to install a Chocolatey package that itself depended on a hotfix. I don't really mind needing to install the prerequisite hotfix as a separate task in the play, but investigating the mysterious "access denied" error certainly slowed me down (especially since I couldn't reproduce the error when running the playbook locally), and it'll break again if the Chocolatey folks should change the hotfix dependencies for the packages I'm using.

I don't really have any good ideas for fixing that. Ansible could, as you suggested at first, walk the dependency graph of the incoming Chocolatey package and look for hotfixes, but that just feels gross to me. I'm personally not using this module for much (my playbook configures a VM image; the occasional run failure is totally fine for my use case) but other users may or may not be impacted more heavily by this scenario, so I'd say it's up to you folks to decide whether this is fixed enough. :)
Thanks @CFSworks It feels to me like its a feature request for chocolatey to support installing hotfixes in a way that doesn't depend on interactive user being available.  If that was in place the whole experience could be transparent.  Ansible is just the wrapper on the erm, chocolatey bit here.

Were you able to try the `become_method: runas` way?  If that works it would be easy to put into the module examples.
@jhawkesworth, it's not the interactive bit that kills us rather the limitations with WSUS and WinRM which is not something chocolatey can really do. Become should work in this case as it runs it like you would locally.
@jborean93 - Glad there's a way to get it working.  
I have the feeling I am missing something obvious here.  Is there's more to solving this than just doing like microsoft suggests here: https://support.microsoft.com/en-us/kb/2773898 - extract using wusa and install using dism?    Fairly certain that works as I have used the above role https://github.com/ansible/ansible/issues/26385#issuecomment-312837682 for some time.  

That's what win_hotfix does but can be limited to where DISM is available. I don't believe hotfixes are different to normal updates when it comes to their composition so win_hotfix should work for normal updates as well
Right.  DISM seems to be fairly available https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/dism-supported-platforms - its just S2008 SP2 that seems to be without DISM support.
Because I'm using the DISM cmdlets with win_hotfix instead of the cmd, 2008 R2 and Windows doesn't support it out of the box. They can ultimately support it but the cmdlets need to be installed. Server 2008 (non R2) I don't think can use DISM to manage its own image but I haven't fully tested that out.
At 19:00 UTC on Tuesday 19 September 2017 this ticket will be processed during the second Windows Sprint,
https://github.com/ansible/community/wiki/Windows:-sprints
we would appreciate if you could join the Sprint to help out with understanding/fixing/closing this issue.
Discussed at the sprint.  @CFSworks - can you try using 'become' to see if this fixes?
If so I will document it in win_chocolatey examples.

needs_info

This is most certainly something that become would fix, the install script from chocolatey would be using the `wusa.exe` which is restricted under WinRM.

Documentation for become is here https://github.com/ansible/ansible/pull/30783, please feel free to review and add comments.

Resolving patch:
diff --git a/lib/ansible/modules/windows/win_chocolatey.py b/lib/ansible/modules/windows/win_chocolatey.py
--- a/lib/ansible/modules/windows/win_chocolatey.py
+++ b/lib/ansible/modules/windows/win_chocolatey.py
@@ -133,6 +133,9 @@
 - When using verbosity 4 (C(-vvvv)) the C(stdout) output will be more verbose.
 - When using verbosity 5 (C(-vvvvv)) the C(stdout) output will include debug output.
 - This module will install or upgrade Chocolatey when needed.
+- Some packages need an interactive user logon in order to install.  You can use (C(become)) to achieve this.
+- Even if you are connecting as local Administrator, using (C(become)) to become Administrator will give you an interactive user logon, see examples below.
+- Use (M(win_hotfix) to install hotfixes instead of (M(win_chocolatey)) as (M(win_hotfix)) avoids using wusa.exe which cannot be run remotely.
 author:
 - Trond Hindenes (@trondhindenes)
 - Peter Mounce (@petemounce)
@@ -173,10 +176,10 @@
     name: git
     state: absent
 
-- name: install multiple packages
+- name: Install multiple packages
   win_chocolatey:
     name: '{{ item }}'
-    state: absent
+    state: present
   with_items:
   - pscx
   - windirstat
@@ -202,6 +205,13 @@
     proxy_url: http://proxy-server:8080/
     proxy_username: user with \"escaped\" double quotes
     proxy_password: pass with \"escaped\" double quotes
+
+- name: Install a package that requires 'become'
+  win_chocolatey:
+    name: officepro2013
+  become: yes
+  become_user: Administrator
+  become_method: runas
 '''
 
 RETURN = r'''


Test patch: