Home > Windows にまつわる e.t.c.

オブジェクトをユニークにして存在数を付加する PowerShell フィルター


PowerShell でオブジェクトをユニークにするには Sort-Objec コマンドレットの -Unique オプションを使うか、ソート後のオブジェクトを Get-Unique コマンドレットするのが常套手段です。

でも、この方法では存在数がいくつあったのかわからないので、ユニークにして存在数をカウントするフィルタを書きました。

関数(function)は、1データを受け取る処理なのに対し、フィルタ(filter)はパイプラインでデーターを受け取ります。
(厳密に言うと、function もパイプライン処理できるのですが、混乱するので僕は function でパイプライン処理を書かないようにしています)

filter の場合、受け取ったオブジェクトは foreach と同様に $_ に分解されるので、分解するためのループを書く必要はありません。

更に、BEGIN、PROCESS、END で処理の流れを制御することができるので、初期処理/終了処理を簡潔に記述することができます。

BEGIN 最初の一度だけ実行される処理(データが読み込まれる前)
PROCESS 通常処理
END 最後の一度だけ実行される処理(PROCESSの後)

 

フローチャートにするとこんな感じの流れになります

 

さて、本題のフィルターです。
アルゴリズムは、昔ながらキーブレークですね。

##################################################
# 指定プロパティでソートされたオブジェクトを
# ユニークにして存在数(Count)を付加する
##################################################
filter Count-Unique($Property){
    BEGIN{
        ### 最初の一度だけ実行される処理
        ## (データ読み込み前に実行されるので初期値設定のみ)

        # 初期値設定
        $InitFlag = $true
        $Count = 0
    }

    PROCESS{
        ### 通常処理

        # 初期処理
        if( $InitFlag -eq $true ){
            $NewKey = $_.$Property
            $NewRec = $_
            $InitFlag = $false
        }

        # 比較キーとデータセット
        $OldKey = $NewKey
        $OldRec = $NewRec

        $NewKey = $_.$Property
        $NewRec = $_

        # キーブレイク確認
        if( $OldKey -eq $NewKey ){
            # 同一キーなのでカウントアップ
            $Count++
        }
        else{
            # キーブレイクしたのでカウンターを付加してデーター出力
            Add-Member -InputObject $OldRec -MemberType NoteProperty -Name Count -Value $Count -Force
            $Count = 1
            return $OldRec
        }
    }

    END{
        ### 最後に一度だけ実行される処理
        ## (PROCESS の後に実行される)

        # 残ったデーターを出力
        Add-Member -InputObject $NewRec -MemberType NoteProperty -Name Count -Value $Count -Force
        return $NewRec
    }
}

 

実行するとこんな感じになります。

PS C:\> Get-Process | sort -Property ProcessName | Count-Unique -Property ProcessName | ft ProcessName,Count -AutoSize

ProcessName                   Count
-----------                   -----
ApplicationFrameHost              1
AppVShNotify                      2
atkexComSvc                       1
BtwRSupportService                1
chrome                           25
CompanionApp                      1
conhost                           2
csrss                             2
dllhost                           1
dwm                               1
EIZO EasyPIX                      1

 

通常のオブジェクトだけではなく、syslog とかのログ集計にも便利です。
(syslog からアタック解析するために書いたフィルタを汎用化しました)

 

 

とここまで書いて Group-Object で同様の事が出来ることに気が付きました w

Get-Process | sort -Property ProcessName | Group-Object -Property ProcessName | ft Name,Count -AutoSize

 

折角書いたので、同様処理のフィルタを書く際のサンプルにどうぞって事で

 

 

back.gif (1980 バイト)

home.gif (1907 バイト)

Copyright © MURA All rights reserved.