You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PowerShell自定义对象中替换指定字段值及脚本问题排查

Windows安全事件ID 5152字段替换问题

基础代码及输出

以下是获取安全事件ID 5152的基础代码:

foreach ($event in Get-WinEvent -FilterHashtable @{LogName='Security';ID=5152}) {
    $xml = [xml]$event.toxml();
    $xml.event.eventdata.data | 
    foreach { $hash = @{} } { $hash[$_.name] = $_.'#text' } { [pscustomobject]$hash } |
    Where FilterOrigin -notmatch 'stealth|unknown|Query User Default' 
}

输出截图:
输出截图

需求

需要对以下字段进行替换:

  • 将FilterOrigin替换为防火墙显示名
  • 将Direction替换为「入站」或「出站」(%%14592对应入站,%%14593对应出站)
  • 将Protocol替换为对应名称(如6对应TCP,17对应UDP)

只需掌握一两个字段的替换方法,即可自行完成其余字段处理。

初次尝试及问题

尝试替换FilterOrigin的代码如下:

foreach ($event in Get-WinEvent -FilterHashtable @{LogName='Security';ID=5152}) {
    $xml = [xml]$event.toxml();
    $xml.event.eventdata.data | 
    foreach { $hash = @{} } { $hash[$_.name] = $_.'#text' } { [pscustomobject]$hash } |
    Where FilterOrigin -notmatch 'stealth|unknown|Query User Default' | ForEach-Object {

    if ($_.filterorigin -match ($pattern = '{.+?}'))

    {
    $_.filterorigin -replace $pattern, (Get-NetFirewallRule -Name $Matches[0]).DisplayName

    }

    }
}

问题:输出仅显示防火墙displaynames,说明脚本能识别FilterOrigin中的防火墙ID,但未在对象内完成替换。

更新后的脚本及问题

更新后的脚本:

foreach ($event in Get-WinEvent -FilterHashtable @{LogName='Security';ID=5152}) {
    $xml = [xml]$event.toxml();
    $xml.event.eventdata.data | 
    foreach { $hash = @{} } { $hash[$_.name] = $_.'#text' } { [pscustomobject]$hash } |
    Where FilterOrigin -notmatch 'Stealth|Unknown|Query User Default|WSH Default' | ForEach-Object {

        $pattern = '\{.+?\}'
        $_.FilterOrigin =  $_.FilterOrigin -replace $pattern, (Get-NetFirewallRule -Name $Matches[0]).DisplayName


        $protocolName = @{ 6 = 'TCP'; 17 = 'UDP' }[$_.Protocol]
        $_.Protocol =  if (-not $protocolName) { $_.Protocol } else { $protocolName }



        # Conceptually clearer PowerShell (Core) 7+ alternative:
        $_.Direction = $_.Direction -eq '%%14592' ? 'Outbound' : 'Inbound'
        # $_.Direction = ('Outbound', 'Inbound')[$_.Direction -eq '%%14592']


        $_



    }
}

存在的问题:

  1. Protocol未被替换,仍显示数字
  2. FilterOrigin显示为空
  3. 每次输出结果后都会出现错误

问题截图:
问题截图

截图中仅Direction被正确替换,脚本中显示的阻止连接的过滤器应有名称,但未正常显示。


解决方案

问题分析及修复步骤

1. FilterOrigin为空的问题

原代码未先执行匹配获取$Matches,且传递给Get-NetFirewallRule的名称带大括号,导致无法找到对应规则。修复代码:

$pattern = '\{.+?\}'
if ($_.FilterOrigin -match $pattern) {
    # 去掉规则名称的大括号
    $ruleName = $Matches[0].Trim('{}')
    # 静默忽略找不到规则的错误
    $firewallRule = Get-NetFirewallRule -Name $ruleName -ErrorAction SilentlyContinue
    if ($firewallRule) {
        $_.FilterOrigin = $firewallRule.DisplayName
    }
}

2. Protocol未替换的问题

$_.Protocol是字符串类型,哈希表的键是数字,类型不匹配导致匹配失败。修复代码:

$protocolMap = @{ 6 = 'TCP'; 17 = 'UDP' }
# 先判断是否为纯数字,再转为整数
if ($_.Protocol -match '^\d+$') {
    $protocolNum = [int]$_.Protocol
    $_.Protocol = $protocolMap.ContainsKey($protocolNum) ? $protocolMap[$protocolNum] : $_.Protocol
}

3. Direction替换的兼容性问题

Windows PowerShell 5.x不支持三元运算符,改用if-else实现,同时替换为中文表述:

if ($_.Direction -eq '%%14592') {
    $_.Direction = '入站'
} else {
    $_.Direction = '出站'
}

完整修复后的脚本

# 提前缓存防火墙规则,提升大数量事件处理效率
$firewallRules = @{}
Get-NetFirewallRule | ForEach-Object { $firewallRules[$_.Name] = $_.DisplayName }

foreach ($event in Get-WinEvent -FilterHashtable @{LogName='Security';ID=5152}) {
    $xml = [xml]$event.toxml()
    $xml.event.eventdata.data | 
        ForEach-Object -Begin { $hash = @{} } -Process { $hash[$_.name] = $_.'#text' } -End { [pscustomobject]$hash } |
        Where-Object FilterOrigin -notmatch 'Stealth|Unknown|Query User Default|WSH Default' | 
        ForEach-Object {
            # 替换FilterOrigin
            $pattern = '\{.+?\}'
            if ($_.FilterOrigin -match $pattern) {
                $ruleName = $Matches[0].Trim('{}')
                if ($firewallRules.ContainsKey($ruleName)) {
                    $_.FilterOrigin = $firewallRules[$ruleName]
                }
            }

            # 替换Protocol
            $protocolMap = @{ 6 = 'TCP'; 17 = 'UDP' }
            if ($_.Protocol -match '^\d+$') {
                $protocolNum = [int]$_.Protocol
                $_.Protocol = $protocolMap.ContainsKey($protocolNum) ? $protocolMap[$protocolNum] : $_.Protocol
            }

            # 替换Direction
            if ($_.Direction -eq '%%14592') {
                $_.Direction = '入站'
            } else {
                $_.Direction = '出站'
            }

            # 输出处理后的对象
            $_
        }
}

内容的提问来源于stack exchange,提问作者user20682592

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 19:50:33