@mta77 (mta77)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Select-Objectで取得した項目をSort-Objectでソート+重複排除したい

Q&A

Closed

解決したいこと

以前"Get-NetTCPConnectionIPアドレス監視"にてご教授頂きCLOSEと致しましたが、再度質問させて頂きたく
投稿致しました。

目的:Select-Objectした項目でソート+重複排除を行いたい

対応した構文 Sort-Objectで指定した出力結果が得られない

# ファイル出力に日付を代入
$filename = Get-Date -Format "yyyy-MMdd"

# 実行:許可リストにあるものをCSV出力
Get-NetTCPConnection -State Established,Listen |
  Sort-Object  -Property  LocalAddress,RemoteAddress -unique  |
  SelectAllowConnection |     
  Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort |
  Export-Csv -Append -path "whitelist_$filename.csv" -Encoding Default

# 実行:許可リストにないものをCSV出力
Get-NetTCPConnection -State Established,Listen |  
  Sort-Object  -Property  LocalAddress,RemoteAddress -unique  |
  SelectDenyConnection |
  Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort |
  Export-Csv -Append -path "Nowhitelist_$filename.csv" -Encoding Default

該当するソースコード

Sort-Object  -Property  LocalAddress,RemoteAddress -unique  |

自分で試したこと

"Select-Object"の後CSV出力をコメントアウトし
Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort | ft >>test.txt
で対応した場合は、希望した出力結果となります。

Sort-Objectは、フィルターの定義である"SelectAllowConnection"、"SelectDenyConnection"の前
に配置しましたが、構文がおかしいのかわからなくなりご教授いただければ幸いです。

0 likes

2Answer

Export-Csvの代わりに、ConvertTo-Csvcsvフォーマットにして、ファイル出力したらいいんじゃないの?

Get-NetTCPConnection -State Established,Listen |
Sort-Object  -Property  LocalAddress,RemoteAddress -unique  |
SelectAllowConnection |     
Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort |
ConvertTo-Csv -NoTypeInformation |
Out-File -Append -Encoding Default -Path "Nowhitelist_$filename.csv"

最後のOut-Fileは、Powershell Core使ってて、utf-8で構わないのであれば、リダイレクト(>>)でも代用可

1Like

Comments

  1. @mta77

    Questioner

    ご回答大変ありがとうございます。
    頂いた内容で処理できました。

    再度の質問で申し訳ございませんが、

    本件の目的としてNWログを一定時間取りたいためforeachオブジェクトの処理結果を
    質問したソートしてCSV出力しているのですが、
    1回の処理結果に対して
    sort-objectで重複排除
    次の処置結果
    sort-objectで重複排除



    となり、全体でのsort処理が行えない状態です。

    処理結果に対して一度tmpファイルに出力してその後、sort-object
    対応しCSV出力出来ればと思っているのですが、よい方法あればご教授頂ければ幸いです。

やりたいことがよく分かりませんが、

  • 許可リストにあるものを軸に重複排除した結果
  • 許可リストにないものを軸に重複排除した結果

この2つの結果をマージし、ソートしてcsv出力したいということであれば、
単純に、Cmdlet関数作ればいいだけですよ?

# 関数名はテケトー
function GetMergeResult {
  # 許可リストにあるもの
  Get-NetTCPConnection -State Established,Listen |
  Sort-Object  -Property  LocalAddress,RemoteAddress -unique  |
  SelectAllowConnection |     
  Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort 

  # 許可リストにないもの
  Get-NetTCPConnection -State Established,Listen |  
  Sort-Object  -Property  LocalAddress,RemoteAddress -unique  |
  SelectDenyConnection |
  Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort  
}

GetMergeResult | # マージした結果とりだしーの
Sort-Object -Property ... | # 好きな条件でソートしーの
ConvertTo-Csv -NoTypeInformation | # 一旦csvフォーマットに変更しーの
Out-File -Append -Encoding Default -Path "Nowhitelist_$filename.csv" # ファイルに吐き出しーの
1Like

