お題:任意のディレクトリ内のファイルについて列挙する。
※SQL Serverのインストールディレクトリ内の「DATA」フォルダを参照するサンプルを作成する。
まずはディレクトリを移動
PS C:\Users\kimiyuki> cd "C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA"
PS C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA>
ディレクトリ内のファイルの列挙・Get-ChildItemでディレクトリ以下のファイルを列挙出来る。
-Includeオプションで拡張子を指定している。
PS C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA>
Get-ChildItem -Recurse -File -Include *.mdf
ディレクトリ: C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2019/01/03 20:55 130088960 AdventureWorksDW2012.mdf
-a--- 2019/01/03 20:55 23003136 AdventureWorksLT2012.mdf
-a--- 2019/01/03 20:55 5111808 master.mdf
-a--- 2019/01/03 20:55 4259840 model.mdf
-a--- 2019/01/03 20:55 17498112 MSDBData.mdf
-a--- 2019/01/20 5:10 148897792 MyStockDB.mdf
-a--- 2019/01/05 2:10 12582912 SalesDB.mdf
-a--- 2019/01/03 20:55 41943040 SSISDB.mdf
-a--- 2019/01/03 21:01 8388608 tempdb.mdf
-a--- 2019/01/03 20:55 14680064 TestDB.mdf
※列挙するだけならGet-ChildItemコマンドで十分であるが、ループ毎に何らかの処理をしたい場合は不十分…
foreachによるループ処理
・Get-ChildItemの結果を$array にObject型の配列として格納する。
・LastWriteTimeはDateTime型なのでToStringでフォーマットを指定できる。
PS C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA>
$array = (Get-ChildItem -Recurse -File -Include *.mdf )
foreach($a in $array)
{
echo $a.LastWriteTime.ToString("yyyyMMdd_HHmmss")
}
20190103_205520
20190103_205518
20190103_205524
20190103_205522
20190103_205522
20190120_051006
20190105_021043
20190103_205517
20190103_210146
20190103_205518
※foreachのループ処理部分で個別のロジックの記述が可能。感覚的にはC#のループ処理と同じイメージ。
foreach-objectによるループ処理
foreachの例と同様にGet-ChildItemの結果を加工する。
PS C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA>
Get-ChildItem -Recurse -File -Include *.mdf | ForEach-Object -Begin{$array= @();} -Process{$array += $_.LastWriteTime.ToString("yyyyMMdd_HHmmss")} -End{$array}
20190103_205520
20190103_205518
20190103_205524
20190103_205522
20190103_205522
20190120_051006
20190105_021043
20190103_205517
20190103_210146
20190103_205518
※ForEach-Object コマンドレットでは、パイプに渡して処理を書くので1行で収まっている(可読性は悪い気が…)-Beginオプション:前処理を記述(データを格納する配列を宣言)
-Processオプション:処理内容を記述(配列にデータを格納)
「$_」で元のデータにアクセスできる
-Endオプション:後処理(結果の表示)
まとめ
色々調べると、foreachステートメントよりforeach-objectコマンドレットの方がメモリ量が少なくて済むそうなので処理の高速化が期待できる。でも、使ってみるとforeachステートメントの方がC#等のループ処理に近い感覚で記述できるので分かりやすい気がします。
この辺の感じは未だにラムダ式に慣れずクエリ式でLinqを書いている感覚に近いものがあります…
参考
Powershellのforeach(ForEach-Object)の使い方【ForEach-Object】PowerShellでパイプからforeachループするテクニック
PowerShellの落とし穴!ForEach-Objectとforeachは違う?
PowerShellのGet-ChildItemコマンドレットでファイル名の一覧を取得する(応用編)