PowerShellの再帰処理と参照渡し引数

2020-12-15 | コメント(0)

PowerShellのメソッドで、参照渡し引数の使い方をつい忘れてしまうことがあるので、再帰処理と併用したコードサンプルを残します。

考え方として、グローバルスコープの変数を使用すれば、わざわざ参照渡しにしなくても済むものですが、メソッド自体の汎用性も無くなってしまい、スクリプトそのものがガチガチになって手を入れにくいものになってしまうので、参照渡し引数を扱えるほうが良いです。

サンプルとして、参照渡しに使用する変数は、ファイルを表す FileInfo クラスを配列として保持する変数にします。

再帰処理としては、フォルダー階層の配下のファイルを列挙するというものにします。

まず、配列変数を宣言しておき、これを参照変数として使います。

[Array]$Files = @()

この配列には System.IO.FileInfo のデータが入ります。

配列であることを明示するために [Array] と型付け宣言しています。
※ [System.IO.FileInfo[]] 型として宣言しても良いです。

再帰処理をするメソッドは次のようにしています。

function FindDirectory {
    Param(
        [System.IO.DirectoryInfo]$di,
        [ref]$arr
    )

    # ファイル一覧の取得とチェック
    try {
        [System.IO.FileInfo[]]$fis = $di.GetFiles()
        $fis | foreach {
            $fi = $_

            $arr.Value += $fi

            #echo $fi.FullName
            #echo $arr.Value.Length
        }
    }
    catch {
    }

    # 配下のディレクトリを再帰処理
    try {
        [System.IO.DirectoryInfo[]]$dis = $di.GetDirectories()
        $dis | foreach {
            $di = $_
            FindDirectory -di $di -arr $arr
        }
    }
    catch {
    }
}

第一引数の [System.IO.DirectoryInfo]$di は、調べるフォルダーを取り、
第二引数の [ref]$arr が、参照渡しの配列で、フォルダー配下で見つかったファイルの FileInfo を追加していくというものです。

この処理では .GetFiles() や .GetDirectories() で、対象ファイルのアクセス権が無い場合に、UnauthorizedAccessException の例外が発生するので try ~ catch で例外処理をしています。

メインの呼び出し側は、次のようになります。

$folder = "C:\Windows"
$di = New-Object System.IO.DirectoryInfo($folder)
FindDirectory -di $di -arr ([ref]$Files)

これを実行すると、$folder 変数で指定した C:\Windows 配下全てのファイルを FileInfo とした配列が得られます。
※ アクセス権限の無いフォルダは得られません。

メソッド間で、参照渡し引数を引数として渡す場合の注意点としては、

メソッド側の引数の宣言は、参照渡しを明示するために [ref] で修飾することです。

また、メイン側からそのメソッドを呼び出す時の引数を指定する際にも、参照渡しを明示するために [ref] で修飾することです。

メイン側からの呼び出しは、FindDirectory -di $di -arr ([ref]$Files) のところですが、
パラメータ引数を指定せず、引数順に FindDirectory $di ([ref]$Files) というようにも記述できます。

どちらの呼び出し方でも、参照渡しの [ref] を含めて括弧で括ることです。括弧で括らないと構文エラーになります。

次に、参照渡し引数を受け取るメソッド内から、その参照渡し引数を(参照渡しとして)別メソッドに渡す場合です。これは、再帰処理のメソッドになりますが、このメソッドの引数は参照渡しの引数なので、それを参照渡しとして引数に使う場合は、[ref] で修飾する必要はありません(27行目のところ)。メソッドの引数が既に参照渡しの引数として渡ってきているため、そのままで参照渡しとして使用できるからです。

あとは、メソッド内で参照渡しの引数を使用する場合ですが、渡された引数の実体にアクセスするには Value プロパティを使用します。

具体的に、(13行目で)配列変数に追加しているところでは、$arr.Value += $fi のように、Value に対して操作しています。

配列数の参照にも、 $arr.Value.Length のように Value プロパティを経由してアクセスできます。

カテゴリ:

コメントする

※HTMLタグは使えません

Author

あきちゃん

主に、.NETでWebシステムの設計と開発をしています。
(茨城県在住, 都内勤務)
プロフィール