Repository: ansible/ansible

Issue:
win_firewall_rule fails when locale isn't English
_From @ilpianista on November 29, 2016 10:45_

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
win_firewall_rule

##### ANSIBLE VERSION
```
ansible 2.2.0.0
```

##### OS / ENVIRONMENT
Target host is Windows 7 with German language.

##### SUMMARY
I've a task to open a firewall port.
The rule creation succeeded, but on the next execution of the same task it fails because win_firewall_rule tries to parse the output which is in German and not in English as the module does expect.

##### STEPS TO REPRODUCE
The rule is e.g.
```
name: Open required port on the firewall
win_firewall_rule: name="Foo 8080" localport="8080" protocol=TCP action=allow direction=In profile=public enable=yes state=present force=true
```
##### EXPECTED RESULTS
Task returns ok on every execution.

##### ACTUAL RESULTS
Task fails on rule check.

_Copied from original issue: ansible/ansible-modules-extras#3563_


Discussion:
_From @ansibot on November 29, 2016 10:57_

<!-- @ilpianista: Thanks for filing this bug report! -->
@TimothyVandenbrande ping, this issue is waiting for your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: issue_bug_new --->
cc @ar7z1
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
I reproduced the issue and working on a fix.
@ilpianista Can you please test whether PR #23162 also fixes your issue ?
@dagwieers thanks, I'll do as soon as possible, but in truth I'm a bit skeptical because I still see output matching based on English words (e.g. Rule Name).
@ilpianista Ah, was that also involved ? I thought it was only related to the error-string in the output.

PS It does work on a Dutch Windows 10 though. But I noticed not everything is translated to Dutch, so ...

Resolving patch:
diff --git a/lib/ansible/modules/windows/win_firewall_rule.py b/lib/ansible/modules/windows/win_firewall_rule.py
--- a/lib/ansible/modules/windows/win_firewall_rule.py
+++ b/lib/ansible/modules/windows/win_firewall_rule.py
@@ -1,21 +1,7 @@
 #!/usr/bin/env python
