diff --git a/lib/ansible/modules/windows/win_firewall_rule.ps1 b/lib/ansible/modules/windows/win_firewall_rule.ps1 index 754198b75de9cd..a61e1a1547a84a 100644 --- a/lib/ansible/modules/windows/win_firewall_rule.ps1 +++ b/lib/ansible/modules/windows/win_firewall_rule.ps1 @@ -20,12 +20,30 @@ # WANT_JSON # POWERSHELL_COMMON +# TODO: Reimplement this using Powershell cmdlets + +$ErrorActionPreference = "Stop" + function convertToNetmask($maskLength) { - [IPAddress] $ip = 0; + [IPAddress] $ip = 0 $ip.Address = ([UInt32]::MaxValue) -shl (32 - $maskLength) -shr (32 - $maskLength) return $ip.IPAddressToString } +function ConvertTo-TitleCase($string) { + return (Get-Culture).TextInfo.ToTitleCase($string.ToLower()) +} + +function ConvertTo-SortedKV($object, $unsupported = @()) { + $output = "" + foreach($item in $object.GetEnumerator() | Sort -Property Name) { + if (($item.Name -notin $unsupported) -and ($item.Value -ne $null)) { + $output += "$($item.Name): $($item.Value)`n" + } + } + return $output +} + function preprocessAndCompare($key, $outputValue, $fwsettingValue) { if ($key -eq 'RemoteIP') { if ($outputValue -eq $fwsettingValue) { @@ -54,351 +72,382 @@ function preprocessAndCompare($key, $outputValue, $fwsettingValue) { } } } - elseif ($key -eq 'Profiles') { - if (($fwsettingValue -eq "any") -and ($outputValue -eq "Domain,Private,Public")) { - return $true - } - } return $false } function getFirewallRule ($fwsettings) { - try { + $diff = $false + $result = @{ + changed = $false + identical = $false + exists = $false + failed = $false + msg = @() + multiple = $false + } - #$output = Get-NetFirewallRule -name $($fwsettings.'Rule Name'); - $rawoutput=@(netsh advfirewall firewall show rule name="$($fwsettings.'Rule Name')" verbose) - if (!($rawoutput -eq 'No rules match the specified criteria.')){ - $rawoutput | Where {$_ -match '^([^:]+):\s*(\S.*)$'} | Foreach -Begin { - $FirstRun = $true; - $HashProps = @{}; + try { + $command = "netsh advfirewall firewall show rule name=`"$($fwsettings.'Rule Name')`" verbose" + #$output = Get-NetFirewallRule -name $($fwsettings.'Rule Name') + $result.output = Invoke-Expression $command | Where { $_ } + $rc = $LASTEXITCODE + if ($rc -eq 1) { + $result.msg += @("No rule '$name' could be found") + } elseif ($rc -eq 0) { + # Process command output + $result.output | Where {$_ -match '^([^:]+):\s*(\S.*)$'} | ForEach -Begin { + $FirstRun = $true + $HashProps = @{} } -Process { - if (($Matches[1] -eq 'Rule Name') -and (!($FirstRun))) { - #$output=New-Object -TypeName PSCustomObject -Property $HashProps; - $output=$HashProps; - $HashProps = @{}; - }; - $HashProps.$($Matches[1]) = $Matches[2]; - $FirstRun = $false; + if (($Matches[1] -eq 'Rule Name') -and (-not $FirstRun)) { + $output = $HashProps + $HashProps = @{} + } + $HashProps.$($Matches[1]) = $Matches[2] + $FirstRun = $false } -End { - #$output=New-Object -TypeName PSCustomObject -Property $HashProps; - $output=$HashProps; + $output = $HashProps } - } - $exists=$false; - $correct=$true; - $diff=$false; - $multi=$false; - $correct=$false; - $difference=@(); - $msg=@(); - if ($($output|measure).count -gt 0) { - $exists=$true; - $msg += @("The rule '" + $fwsettings.'Rule Name' + "' exists."); - if ($($output|measure).count -gt 1) { - $multi=$true - $msg += @("The rule '" + $fwsettings.'Rule Name' + "' has multiple entries."); - ForEach($rule in $output.GetEnumerator()) { + if ($($output|measure).count -gt 0) { + $diff = $false + $result.exists = $true + #$result.msg += @("The rule '$($fwsettings.'Rule Name')' exists.") + if ($($output|measure).count -gt 1) { + $result.multiple = $true + $result.msg += @("The rule '$($fwsettings.'Rule Name')' has multiple entries.") + $result.diff = @{} + $result.diff.after = ConvertTo-SortedKV $fwsettings + $result.diff.before = ConvertTo-SortedKV $rule $unsupported + if ($result.diff.after -ne $result.diff.before ) { + $diff = $true + } + } else { + if ($diff_support) { + $result.diff = @{} + $result.diff.after = ConvertTo-SortedKV $fwsettings + $result.diff.before = ConvertTo-SortedKV $output $unsupported + } ForEach($fwsetting in $fwsettings.GetEnumerator()) { - if ( $rule.$fwsetting -ne $fwsettings.$fwsetting) { - $diff=$true; - #$difference+=@($fwsettings.$($fwsetting.Key)); - $difference+=@("output:$rule.$fwsetting,fwsetting:$fwsettings.$fwsetting"); - }; - }; - if ($diff -eq $false) { - $correct=$true - }; - }; - } else { - ForEach($fwsetting in $fwsettings.GetEnumerator()) { - if ($output.$($fwsetting.Key) -ne $fwsettings.$($fwsetting.Key)) { - if ((preprocessAndCompare -key $fwsetting.Key -outputValue $output.$($fwsetting.Key) -fwsettingValue $fwsettings.$($fwsetting.Key))) { - Continue - } elseif (($fwsetting.Key -eq 'DisplayName') -and ($output."Rule Name" -eq $fwsettings.$($fwsetting.Key))) { - Continue - } else { - $diff=$true; - $difference+=@($fwsettings.$($fwsetting.Key)); - }; - }; - }; - if ($diff -eq $false) { - $correct=$true - }; - }; - if ($correct) { - $msg += @("An identical rule exists"); - } else { - $msg += @("The rule exists but has different values"); + if ($output.$($fwsetting.Key) -ne $fwsettings.$($fwsetting.Key)) { + if ((preprocessAndCompare -key $fwsetting.Key -outputValue $output.$($fwsetting.Key) -fwsettingValue $fwsettings.$($fwsetting.Key))) { + Continue + } elseif (($fwsetting.Key -eq 'DisplayName') -and ($output."Rule Name" -eq $fwsettings.$($fwsetting.Key))) { + Continue + } elseif (($fwsetting.Key -eq 'Program') -and ($output.$($fwsetting.Key) -eq (Expand-Environment($fwsettings.$($fwsetting.Key))))) { + # Ignore difference caused by expanded environment variables + Continue + } else { + $diff = $true + Break + } + } + } + } + if (-not $diff) { + $result.identical = $true + } + if ($result.identical) { + $result.msg += @("The rule '$name' exists and is identical") + } else { + $result.msg += @("The rule '$name' exists but has different values") + } } } else { - $msg += @("No rule could be found"); - }; - $result = @{ - failed = $false - exists = $exists - identical = $correct - multiple = $multi - difference = $difference - msg = $msg - } - } catch [Exception]{ - $result = @{ - failed = $true - error = $_.Exception.Message - msg = $msg + $result.failed = $true } - }; + } catch [Exception] { + $result.failed = $true + $result.error = $_.Exception.Message + } return $result -}; +} function createFireWallRule ($fwsettings) { - $msg=@() - $execString="netsh advfirewall firewall add rule" + $result = @{ + changed = $false + failed = $false + msg = @() + } + $command = "netsh advfirewall firewall add rule" ForEach ($fwsetting in $fwsettings.GetEnumerator()) { - if ($fwsetting.key -eq 'Direction') { - $key='dir' - } elseif ($fwsetting.key -eq 'Rule Name') { - $key='name' - } elseif ($fwsetting.key -eq 'Enabled') { - $key='enable' - } elseif ($fwsetting.key -eq 'Profiles') { - $key='profile' - } else { - $key=$($fwsetting.key).ToLower() - }; - $execString+=" "; - $execString+=$key; - $execString+="="; - $execString+='"'; - $execString+=$fwsetting.value; - $execString+='"'; - }; - try { - #$msg+=@($execString); - $output=$(Invoke-Expression $execString| ? {$_}); - $msg+=@("Created firewall rule $name"); - - $result=@{ - failed = $false - output=$output - changed=$true - msg=$msg - }; + if ($fwsetting.value -ne $null) { + switch($fwsetting.key) { + "Direction" { $option = "dir" } + "Rule Name" { $option = "name" } + "Enabled" { $option = "enable" } + "Profiles" { $option = "profile" } + "InterfaceTypes" { $option = "interfacetype" } + "Security" { $option = "security" } + "Edge traversal" { $option = "edge" } + default { $option = $($fwsetting.key).ToLower() } + } + $command += " $option='$($fwsetting.value)'" + } + } + try { + $rc = 0 + if (-not $check_mode) { + $result.output = Invoke-Expression $command | Where { $_ } + $rc = $LASTEXITCODE + } + if ($rc -eq 0) { + if ($diff_support) { + $result.diff = @{} + $result.diff.after = ConvertTo-SortedKV $fwsettings + $result.diff.before= "" + } + $result.changed = $true + $result.msg += @("Created firewall rule '$name'") + } else { + $result.failed = $true + $result.msg += @("Create command '$command' failed with rc=$rc") + } } catch [Exception]{ - $msg=@("Failed to create the rule") - $result=@{ - output=$output - failed=$true - error=$_.Exception.Message - msg=$msg - }; - }; + $result.error = $_.Exception.Message + $result.failed = $true + $result.msg = @("Failed to create the rule '$name'") + } return $result -}; +} function removeFireWallRule ($fwsettings) { - $msg=@() + $result = @{ + changed = $false + failed = $false + msg = @() + } + + $command = "netsh advfirewall firewall delete rule name='$($fwsettings.'Rule Name')'" try { - $rawoutput=@(netsh advfirewall firewall delete rule name="$($fwsettings.'Rule Name')") - $rawoutput | Where {$_ -match '^([^:]+):\s*(\S.*)$'} | Foreach -Begin { - $FirstRun = $true; - $HashProps = @{}; - } -Process { - if (($Matches[1] -eq 'Rule Name') -and (!($FirstRun))) { - $output=$HashProps; - $HashProps = @{}; - }; - $HashProps.$($Matches[1]) = $Matches[2]; - $FirstRun = $false; - } -End { - $output=$HashProps; - }; - $msg+=@("Removed the rule") - $result=@{ - failed=$false - changed=$true - msg=$msg - output=$output - }; - } catch [Exception]{ - $msg+=@("Failed to remove the rule") - $result=@{ - failed=$true - error=$_.Exception.Message - msg=$msg + $rc = 0 + if (-not $check_mode) { + $result.output = Invoke-Expression $command | Where { $_ } + $rc = $LASTEXITCODE + $result.output | Where {$_ -match '^([^:]+):\s*(\S.*)$'} | Foreach -Begin { + $FirstRun = $true + $HashProps = @{} + } -Process { + if (($Matches[1] -eq 'Rule Name') -and (-not $FirstRun)) { + $result.output = $HashProps + $HashProps = @{} + } + $HashProps.$($Matches[1]) = $Matches[2] + $FirstRun = $false + } -End { + $result.output = $HashProps + } + } + if ($rc -eq 0 -or $rc -eq 1) { + if ($diff_support) { + $result.diff = @{} + $result.diff.after = "" + $result.diff.before = ConvertTo-SortedKV $fwsettings + } + $result.changed = $true + $result.msg += @("Removed the rule '$name'") + } else { + $result.failed = $true + $result.msg += @("Remove command '$command' failed with rc=$rc") } - }; + } catch [Exception]{ + $result.error = $_.Exception.Message + $result.failed = $true + $result.msg += @("Failed to remove the rule '$name'") + } return $result } -# Mount Drives -$change=$false; -$fail=$false; -$msg=@(); -$fwsettings=@{} +# FIXME: Unsupported keys +#$unsupported = @("Grouping", "Rule source") +$unsupported = @("Rule source") + +$result = @{ + changed = $false + fwsettings = @{} + msg = @() +} -# Variabelise the arguments -$params=Parse-Args $args; +$params = Parse-Args $args -supports_check_mode $true +$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false +$diff_support = Get-AnsibleParam -obj $params -name "_ansible_diff" -type "bool" -default $false $name = Get-AnsibleParam -obj $params -name "name" -failifempty $true -$direction = Get-AnsibleParam -obj $params -name "direction" -failifempty $true -validateSet "in","out" -$action = Get-AnsibleParam -obj $params -name "action" -failifempty $true -validateSet "allow","block","bypass" -$program = Get-AnsibleParam -obj $params -name "program" -$service = Get-AnsibleParam -obj $params -name "service" -default "any" -$description = Get-AnsibleParam -obj $params -name "description" -$enable = ConvertTo-Bool (Get-AnsibleParam -obj $params -name "enable" -default "true") -$winprofile = Get-AnsibleParam -obj $params -name "profile" -default "any" -$localip = Get-AnsibleParam -obj $params -name "localip" -default "any" -$remoteip = Get-AnsibleParam -obj $params -name "remoteip" -default "any" -$localport = Get-AnsibleParam -obj $params -name "localport" -default "any" -$remoteport = Get-AnsibleParam -obj $params -name "remoteport" -default "any" -$protocol = Get-AnsibleParam -obj $params -name "protocol" -default "any" - -$state = Get-AnsibleParam -obj $params -name "state" -failifempty $true -validateSet "present","absent" -$force = ConvertTo-Bool (Get-AnsibleParam -obj $params -name "force" -default "false") +$description = Get-AnsibleParam -obj $params -name "description" -type "str" +$direction = Get-AnsibleParam -obj $params -name "direction" -type "str" -failifempty $true -validateset "in","out" +$action = Get-AnsibleParam -obj $params -name "action" -type "str" -failifempty $true -validateset "allow","block","bypass" +$program = Get-AnsibleParam -obj $params -name "program" -type "str" +$service = Get-AnsibleParam -obj $params -name "service" -type "str" +$enabled = Get-AnsibleParam -obj $params -name "enabled" -type "bool" -default $true -aliases "enable" +$profiles = Get-AnsibleParam -obj $params -name "profiles" -type "str" -default "domain,private,public" -aliases "profile" +$localip = Get-AnsibleParam -obj $params -name "localip" -type "str" -default "any" +$remoteip = Get-AnsibleParam -obj $params -name "remoteip" -type "str" -default "any" +$localport = Get-AnsibleParam -obj $params -name "localport" -type "str" +$remoteport = Get-AnsibleParam -obj $params -name "remoteport" -type "str" +$protocol = Get-AnsibleParam -obj $params -name "protocol" -type "str" -default "any" +$edge = Get-AnsibleParam -obj $params -name "edge" -type "str" -default "no" -validateset "no","yes","deferapp","deferuser" +$interfacetypes = Get-AnsibleParam -obj $params -name "interfacetypes" -type "str" -default "any" +$security = Get-AnsibleParam -obj $params -name "security" -type "str" -default "notrequired" + +$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "present","absent" +$force = Get-AnsibleParam -obj $params -name "force" -type "bool" -default $false # Check the arguments -If ($enable -eq $true) { - $fwsettings.Add("Enabled", "yes"); -} Else { - $fwsettings.Add("Enabled", "no"); -}; - -$fwsettings.Add("Rule Name", $name) -#$fwsettings.Add("displayname", $name) - -$state = $state.ToString().ToLower() -If ($state -eq "present"){ - $fwsettings.Add("Direction", $direction) - $fwsettings.Add("Action", $action) -}; - -If ($description) { - $fwsettings.Add("Description", $description); +if ($enabled) { + $result.fwsettings.Add("Enabled", "Yes") +} else { + $result.fwsettings.Add("Enabled", "No") } -If ($program) { - $fwsettings.Add("Program", $program); +$result.fwsettings.Add("Rule Name", $name) +#$result.fwsettings.Add("displayname", $name) + +if ($state -eq "present") { + $result.fwsettings.Add("Direction", $(ConvertTo-TitleCase($direction))) + $result.fwsettings.Add("Action", $(ConvertTo-TitleCase $action)) } -$fwsettings.Add("LocalIP", $localip); -$fwsettings.Add("RemoteIP", $remoteip); -$fwsettings.Add("LocalPort", $localport); -$fwsettings.Add("RemotePort", $remoteport); -$fwsettings.Add("Service", $service); -$fwsettings.Add("Protocol", $protocol); -$fwsettings.Add("Profiles", $winprofile) - -$output=@() -$capture=getFirewallRule ($fwsettings); -if ($capture.failed -eq $true) { - $msg+=$capture.msg; - $result=New-Object psobject @{ - changed=$false - failed=$true - error=$capture.error - msg=$msg - }; - Exit-Json $result; +if ($description -ne $null) { + $result.fwsettings.Add("Description", $description) +} + +if ($program -ne $null) { + $result.fwsettings.Add("Program", $program) +} + +$result.fwsettings.Add("LocalIP", $localip) +$result.fwsettings.Add("RemoteIP", $remoteip) + +if ($localport -ne $null) { + $result.fwsettings.Add("LocalPort", $localport) +} + +if ($remoteport -ne $null) { + $result.fwsettings.Add("RemotePort", $remoteport) +} + +if ($service -ne $null) { + $result.fwsettings.Add("Service", $(ConvertTo-TitleCase($service))) +} + +if ($protocol -eq "Any") { + $result.fwsettings.Add("Protocol", $protocol) } else { - $diff=$capture.difference - $msg+=$capture.msg; - $identical=$capture.identical; - $multiple=$capture.multiple; + $result.fwsettings.Add("Protocol", $protocol.toupper()) } +if ($profiles -eq "Any") { + $result.fwsettings.Add("Profiles", "Domain,Private,Public") +} else { + $result.fwsettings.Add("Profiles", $(ConvertTo-TitleCase($profiles))) +} -switch ($state){ - "present" { - if ($capture.exists -eq $false) { - $capture=createFireWallRule($fwsettings); - $msg+=$capture.msg; - $change=$true; - if ($capture.failed -eq $true){ - $result=New-Object psobject @{ - failed=$capture.failed - error=$capture.error - output=$capture.output - changed=$change - msg=$msg - difference=$diff - fwsettings=$fwsettings - }; - Exit-Json $result; - } - } elseif ($capture.identical -eq $false) { - if ($force -eq $true) { - $capture=removeFirewallRule($fwsettings); - $msg+=$capture.msg; - $change=$true; - if ($capture.failed -eq $true){ - $result=New-Object psobject @{ - failed=$capture.failed - error=$capture.error - changed=$change - msg=$msg - output=$capture.output - fwsettings=$fwsettings - }; - Exit-Json $result; - } - $capture=createFireWallRule($fwsettings); - $msg+=$capture.msg; - $change=$true; - if ($capture.failed -eq $true){ - $result=New-Object psobject @{ - failed=$capture.failed - error=$capture.error - changed=$change - msg=$msg - difference=$diff - fwsettings=$fwsettings - }; - Exit-Json $result; - } +$result.fwsettings.Add("Edge traversal", $(ConvertTo-TitleCase($edge))) + +if ($interfacetypes -ne $null) { + $result.fwsettings.Add("InterfaceTypes", $(ConvertTo-TitleCase($interfacetypes))) +} + +switch($security) { + "Authenticate" { $security = "Authenticate" } + "AuthDynEnc" { $security = "AuthDynEnc" } + "AuthEnc" { $security = "AuthEnc" } + "AuthNoEncap" { $security = "AuthNoEncap" } + "NotRequired" { $security = "NotRequired" } +} +$result.fwsettings.Add("Security", $security) + +# FIXME: Define unsupported options +#$result.fwsettings.Add("Grouping", "") +#$result.fwsettings.Add("Rule source", "Local Setting") + +$get = getFirewallRule($result.fwsettings) +$result.msg += $get.msg + +if ($get.failed) { + $result.error = $get.error + $result.output = $get.output + Fail-Json $result $result.msg +} + +$result.diff = $get.diff - } else { - $fail=$true - $msg+=@("There was already a rule $name with different values, use force=True to overwrite it"); +if ($state -eq "present") { + if (-not $get.exists) { + + $create = createFireWallRule($result.fwsettings) + $result.msg += $create.msg + $result.diff = $create.diff + + if ($create.failed) { + $result.error = $create.error + $result.output = $create.output + Fail-Json $result $result.msg + } + + $result.changed = $true + + } elseif (-not $get.identical) { + # FIXME: This ought to use netsh advfirewall firewall set instead ! + if ($force) { + + $remove = removeFirewallRule($result.fwsettings) + # NOTE: We retain the diff output from $get.diff here + $result.msg += $remove.msg + + if ($remove.failed) { + $result.error = $remove.error + $result.output = $remove.output + Fail-Json $result $result.msg } - } elseif ($capture.identical -eq $true) { - $msg+=@("Firewall rule $name was already created"); - }; - } - "absent" { - if ($capture.exists -eq $true) { - $capture=removeFirewallRule($fwsettings); - $msg+=$capture.msg; - $change=$true; - if ($capture.failed -eq $true){ - $result=New-Object psobject @{ - failed=$capture.failed - error=$capture.error - changed=$change - msg=$msg - output=$capture.output - fwsettings=$fwsettings - }; - Exit-Json $result; + + $create = createFireWallRule($result.fwsettings) + # NOTE: We retain the diff output from $get.diff here + $result.msg += $create.msg + + if ($create.failed) { + $result.error = $create.error + $result.output = $create.output + Fail-Json $result $result.msg } + + $result.changed = $true + } else { - $msg+=@("Firewall rule $name did not exist"); - }; + + $result.msg += @("There was already a rule '$name' with different values, use the 'force' parameter to overwrite it") + Fail-Json $result $result.msg + + } + } else { + + $result.msg += @("Firewall rule '$name' was already created") + } -}; +} elseif ($state -eq "absent") { + + if ($get.exists) { + + $remove = removeFirewallRule($result.fwsettings) + $result.diff = $remove.diff + $result.msg += $remove.msg -$result=New-Object psobject @{ - failed=$fail - changed=$change - msg=$msg - difference=$diff - fwsettings=$fwsettings -}; + if ($remove.failed) { + $result.error = $remove.error + $result.output = $remove.output + Fail-Json $result $result.msg + } + + $result.changed = $true + + } else { + $result.msg += @("Firewall rule '$name' did not exist") + + } +} -Exit-Json $result; +Exit-Json $result diff --git a/lib/ansible/modules/windows/win_firewall_rule.py b/lib/ansible/modules/windows/win_firewall_rule.py index e4ab1e44a7dc44..6035521c384865 100644 --- a/lib/ansible/modules/windows/win_firewall_rule.py +++ b/lib/ansible/modules/windows/win_firewall_rule.py @@ -29,100 +29,98 @@ author: Timothy Vandenbrande short_description: Windows firewall automation description: - - allows you to create/remove/update firewall rules + - Allows you to create/remove/update firewall rules options: - enable: + enabled: description: - - is this firewall rule enabled or disabled - default: true - required: false + - Is this firewall rule enabled or disabled + default: 'yes' + choices: [ 'no', 'yes' ] + aliases: [ 'enable' ] state: description: - - should this rule be added or removed + - Should this rule be added or removed default: "present" - required: true choices: ['present', 'absent'] name: description: - - the rules name - default: null + - The rules name required: true direction: description: - - is this rule for inbound or outbound traffic - default: null + - 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 - default: null + - What to do with the items this rule is for required: true choices: ['allow', 'block', 'bypass'] description: description: - - description for the firewall rule - default: null - required: false + - Description for the firewall rule localip: description: - - the local ip address this rule applies to + - The local ip address this rule applies to default: 'any' - required: false remoteip: description: - - the remote ip address/range this rule applies to + - The remote ip address/range this rule applies to default: 'any' - required: false localport: description: - - the local port this rule applies to - default: 'any' - required: false + - The local port this rule applies to remoteport: description: - - the remote port this rule applies to - default: 'any' - required: false + - The remote port this rule applies to program: description: - - the program this rule applies to - default: null - required: false + - The program this rule applies to service: description: - - the service this rule applies to - default: 'any' - required: false + - The service this rule applies to protocol: description: - - the protocol this rule applies to + - The protocol this rule applies to default: 'any' - required: false - profile: + profiles: description: - - the profile this rule applies to, e.g. Domain,Private,Public - default: 'any' - required: false + - The profile this rule applies to + default: 'domain,private,public' + aliases: [ 'profile' ] force: description: - - Enforces the change if a rule with different values exists - default: false - required: false - - + - 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)). ''' EXAMPLES = r''' -- name: Firewall rule to allow smtp on TCP port 25 - action: win_firewall_rule - args: - name: smtp - enable: yes - state: present - localport: 25 - action: allow - direction: In - protocol: TCP +- name: Firewall rule to allow SMTP on TCP port 25 + win_firewall_rule: + name: SMTP + localport: 25 + action: allow + direction: in + protocol: tcp + state: present + enabled: yes +- name: Firewall rule to allow RDP on TCP port 3389 + win_firewall_rule: + name: Remote Desktop + localport: 3389 + action: allow + direction: in + protocol: tcp + profiles: private + state: present + enabled: yes ''' diff --git a/test/integration/targets/win_firewall_rule/tasks/main.yml b/test/integration/targets/win_firewall_rule/tasks/main.yml index cf0af7580d19a5..b8717507a92527 100644 --- a/test/integration/targets/win_firewall_rule/tasks/main.yml +++ b/test/integration/targets/win_firewall_rule/tasks/main.yml @@ -3,7 +3,7 @@ name: http state: absent action: "{{ item }}" - direction: In + direction: in with_items: - allow - block @@ -11,90 +11,86 @@ - name: Add firewall rule win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp register: add_firewall_rule - name: Check that creating new firewall rule succeeds with a change assert: that: - - add_firewall_rule.failed == false - add_firewall_rule.changed == true - name: Add same firewall rule (again) win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp register: add_firewall_rule_again - name: Check that creating same firewall rule succeeds without a change assert: that: - - add_firewall_rule_again.failed == false - add_firewall_rule_again.changed == false - name: Remove firewall rule win_firewall_rule: name: http - enable: yes + enabled: yes state: absent localport: 80 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp register: remove_firewall_rule - name: Check that removing existing firewall rule succeeds with a change assert: that: - - remove_firewall_rule.failed == false - remove_firewall_rule.changed == true - name: Remove absent firewall rule win_firewall_rule: name: http - enable: yes + enabled: yes state: absent localport: 80 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp register: remove_absent_firewall_rule - name: Check that removing non existing firewall rule succeeds without a change assert: that: - - remove_absent_firewall_rule.failed == false - remove_absent_firewall_rule.changed == false - name: Add firewall rule win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp - name: Add different firewall rule win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 action: block - direction: In - protocol: TCP + direction: in + protocol: tcp ignore_errors: yes register: add_different_firewall_rule_without_force @@ -103,143 +99,136 @@ that: - add_different_firewall_rule_without_force.failed == true - add_different_firewall_rule_without_force.changed == false - - add_different_firewall_rule_without_force.difference == ["block"] - name: Add different firewall rule with force setting win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 action: block - direction: In - protocol: TCP + direction: in + protocol: tcp force: yes register: add_different_firewall_rule_with_force - name: Check that creating different firewall rule with enabling force setting succeeds assert: that: - - add_different_firewall_rule_with_force.failed == false - add_different_firewall_rule_with_force.changed == true - - add_different_firewall_rule_with_force.difference == ["block"] - name: Add firewall rule when remoteip is range win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 remoteip: 192.168.0.1-192.168.0.5 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp force: yes - name: Add same firewall rule when remoteip is range (again) win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 remoteip: 192.168.0.1-192.168.0.5 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp register: add_firewall_rule_with_range_remoteip_again - name: Check that creating same firewall rule when remoteip is range succeeds without a change assert: that: - - add_firewall_rule_with_range_remoteip_again.failed == false - add_firewall_rule_with_range_remoteip_again.changed == false - name: Add firewall rule when remoteip in CIDR notation win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 remoteip: 192.168.0.0/24 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp force: yes - name: Add same firewall rule when remoteip in CIDR notation (again) win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 remoteip: 192.168.0.0/24 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp register: add_firewall_rule_with_cidr_remoteip_again - name: Check that creating same firewall rule succeeds without a change when remoteip in CIDR notation assert: that: - - add_firewall_rule_with_cidr_remoteip_again.failed == false - add_firewall_rule_with_cidr_remoteip_again.changed == false - name: Add firewall rule when remoteip contains a netmask win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 remoteip: 192.168.0.0/255.255.255.0 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp force: yes - name: Add same firewall rule when remoteip contains a netmask (again) win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 remoteip: 192.168.0.0/255.255.255.0 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp register: add_firewall_rule_remoteip_contains_netmask_again - name: Check that creating same firewall rule succeeds without a change when remoteip contains a netmask assert: that: - - add_firewall_rule_remoteip_contains_netmask_again.failed == false - add_firewall_rule_remoteip_contains_netmask_again.changed == false - name: Add firewall rule when remoteip is IPv4 win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 remoteip: 192.168.0.1 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp force: yes - name: Add same firewall rule when remoteip is IPv4 (again) win_firewall_rule: name: http - enable: yes + enabled: yes state: present localport: 80 remoteip: 192.168.0.1 action: allow - direction: In - protocol: TCP + direction: in + protocol: tcp register: add_firewall_rule_with_ipv4_remoteip_again - name: Check that creating same firewall rule when remoteip is IPv4 succeeds without a change assert: that: - - add_firewall_rule_with_ipv4_remoteip_again.failed == false - add_firewall_rule_with_ipv4_remoteip_again.changed == false