Repository: ansible/ansible

Issue:
Select a reference Windows module for the documentation
##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Documentation Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
win_environment

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
v2.4

##### SUMMARY
<!--- Explain the problem briefly -->
As discussed on IRC, let's declare one module the reference module for Windows and use it in the documentation for new module authors.

The module should have all these features:
- must be small in business logic
- must be idempotent
- must support check-mode
- must include `-validateset`
- must include `-failifempty`
- must include `-default`
- must include a bool-type parameter
- should include a path-type parameter
- should include a string-type parameter

The *win_service* module was our first candidate, but it has turned into a more complex example. It does meet all requirements. So we decided to use **win_environment** as *the* reference module.

The rewrite of this module and the expected bikeshedding will be done during the review-process in the PR. The PR will also include:
- Include plenty of annotations to guide the new contributor
- Ensure the module has a consistent CodingStyle that we prefer most (but we do not enforce it) @jborean93 
- We update this module every time we improve our standards, so that new and existing maintainers can track new standards


Discussion:
@jhawkesworth @nitzmahone @dav1x @jctanner As discussed on IRC.
mention @ilpianista who also mentioned on IRC

some other (unsorted) thoughts

what to put for metadata?
link to jimic's presentation(s) on writing modules?
a note about | out-null so you don't put unintended objects into the output pipelines (therefore putting cruft into the generated json.
avoid feeding trailing slashes on strings into ConvertTo-Json 'cos it makes it fail
link to how to run existing integration tests against your test windows machines/vms



Keep me in the loop, will help with the `developing_modules.html` rewrite that's going on. 
more thoughts...

need to support powershell 3 and above
links to powershell references

document return values
conventions for var names
conventions for return values
check with linux equivalents to make consistent names where possible, but only if it makes sense 

advanced topics:

example of calling .net class
example of embedding c# code
So we have 3 candidates, and win_service is no longer on the table :-)
```
[dag@moria ansible.git]$ grep -l -- '-type "str"' $(grep -l -- '-type "path"' $(grep -l -- '-type "bool"' $(grep -l default $(grep -l failifempty $(grep -l 'validateset' $(grep -rl '$check_mode' lib/ansible/modules/windows/))))))
lib/ansible/modules/windows/win_lineinfile.ps1
lib/ansible/modules/windows/win_owner.ps1
lib/ansible/modules/windows/win_uri.ps1
```

Of these, *win_uri* is clearly the most simple example, although it does have some things that require cleaning up.

- headers should be a dict (implement a dict-type !)
- fix the idempotency issue when writing to a file
- make it somewhat more feature complete with the **uri** module
- reorganize result
- add integration tests
- update documentation

So quite some work before we can consider it first-of-class.
It has been decided to use **win_environment** as it has the most simple implementation of an idempotent module supporting check-mode and diff support.

The upside is that we don't need to do a lot of work ;-)
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.

Resolving patch:
diff --git a/lib/ansible/modules/windows/win_environment.py b/lib/ansible/modules/windows/win_environment.py
--- a/lib/ansible/modules/windows/win_environment.py
+++ b/lib/ansible/modules/windows/win_environment.py
@@ -1,81 +1,56 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
-# (c) 2015, Jon Hawkesworth (@jhawkesworth) <figs@unity.demon.co.uk>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
-
-# this is a windows documentation stub.  actual code lives in the .ps1
-# file of the same name
+# Copyright: (c) 2015, Jon Hawkesworth (@jhawkesworth) <figs@unity.demon.co.uk>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
 
 ANSIBLE_METADATA = {'metadata_version': '1.1',
                     'status': ['preview'],
                     'supported_by': 'community'}
 
