簡體   English   中英

如何在 Windows 10 上加速 powershell 以獲取防火牆規則?

[英]How can I speed up powershell to get firewall rules on windows 10?

我需要使用 PowerShell 枚舉 Windows 10 上的所有防火牆規則。 我從netsh切換到 PowerShell,因為一些內置規則的名稱很有趣,例如@{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

好的,感謝所有發帖的人。 最初的問題是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(當未解析的名稱迫使我們這樣做時)

這種方法更快,因此,您可能會采用不同的方法來獲取相同的信息。

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

Get-NetFirewallRule滿足您的需求嗎?

$MyRules = Get-NetFirewallRule
foreach ($rule in $MyRules) {
    [the rest of your code]
}

我不認為這很好理解,但 get-netfirewall*filter 命令旨在更快地完成任務。 只需將第一個管道與第二個管道進行比較。 這就像在 get-childitem 或 get-wmiobject 等其他命令中使用 -filter 選項一樣。 我認為即使是在線幫助的作者也無法理解這一點。 就像 powershell 只有 80% 的文檔。

Get-NetFirewallRule | 
Get-NetFirewallPortFilter | 
Where LocalPort -eq 3389 | Get-NetFirewallRule | 
Set-NetFirewallRule -RemoteAddress 192.168.1.1 -WhatIf
Get-NetFirewallPortFilter | 
Where LocalPort -eq 3389 | Get-NetFirewallRule | 
Set-NetFirewallRule -RemoteAddress 192.168.1.1 -WhatIf

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM