class Inspec::Resources::WindowsFirewallRule

def access_property(property)

def access_property(property)
  @state[property]
end

def allowed?

def allowed?
  @state["action"] == "Allow"
end

def enabled?

def enabled?
  @state["enabled"]
end

def exist?

def exist?
  !@state.empty?
end

def icmp?

def icmp?
  @state["protocol"].start_with? "ICMP"
end

def icmpv4?

def icmpv4?
  @state["protocol"] == "ICMPv4"
end

def icmpv6?

def icmpv6?
  @state["protocol"] == "ICMPv6"
end

def inbound?

def inbound?
  @state["direction"] == "Inbound"
end

def initialize(name)

def initialize(name)
  @name = name
  @state = {}
  query = load_firewall_state(name)
  cmd = inspec.powershell(query)
  @state = JSON.load(cmd.stdout) unless cmd.stdout.empty?
end

def load_firewall_state(rule_name)

Other tags:
    See: https://github.com/chef/chef/blob/master/lib/chef/resource/windows_firewall_rule.rb -
def load_firewall_state(rule_name)
  <<-EOH
    Get-TypeData -TypeName System.Array | Remove-TypeData # workaround for PS bug here: https://bit.ly/2SRMQ8M
    $rule = Get-NetFirewallRule -Name "#{rule_name}"
    $addressFilter = $rule | Get-NetFirewallAddressFilter
    $portFilter = $rule | Get-NetFirewallPortFilter
    $applicationFilter = $rule | Get-NetFirewallApplicationFilter
    $serviceFilter = $rule | Get-NetFirewallServiceFilter
    $interfaceTypeFilter = $rule | Get-NetFirewallInterfaceTypeFilter
    ([PSCustomObject]@{
      rule_name = $rule.Name
      description = $rule.Description
      displayname = $rule.DisplayName
      group = $rule.Group
      local_address = $addressFilter.LocalAddress
      local_port = $portFilter.LocalPort
      remote_address = $addressFilter.RemoteAddress
      remote_port = $portFilter.RemotePort
      direction = $rule.Direction.ToString()
      protocol = $portFilter.Protocol
      icmp_type = $portFilter.IcmpType
      action = $rule.Action.ToString()
      profile = $rule.Profile.ToString()
      program = $applicationFilter.Program
      service = $serviceFilter.Service
      interface_type = $interfaceTypeFilter.InterfaceType.ToString()
      enabled = [bool]::Parse($rule.Enabled.ToString())
    }) | ConvertTo-Json
  EOH
end

def method_missing(method_name, *arguments, &_block)

Access to return values from Powershell via `its("PROPERTY")` and `have_PROPERTY? "VALUE"`
def method_missing(method_name, *arguments, &_block)
  property = normalize_for_have_access(method_name)
  if method_name.to_s.start_with? "has_"
    expected_value = arguments.first
    respond_to_have(property, expected_value)
  else
    access_property(property)
  end
end

def normalize_for_have_access(property)

def normalize_for_have_access(property)
  property.to_s
    .delete_prefix("has_")
    .delete_suffix("?")
end

def outbound?

def outbound?
  ! inbound?
end

def resource_id

def resource_id
  @name || "windows_firewall_rule"
end

def respond_to_have(property, value)

def respond_to_have(property, value)
  @state[property] == value
end

def respond_to_missing?(method_name, _include_private = false)

def respond_to_missing?(method_name, _include_private = false)
  property = normalize_for_have_access(method_name)
  @state.key? property
end

def tcp?

def tcp?
  @state["protocol"] == "TCP"
end

def to_s

def to_s
  "Windows Firewall Rule #{@name}"
end

def udp?

def udp?
  @state["protocol"] == "UDP"
end