-
 DOCUMENTATION = r'''
 ---
 module: win_environment
-version_added: "2.0"
-short_description: Modifies environment variables on windows hosts.
+version_added: '2.0'
+short_description: Modify environment variables on windows hosts
 description:
-    - Uses .net Environment to set or remove environment variables and can set at User, Machine or Process level.
-    - User level environment variables will be set, but not available until the user has logged off and on again.
+- Uses .net Environment to set or remove environment variables and can set at User, Machine or Process level.
+- User level environment variables will be set, but not available until the user has logged off and on again.
 options:
   state:
     description:
-      - present to ensure environment variable is set, or absent to ensure it is removed
-    required: false
+    - Set to C(present) to ensure environment variable is set.
+    - Set to C(absent) to ensure it is removed.
+    choices: [ absent, present ]
     default: present
-    choices:
-      - present
-      - absent
   name:
     description:
-      - The name of the environment variable
+    - The name of the environment variable.
     required: true
-    default: no default
   value:
     description:
-      - The value to store in the environment variable. Can be omitted for state=absent
-    required: false
-    default: no default
+    - The value to store in the environment variable.
+    - Can be omitted for C(state=absent).
   level:
     description:
-      - The level at which to set the environment variable.
-      - Use 'machine' to set for all users.
-      - Use 'user' to set for the current user that ansible is connected as.
-      - Use 'process' to set for the current process.  Probably not that useful.
+    - The level at which to set the environment variable.
+    - Use C(machine) to set for all users.
+    - Use C(user) to set for the current user that ansible is connected as.
+    - Use C(process) to set for the current process.  Probably not that useful.
+    choices: [ machine, user, process ]
     required: true
-    default: no default
-    choices:
-      - machine
-      - process
-      - user
-author: "Jon Hawkesworth (@jhawkesworth)"
+author:
+- Jon Hawkesworth (@jhawkesworth)
 notes:
-   - This module is best-suited for setting the entire value of an
-     environment variable. For safe element-based management of
-     path-like environment vars, use the M(win_path) module.
-   - This module does not broadcast change events.
-     This means that the minority of windows applications which can have
-     their environment changed without restarting will not be notified and
-     therefore will need restarting to pick up new environment settings.
-     User level environment variables will require the user to log out
-     and in again before they become available.
+- This module is best-suited for setting the entire value of an
+  environment variable. For safe element-based management of
+  path-like environment vars, use the M(win_path) module.
+- This module does not broadcast change events.
+  This means that the minority of windows applications which can have
+  their environment changed without restarting will not be notified and
+  therefore will need restarting to pick up new environment settings.
+  User level environment variables will require the user to log out
+  and in again before they become available.
 '''
 
 EXAMPLES = r'''
@@ -95,24 +70,12 @@
 
 RETURN = r'''
 before_value:
-  description:
-  - the value of the environment key before a change, this is null if it didn't
-    exist
+  description: the value of the environment key before a change, this is null if it didn't exist
   returned: always
   type: string
   sample: C:\Windows\System32
-level:
-  description: the level set when calling the module
-  returned: always
-  type: string
-  sample: machine
-name:
-  description: the name of the environment key the module checked
-  returned: always
-  type: string
-  sample: JAVA_HOME
 value:
-  description: the value the environment key has been set to
+  description: the value the environment key has been set to, this is null if removed
   returned: always
   type: string
   sample: C:\Program Files\jdk1.8
