title: How can I speed up powershell to get firewall rules on windows 10?
body: <p>I need to enumerate all firewall rules on windows 10 using PowerShell. I switched to PowerShell from <code>netsh</code> because some built-in rules were getting <em>funny</em> names like <code>@{microsoft.windows.shellexperiencehost_10.0.17134.1_neutral_neutral_cw5n1h2txyewy?ms-resource://microsoft.windows.shellexperiencehost/resources/pkgdisplayname}</code> which I was unable to manage with <code>netsh</code>. Switching to PowerShell shows that the real name was a UID and fixed my problem but the code is <em>really</em> slow to run:</p>
  
  <pre><code>PS C:\Users\vagrant\Desktop&gt; Measure-Command {.\ps-slow.ps1 show}
  Seconds           : 48
  ...
  </code></pre>
  
  <p>In contrast to <code>Measure-Command {show-netfirewallrule}</code>:</p>
  
  <pre><code>...
  Milliseconds      : 644
  </code></pre>
  
  <p>And <code>netsh</code>:</p>
  
  <pre><code>PS C:\Users\vagrant\Desktop&gt; Measure-Command { netsh advfirewall firewall show rule all verbose}
  ...
  TotalSeconds      : 1.0588127
  </code></pre>
  
  <p>By commenting out the <code>Get-NetFirewall*Filter</code> part of the script it runs at full speed but of course is missing all the data I want. The idea is to collect detailed info on all firewall rules and then output the lot as JSON.</p>
  
  <p>Does anyone have an idea how to optimize this? I'm a PowerShell noob so I'm hoping I missed something obvious. The complete script is:</p>
  
  <pre><code>Show-NetFirewallRule | `
      Where-Object { $_.cimclass.toString() -eq "root/standardcimv2:MSFT_NetFirewallRule" } | `
          ForEach-Object { `
              $af = $_ | Get-NetFirewallAddressFilter | Select-Object -First 1; # Assumes only one filter
              $appf = $_ | Get-NetFirewallApplicationFilter | Select-Object -First 1; # Assumes only one filter
              $pf = $_ | Get-NetFirewallPortFilter | Select-Object -First 1; # Assumes only one filter
              $if = $_ | Get-NetFirewallInterfaceTypeFilter | Select-Object -First 1; # Assumes only one filter
  
              New-Object -Type PSCustomObject -Property @{
                Name = $_.Name
                DisplayName = $_.DisplayName
                Description = $_.Description
                Enabled = $_.Enabled.toString()
                Action = $_.Action.toString()
                Direction = $_.Direction.toString()
                EdgeTraversalPolicy = $_.EdgeTraversalPolicy.toString()
                Profile = $_.Profile.toString()
                DisplayGroup = $_.DisplayGroup
                # Address Filter
                LocalAddress = $af.LocalAddress
                RemoteAddress = $af.RemoteAddress
                LocalIp = $af.LocalIp
                RemoteIp = $af.RemoteIp
                # Port Filter
                LocalPort = $pf.LocalPort
                RemotePort = $pf.RemotePort
                Protocol = $pf.Protocol
                IcmpType = $pf.IcmpType
                # Application Filter
                Program = $appf.Program
                # Interface Filter
                InterfaceType = $if.InterfaceType.toString()
              }
          } | Convertto-json
  </code></pre>