Comments

  1. Powershellにおける値は、変数に代入しない場合、呼びだし元に送られるしようとなっています(その呼びだし元で変数に代入されていなければもう一つ上の先祖に)

    イメージとしては、C#のyield returnが相当しますが、もっと賢くて、コレクションについては自動的に1要素ずつ取り出して、yield retunしてくれます(チョーベンリ)

    なので、「GetMergeResult | Sort-Object」としても問題ないというわけ。
  2. @mta77

    Questioner

    ご回答ありがとうございます。
    Get-NetTCPConnectionでTCPに接続しているIPアドレスをjson化した
    ホワイトリストで検索し、リストにあるもの、それ以外をCSV出力
    したい目的があります。

    その為、マージではなく別々にCSV出力したい目的があります。

    そもそものコードとしては以下となります。


    -----------------------------
    # JSON を読み込み
    $json = ConvertFrom-Json -InputObject (Get-Content .\allowList.json -Raw)

    # 許可リストの作成
    $allowList = @()
    foreach($item in $json)
    {
    $allowItem = New-Object allowItem
    $allowItem.LocalAddress = New-Object Ip4Address($item.LocalAddress)
    $allowItem.LocalPorts = $item.LocalPorts
    $allowItem.RemoteAddress = New-Object Ip4Address($item.RemoteAddress)
    $allowItem.RemotePorts = $item.RemotePorts
    $allowList += $allowItem
    }

    # ホワイトリストと比較 1分間のみ実行
    $timeout = new-timespan -Minutes 1
    $sw = [diagnostics.stopwatch]::StartNew()
    while ($sw.elapsed -lt $timeout){


    Function IsAllowed([CimInstance] $connection)
    {
    if ($connection.LocalAddress.Contains(":"))
    {
    # IPv6 は不許可扱い
    return $FLASE
    }
    foreach($allowItem in $allowList)
    {
    $local = New-Object Ip4Address($connection.LocalAddress)
    $remote = New-Object Ip4Address($connection.RemoteAddress)

    if ($allowItem.LocalAddress.Contains($local) -and
    # ポート番号が1つもない時にはどれでもOK
    ( $allowItem.LocalPorts.Contains([int]$connection.LocalPort) -or $allowItem.LocalPorts.Length -eq 0 ) -and
    $allowItem.RemoteAddress.Contains($remote) -and
    # ポート番号が1つもない時にはどれでもOK
    ( $allowItem.RemotePorts.Contains([int]$connection.RemotePort) -or $allowItem.RemotePorts.Length -eq 0 ) )
    {
    return $TRUE
    }
    }
    return $FALSE
    }



    # フィルターの定義
    filter SelectAllowConnection()
    {
    if (IsAllowed($_))
    {
    return $_
    }
    }

    filter SelectDenyConnection()
    {
    if (!(IsAllowed($_)))
    {
    return $_
    }
    }

    # ファイル出力に日付を代入
    $filename = Get-Date -Format "yyyy-MMdd"

    # 実行:許可リストにあるものをCSV出力
    Get-NetTCPConnection -State Established,Listen |
    SelectAllowConnection |
    Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort |
    Export-Csv -Append -path "whitelist_$filename.csv" -Encoding Default

    # 実行:許可リストにないものをCSV出力
    Get-NetTCPConnection -State Established,Listen |
    SelectDenyConnection |
    Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort |
    Export-Csv -Append -path "Nowhitelist_$filename.csv" -Encoding Default
    }
    # IPv4のアドレスクラスの定義
    class Ip4Address
    {
    [int64] $Address
    [int64] $Mask
    [int] $Width

    # 渡せるアドレスは "192.168.140.0/24"、あるいは "192.168.140.10" など
    Ip4Address([String] $addressCidr){
    if($addressCidr -eq "")
    {
    $this.Address = 0
    $this.Mask = 0
    $this.Width = 0
    return
    }

    $temp = $addressCidr -split "/"
    $ip = $temp[0] -split "\."
    $this.Width = 32
    if(2 -eq $temp.Length)
    {
    $this.Width = [int]$temp[1]
    }
    $this.Mask = 0
    if($this.Width -ne 0)
    {
    $this.Mask = 0xffffffffL -bxor ( [Math]::Pow(2,32 - $this.Width) - 1 )
    }
    $this.Address = 0
    foreach($octet in $ip)
    {
    $this.Address = $this.Address * 256 + [int]$octet
    }
    $this.Address = $this.Address -band $this.Mask
    }

    [bool]Contains([Ip4Address] $other){
    return $this.Width -le $other.Width -and ( $other.Address -band $this.Mask ) -eq $this.Address
    }
    }

    # 許可リスト用の項目クラス
    class allowItem
    {
    [Ip4Address] $LocalAddress
    [int[]] $LocalPorts
    [Ip4Address] $RemoteAddress
    [int[]] $RemotePorts
    }
    -----------------------------


  3. > 全体でのsort処理が行えない状態です。

    というのが、やはり理解不能ですが、Cmdlet関数を自作してやれば、なんやかんややれると思います。

    Powershellは、バッチファイルとは異なり、すべてオンメモリ上で処理を解決できるということも覚えておくとよいでしょう。
  4. @mta77

    Questioner

    Cmdlet関数で可能とのご意見をいただきましたが、
    例えばfunction {}からGetMergeResult | を各CSV出力に付与して実行すれば
    許可した結果
    許可しない結果

    事にsortした結果が得られるのでしょうか。



     



Your answer might help someone💌