diff --git a/lib/ansible/modules/windows/win_uri.py b/lib/ansible/modules/windows/win_uri.py
--- a/lib/ansible/modules/windows/win_uri.py
+++ b/lib/ansible/modules/windows/win_uri.py
@@ -1,26 +1,9 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
-# (c) 2015, Corwin Brown <corwin@corwinbrown.com>
-# (c) 2017, Dag Wieers <dag@wieers.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
-
-# this is a windows documentation stub.  actual code lives in the .ps1
-# file of the same name
+# Copyright: (c) 2015, Corwin Brown <corwin@corwinbrown.com>
+# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
 
 ANSIBLE_METADATA = {'metadata_version': '1.1',
                     'status': ['preview'],


Test patch:
diff --git a/test/integration/targets/win_environment/tasks/main.yml b/test/integration/targets/win_environment/tasks/main.yml
--- a/test/integration/targets/win_environment/tasks/main.yml
+++ b/test/integration/targets/win_environment/tasks/main.yml
@@ -45,9 +45,6 @@
     that:
     - create_machine|changed
     - create_machine.before_value == None
-    - create_machine.level == 'machine'
-    - create_machine.name == test_environment_name
-    - create_machine.value == test_machine_environment_value
     - create_machine_actual.stdout == "{{test_machine_environment_value}}\r\n"
 
 - name: create test environment value for machine again
@@ -67,9 +64,6 @@
     that:
     - not create_machine_again|changed
     - create_machine_again.before_value == test_machine_environment_value
-    - create_machine_again.level == 'machine'
-    - create_machine_again.name == test_environment_name
-    - create_machine_again.value == test_machine_environment_value
     - create_machine_actual_again.stdout == "{{test_machine_environment_value}}\r\n"
 
 - name: change test environment value for machine check
@@ -90,9 +84,6 @@
     that:
     - change_machine_check|changed
     - change_machine_check.before_value == test_machine_environment_value
-    - change_machine_check.level == 'machine'
-    - change_machine_check.name == test_environment_name
-    - change_machine_check.value == test_new_machine_environment_value
     - change_machine_actual_check.stdout == "{{test_machine_environment_value}}\r\n"
 
 - name: change test environment value for machine
@@ -112,9 +103,6 @@
     that:
     - change_machine|changed
     - change_machine.before_value == test_machine_environment_value
-    - change_machine.level == 'machine'
-    - change_machine.name == test_environment_name
-    - change_machine.value == test_new_machine_environment_value
     - change_machine_actual.stdout == "{{test_new_machine_environment_value}}\r\n"
 
 - name: change test environment value for machine again
@@ -134,9 +122,6 @@
     that:
     - not change_machine_again|changed
     - change_machine_again.before_value == test_new_machine_environment_value
-    - change_machine_again.level == 'machine'
-    - change_machine_again.name == test_environment_name
-    - change_machine_again.value == test_new_machine_environment_value
     - change_machine_actual_again.stdout == "{{test_new_machine_environment_value}}\r\n"
 
 - name: create test environment value for user check
@@ -175,9 +160,6 @@
     that:
     - create_user|changed
     - create_user.before_value == None
-    - create_user.level == 'user'
-    - create_user.name == test_environment_name
-    - create_user.value == test_user_environment_value
     - create_user_actual.stdout == "{{test_user_environment_value}}\r\n"
 
 - name: create test environment value for user again
@@ -197,9 +179,6 @@
     that:
     - not create_user_again|changed
     - create_user_again.before_value == test_user_environment_value
-    - create_user_again.level == 'user'
-    - create_user_again.name == test_environment_name
-    - create_user_again.value == test_user_environment_value
     - create_user_actual_again.stdout == "{{test_user_environment_value}}\r\n"
 
 - name: change test environment value for user check
@@ -220,9 +199,6 @@
     that:
     - change_user_check|changed
     - change_user_check.before_value == test_user_environment_value
-    - change_user_check.level == 'user'
-    - change_user_check.name == test_environment_name
-    - change_user_check.value == test_new_user_environment_value
     - change_user_actual_check.stdout == "{{test_user_environment_value}}\r\n"
 
 - name: change test environment value for user
@@ -242,9 +218,6 @@
     that:
     - change_user|changed
     - change_user.before_value == test_user_environment_value
-    - change_user.level == 'user'
-    - change_user.name == test_environment_name
-    - change_user.value == test_new_user_environment_value
     - change_user_actual.stdout == "{{test_new_user_environment_value}}\r\n"
 
 - name: change test environment value for user again
@@ -264,9 +237,6 @@
     that:
     - not change_user_again|changed
     - change_user_again.before_value == test_new_user_environment_value
-    - change_user_again.level == 'user'
-    - change_user_again.name == test_environment_name
-    - change_user_again.value == test_new_user_environment_value
     - change_user_actual_again.stdout == "{{test_new_user_environment_value}}\r\n"
 
 - name: cleanup test changes