需求

昨天在群里 有人提供了一些防火墙的策略文本,询问如何能够在PowerShell里面转换为对象。

文本样例如下所示

rule id 39
  action permit
  src-zone "Any"
  dst-zone "Any"
  src-addr "Any"
  dst-addr "Any"
  service "Any"
exit
rule id 46
  action permit
  src-zone "Any"
  dst-zone "Any"
  src-addr "Any"
  dst-addr "Any"
  service "PING"
exit
rule id 11
  action permit
  src-zone "untrust"
  dst-zone "trust"
  src-addr "nqtwgroup"
  dst-addr "zj-wtqzgroup"
  service "wtqz_group"
  name "zj-nqtw-wtqz"
exit

方案1

因为这个文本看起来很有规律,所以第一个方案是使用 convertfrom-string这个命令,配合自己定义的模板,可以把这些字符串转换为PS对象。

$t=
@'
rule id {ID*:39}
  action {action:permit}
  src-zone {srz_zone:"Any"}
  dst-zone {dst_zone:"Any"}
  src-addr {src_addr:"Any"}
  dst-addr {dst_addr:"Any"}
  service {service_addr:"Any"}
  {name:""}
exit
rule id {ID*:46}
  action permit
  src-zone "Any"
  dst-zone "Any"
  src-addr "Any"
  dst-addr "Any"
  service "PING"

exit
rule id 11
  action permit
  src-zone "untrust"
  dst-zone "trust"
  src-addr "nqtwgroup"
  dst-addr "zj-wtqzgroup"
  service "wtqz_group"
  name "zj-nqtw-wtqz"
exit
'@

ConvertFrom-String -TemplateContent $t -InputObject $st | ft -AutoSize

简单的解释一下这个模板是怎么设计的,把整个文本copy过来,在上面开始修改,比如我所需要的模板的每一行的开始需要用*进行标明,大括号{}里面的键值对,键是自己取的名字,后面的值是文本的原先的内容;PS会自动根据规律来生成对应的对象。
具体的命令解释可以参见 https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertfrom-string?view=powershell-5.1

结果如下所示:


ID action srz_zone  dst_zone src_addr    dst_addr       service_addr
-- ------ --------  -------- --------    --------       ------------
39 permit "Any"     "Any"    "Any"       "Any"          "Any"       
46 permit "Any"     "Any"    "Any"       "Any"          "PING"      
11 permit "untrust" "trust"  "nqtwgroup" "zj-wtqzgroup" "wtqz_group"

咋一看好像需要的结果都有了,不过仔细观察 发现文本每一块策略的内容略微有些不太一样,比如说有些rule还多了个name的属性,这样的话如果不统一,一个单一的模板就对不上所以的内容了。

方案2

传统的正则+字符串拼接处理

 #原始文本
 $st=@"
rule id 39
  action permit
  src-zone "Any"
  dst-zone "Any"
  src-addr "Any"
  dst-addr "Any"
  service "Any"
exit
rule id 46
  action permit
  src-zone "Any"
  dst-zone "Any"
  src-addr "Any"
  dst-addr "Any"
  service "PING"
exit
rule id 11
  action permit
  src-zone "untrust"
  dst-zone "trust"
  src-addr "nqtwgroup"
  dst-addr "zj-wtqzgroup"
  service "wtqz_group"
  name "zj-nqtw-wtqz"
exit
"@

$r=@()

#正则进行多行匹配,获取每一个rule的块
$st | Select-String '(?smi)rule id [1-9]{2}.*?exit' -AllMatches | Foreach {$_.Matches} | 
Foreach {

  #替代一下空格和换行符,这样更规整,方便处理
  $temp=$_.value -replace 'rule id','rule-id'
  $temp=$temp -replace 'exit', ''
  $temp=$temp -replace '\r\n',','
  $list=$temp.split(',')

  $object = New-Object –TypeName PSObject
  try{
 foreach($item in $list){
    $c=$item.trim().split()
    $name=$c[0]
    $value=$c[1]

    $object | Add-Member -NotePropertyName $name -NotePropertyValue $value -ErrorAction SilentlyContinue

  }}catch{}
  $r+=$object

}

$r | select rule-id,action,src-zone,dst-zone,src-addr,dst-addr,service,name | ft

最后结果如下所示,成功获取了所以的信息

rule-id action src-zone  dst-zone src-addr    dst-addr       service      name          
------- ------ --------  -------- --------    --------       -------      ----          
39      permit "Any"     "Any"    "Any"       "Any"          "Any"                      
46      permit "Any"     "Any"    "Any"       "Any"          "PING"                     
11      permit "untrust" "trust"  "nqtwgroup" "zj-wtqzgroup" "wtqz_group" "zj-nqtw-wtqz"