Как я могу ускорить powershell, чтобы получить правила брандмауэра для Windows 10? - PullRequest
0 голосов
/ 05 ноября 2018

Мне нужно перечислить все правила брандмауэра в Windows 10, используя PowerShell. Я переключился на PowerShell с netsh, потому что некоторые встроенные правила получали смешные имена, такие как @{microsoft.windows.shellexperiencehost_10.0.17134.1_neutral_neutral_cw5n1h2txyewy?ms-resource://microsoft.windows.shellexperiencehost/resources/pkgdisplayname}, которыми я не смог управлять с помощью netsh. Переключение на PowerShell показывает, что настоящее имя было UID и устранило мою проблему, но код действительно медленно запускается:

PS C:\Users\vagrant\Desktop> Measure-Command {.\ps-slow.ps1 show}
Seconds           : 48
...

В отличие от Measure-Command {show-netfirewallrule}:

...
Milliseconds      : 644

А netsh:

PS C:\Users\vagrant\Desktop> Measure-Command { netsh advfirewall firewall show rule all verbose}
...
TotalSeconds      : 1.0588127

Комментируя часть скрипта Get-NetFirewall*Filter, он запускается на полной скорости, но, конечно, не хватает всех данных, которые я хочу. Идея состоит в том, чтобы собрать подробную информацию обо всех правилах брандмауэра и затем вывести лот в формате JSON.

У кого-нибудь есть идеи, как это оптимизировать? Я нуб PowerShell, поэтому я надеюсь, что пропустил что-то очевидное. Полный сценарий:

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

Ответы [ 3 ]

0 голосов
/ 06 ноября 2018

Дает ли Get-NetFirewallRule то, что вы хотите?

$MyRules = Get-NetFirewallRule
foreach ($rule in $MyRules) {
    [the rest of your code]
}
0 голосов
/ 06 ноября 2018

Хорошо, спасибо, куча всем, кто написал Первоначальная проблема заключалась в том, что netsh оставляет нерешенные имена, такие как:

@{Microsoft.Todos_1.41.12842.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Todos/Resources/app_name_ms_todo}
@{Microsoft.Todos_1.41.12842.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Todos/Resources/app_name_ms_todo}

В своем выводе, который может быть разрешен только PowerShell, используя оригинальный скрипт. Проблема с этим подходом состоит в том, что это очень медленно (минуты).

Предложения по этой теме и от коллег были:

  • Использовать пакетную обработку PS (что замедлило работу, предполагая узкое место в WMI)
  • Чтение реестра напрямую (в основном работает, но данные остаются неразрешенными по-разному, и для разрешения потребуется медленное сканирование реестра - например, @FirewallAPI.dll,-25427 для любого ресурса, на который ссылается)
  • Использование COM API New-Object -ComObject HNetCfg.FwPolicy (имеет те же проблемы с выводом, что и netsh)
  • Настройка использования конвейеров / создание объектов (без измеримых воздействий)

Таким образом, оптимизация, которую я хочу, невозможна без ущерба для данных, которые я хочу. Я собираюсь попытаться использовать более быстрый COM API / netsh в большинстве случаев , но переключиться на использование PowerShell API, когда нет выбора (когда нерешенные имена вынуждают нас)

0 голосов
/ 05 ноября 2018

Этот подход быстрее, так что, может быть, другой подход для вас, чтобы получить ту же информацию.

param
( 
    [switch]$Local, 
    [switch]$GPO 
) 

# If no switches are set the script will default to local firewall rules 
if (!($Local) -and !($Gpo)) 
{ $Local = $true } 

$RegistryKeys = @() 

if ($Local) {$RegistryKeys += 'Registry::HKLM\System\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\FirewallRules'} 
if ($GPO) {$RegistryKeys += 'Registry::HKLM\Software\Policies\Microsoft\WindowsFirewall\FirewallRules'} 

Foreach ($Key in $RegistryKeys) 
{ 
    if (Test-Path -Path $Key) 
    { 
        (Get-ItemProperty -Path $Key).PSObject.Members | 
        Where-Object {
        (@('PSPath','PSParentPath','PSChildName') -notcontains $_.Name) -and 
        ($_.MemberType -eq 'NoteProperty') -and 
        ($_.TypeNameOfValue -eq 'System.String')} | 
         ForEach-Object { 

            # Prepare hashtable 
            $HashProps = @{ 
                NameOfRule = $_.Name 
                RuleVersion = ($_.Value -split '\|')[0] 
                Action = $null 
                Active = $null 
                Dir = $null 
                Protocol = $null 
                LPort = $null 
                App = $null 
                Name = $null 
                Desc = $null 
                EmbedCtxt = $null 
                Profile = $null 
                RA4 = $null 
                RA6 = $null 
                Svc = $null 
                RPort = $null 
                ICMP6 = $null 
                Edge = $null 
                LA4 = $null 
                LA6 = $null 
                ICMP4 = $null 
                LPort2_10 = $null 
                RPort2_10 = $null 
            } 

            # Determine if this is a local or a group policy rule and display this in the hashtable 
            if ($Key -match 'HKLM\\System\\CurrentControlSet') 
            {  $HashProps.RuleType = 'Local' } 
            else 
            {  $HashProps.RuleType = 'GPO' } 

            # Iterate through the value of the registry key and fill PSObject with the relevant data 
            ForEach ($FireWallRule in ($_.Value -split '\|')) 
            { 
                switch (($FireWallRule -split '=')[0]) 
                { 
                    'Action' {$HashProps.Action = ($FireWallRule -split '=')[1]} 
                    'Active' {$HashProps.Active = ($FireWallRule -split '=')[1]} 
                    'Dir' {$HashProps.Dir = ($FireWallRule -split '=')[1]} 
                    'Protocol' {$HashProps.Protocol = ($FireWallRule -split '=')[1]} 
                    'LPort' {$HashProps.LPort = ($FireWallRule -split '=')[1]} 
                    'App' {$HashProps.App = ($FireWallRule -split '=')[1]} 
                    'Name' {$HashProps.Name = ($FireWallRule -split '=')[1]} 
                    'Desc' {$HashProps.Desc = ($FireWallRule -split '=')[1]} 
                    'EmbedCtxt' {$HashProps.EmbedCtxt = ($FireWallRule -split '=')[1]} 
                    'Profile' {$HashProps.Profile = ($FireWallRule -split '=')[1]} 
                    'RA4' {[array]$HashProps.RA4 += ($FireWallRule -split '=')[1]} 
                    'RA6' {[array]$HashProps.RA6 += ($FireWallRule -split '=')[1]} 
                    'Svc' {$HashProps.Svc = ($FireWallRule -split '=')[1]} 
                    'RPort' {$HashProps.RPort = ($FireWallRule -split '=')[1]} 
                    'ICMP6' {$HashProps.ICMP6 = ($FireWallRule -split '=')[1]} 
                    'Edge' {$HashProps.Edge = ($FireWallRule -split '=')[1]} 
                    'LA4' {[array]$HashProps.LA4 += ($FireWallRule -split '=')[1]} 
                    'LA6' {[array]$HashProps.LA6 += ($FireWallRule -split '=')[1]} 
                    'ICMP4' {$HashProps.ICMP4 = ($FireWallRule -split '=')[1]} 
                    'LPort2_10' {$HashProps.LPort2_10 = ($FireWallRule -split '=')[1]} 
                    'RPort2_10' {$HashProps.RPort2_10 = ($FireWallRule -split '=')[1]} 
                    Default {} 
                } 
            } 

            # Create and output object using the properties defined in the hashtable 
            New-Object -TypeName 'PSCustomObject' -Property $HashProps
        } 
    } 
}

# Partial results

Action      : Allow
LPort2_10   : 
RuleType    : Local
LPort       : 135
Edge        : 
LA6         : 
Dir         : In
Desc        : @icsvc.dll,-710
ICMP4       : 
RA4         : 
Name        : @icsvc.dll,-709
LA4         : 
App         : %SystemRoot%\system32\svchost.exe
ICMP6       : 
Protocol    : 6
RuleVersion : v2.0
NameOfRule  : vm-monitoring-dcom
RPort       : 
Svc         : RpcSs
RA6         : 
Profile     : 
EmbedCtxt   : @icsvc.dll,-700
RPort2_10   : 
Active      : FALSE
...