-
-# (c) 2014, Timothy Vandenbrande <timothy.vandenbrande@gmail.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/>.
+# Copyright (c) 2017 Artem Zinenko <zinenkoartem@gmail.com>
+# Copyright (c) 2014 Timothy Vandenbrande <timothy.vandenbrande@gmail.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
 
 ANSIBLE_METADATA = {'metadata_version': '1.0',
                     'status': ['preview'],
@@ -26,80 +12,70 @@
 ---
 module: win_firewall_rule
 version_added: "2.0"
-author: Timothy Vandenbrande
+author:
+  - Artem Zinenko (@ar7z1)
+  - Timothy Vandenbrande (@TimothyVandenbrande)
 short_description: Windows firewall automation
 description:
-    - Allows you to create/remove/update firewall rules
+  - Allows you to create/remove/update firewall rules.
 options:
-    enabled:
-        description:
-            - Is this firewall rule enabled or disabled
-        default: 'yes'
-        choices: [ 'no', 'yes' ]
-        aliases: [ 'enable' ]
-    state:
-        description:
-            - Should this rule be added or removed
-        default: "present"
-        choices: ['present', 'absent']
-    name:
-        description:
-            - The rules name
-        required: true
-    direction:
-        description:
-            - Is this rule for inbound or outbound traffic
-        required: true
-        choices: ['in', 'out']
-    action:
-        description:
-            - What to do with the items this rule is for
-        required: true
-        choices: ['allow', 'block', 'bypass']
+  enabled:
+    description:
+      - Is this firewall rule enabled or disabled.
+    type: bool
+    default: 'yes'
+    aliases: [ 'enable' ]
+  state:
+    description:
+      - Should this rule be added or removed.
+    default: "present"
+    choices: ['present', 'absent']
+  name:
+    description:
+      - The rules name
+    required: true
+  direction:
+    description:
+      - Is this rule for inbound or outbound traffic.
+    required: true
+    choices: ['in', 'out']
+  action:
+    description:
+      - What to do with the items this rule is for.
+    required: true
+    choices: ['allow', 'block', 'bypass']
+  description:
+    description:
+      - Description for the firewall rule.
+  localip:
+    description:
+      - The local ip address this rule applies to.
+    default: 'any'
+  remoteip:
+    description:
+      - The remote ip address/range this rule applies to.
+    default: 'any'
+  localport:
+    description:
+      - The local port this rule applies to.
+  remoteport:
+    description:
+      - The remote port this rule applies to.
+  program:
+    description:
+      - The program this rule applies to.
+  service:
+    description:
+      - The service this rule applies to.
+  protocol:
+    description:
+      - The protocol this rule applies to.
+    default: 'any'
+  profiles:
     description:
-        description:
-            - Description for the firewall rule
-    localip:
-        description:
-            - The local ip address this rule applies to
-        default: 'any'
-    remoteip:
-        description:
-            - The remote ip address/range this rule applies to
-        default: 'any'
-    localport:
-        description:
-            - The local port this rule applies to
-    remoteport:
-        description:
-            - The remote port this rule applies to
-    program:
-        description:
-            - The program this rule applies to
-    service:
-        description:
-            - The service this rule applies to
-    protocol:
-        description:
-            - The protocol this rule applies to
-        default: 'any'
-    profiles:
-        description:
-            - The profile this rule applies to
-        default: 'domain,private,public'
-        aliases: [ 'profile' ]
-    force:
-        description:
-            - Replace any existing rule by removing it first.
-        default: 'no'
-        choices: [ 'no', 'yes' ]
-notes:
-- The implementation uses C(netsh advfirewall) underneath, a pure-Powershell
-  reimplementation would be more powerful.
-- Modifying existing firewall rules is not possible, the module does allow
-  replacing complete rules based on name, but that works by removing the
-  existing rule completely, and recreating it with provided information
-  (when using C(force)).
+      - The profile this rule applies to.
+    default: 'domain,private,public'
+    aliases: [ 'profile' ]
 '''
 
 EXAMPLES = r'''


Test patch:
diff --git a/test/integration/targets/win_firewall_rule/tasks/main.yml b/test/integration/targets/win_firewall_rule/tasks/main.yml
--- a/test/integration/targets/win_firewall_rule/tasks/main.yml
+++ b/test/integration/targets/win_firewall_rule/tasks/main.yml
@@ -2,11 +2,8 @@
   win_firewall_rule:
     name: http
     state: absent
-    action: "{{ item }}"
+    action: allow
     direction: in
-  with_items:
-     - allow
-     - block
 
 - name: Add firewall rule
   win_firewall_rule:
@@ -82,25 +79,7 @@
     direction: in
     protocol: tcp
 
-- name: Add different firewall rule
-  win_firewall_rule:
-    name: http
-    enabled: yes
-    state: present
-    localport: 80
-    action: block
-    direction: in
-    protocol: tcp
-  ignore_errors: yes
-  register: add_different_firewall_rule_without_force
-
-- name: Check that creating different firewall rule without enabling force setting fails
-  assert:
-    that:
-    - add_different_firewall_rule_without_force.failed == true
-    - add_different_firewall_rule_without_force.changed == false
-
-- name: Add different firewall rule with force setting
+- name: Change firewall rule
   win_firewall_rule:
     name: http
     enabled: yes
@@ -109,13 +88,12 @@
     action: block
     direction: in
     protocol: tcp
-    force: yes
-  register: add_different_firewall_rule_with_force
+  register: change_firewall_rule
 
-- name: Check that creating different firewall rule with enabling force setting succeeds
+- name: Check that changing firewall rule succeeds
   assert:
     that:
-    - add_different_firewall_rule_with_force.changed == true
+    - change_firewall_rule.changed == true
 
 - name: Add firewall rule when remoteip is range
   win_firewall_rule:
@@ -127,7 +105,6 @@
     action: allow
     direction: in
     protocol: tcp
-    force: yes
 
 - name: Add same firewall rule when remoteip is range (again)
   win_firewall_rule:
@@ -156,7 +133,6 @@
     action: allow
     direction: in
     protocol: tcp
-    force: yes
 
 - name: Add same firewall rule when remoteip in CIDR notation (again)
   win_firewall_rule:
@@ -181,11 +157,10 @@
     enabled: yes
     state: present
     localport: 80
-    remoteip: 192.168.0.0/255.255.255.0
+    remoteip: 192.168.1.0/255.255.255.0
     action: allow
     direction: in
     protocol: tcp
-    force: yes
 
 - name: Add same firewall rule when remoteip contains a netmask (again)
   win_firewall_rule:
@@ -193,7 +168,7 @@
     enabled: yes
     state: present
     localport: 80
-    remoteip: 192.168.0.0/255.255.255.0
+    remoteip: 192.168.1.0/255.255.255.0
     action: allow
     direction: in
     protocol: tcp
@@ -214,7 +189,6 @@
     action: allow
     direction: in
     protocol: tcp
-    force: yes
 
 - name: Add same firewall rule when remoteip is IPv4 (again)
   win_firewall_rule:
@@ -232,3 +206,122 @@
   assert:
     that:
     - add_firewall_rule_with_ipv4_remoteip_again.changed == false
+
+- name: Add firewall rule when remoteip contains a netmask
+  win_firewall_rule:
+    name: http
+    enabled: yes
+    state: present
+    localport: 80
+    remoteip: 192.168.2.0/255.255.255.0
+    action: allow
+    direction: in
+    protocol: tcp
+
+- name: Add same firewall rule when remoteip in CIDR notation
+  win_firewall_rule:
+    name: http
+    enabled: yes
+    state: present
+    localport: 80
+    remoteip: 192.168.2.0/24
+    action: allow
+    direction: in
+    protocol: tcp
+  register: add_same_firewall_rule_with_cidr_remoteip
+
+- name: Check that creating same firewall rule succeeds without a change when remoteip contains a netmask or CIDR
+  assert:
+    that:
+    - add_same_firewall_rule_with_cidr_remoteip.changed == false
+
+- name: Add firewall rule with multiple ports
+  win_firewall_rule:
+    name: http
+    enabled: yes
+    state: present
+    localport: '80,81'
+    action: allow
+    direction: in
+    protocol: tcp
+  register: add_firewall_rule_with_multiple_ports
+
+- name: Check that creating firewall rule with multiple ports succeeds with a change
+  assert:
+    that:
+    - add_firewall_rule_with_multiple_ports.changed == true
+
+- name: Add firewall rule with interface types
+  win_firewall_rule:
+    name: http
+    enabled: yes
+    state: present
+    localport: 80
+    action: allow
+    direction: in
+    protocol: tcp
+    interfacetypes: 'ras,lan,wireless'
+  register: add_firewall_rule_with_interface_types
+
+- name: Check that creating firewall rule with interface types succeeds with a change
+  assert:
+    that:
+    - add_firewall_rule_with_interface_types.changed == true
+
+- name: Add firewall rule with interface type 'any'
+  win_firewall_rule:
+    name: http
+    enabled: yes
+    state: present
+    localport: 80
+    action: allow
+    direction: in
+    protocol: tcp
+    interfacetypes: any
+  register: add_firewall_rule_with_interface_type_any
+
+- name: Check that creating firewall rule with interface type 'any' succeeds with a change
+  assert:
+    that:
+    - add_firewall_rule_with_interface_type_any.changed == true
+
+- name: Add firewall rule with edge traversal option 'deferapp'
+  win_firewall_rule:
+    name: http
+    enabled: yes
+    state: present
+    localport: 80
+    action: allow
+    direction: in
+    protocol: tcp
+    edge: deferapp
+  register: add_firewall_rule_with_edge_traversal
+
+# Setup action creates ansible_distribution_version variable
+- action: setup
+
+- name: Check that creating firewall rule with enge traversal option 'deferapp' succeeds with a change
+  assert:
+    that:
+    - add_firewall_rule_with_edge_traversal.changed == true
+  # Works on windows >= Windows 7/Windows Server 2008 R2
+  when: ansible_distribution_version | version_compare('6.1', '>=')
+
+- name: Add firewall rule with 'authenticate' secure flag
+  win_firewall_rule:
+    name: http
+    enabled: yes
+    state: present
+    localport: 80
+    action: allow
+    direction: in
+    protocol: tcp
+    security: authenticate
+  register: add_firewall_rule_with_secure_flags
+
+- name: Check that creating firewall rule with secure flag 'authenticate' succeeds with a change
+  assert:
+    that:
+    - add_firewall_rule_with_secure_flags.changed == true
+  # Works on windows >= Windows 8/Windows Server 2012
+  when: ansible_distribution_version | version_compare('6.2', '>=')