Powershellメモ1
- foreach と Foreach-Objectで ループの抜け方が異なる
- Select-Object の出力を加工したい
- 危険なコマンドを実行する際に確認のステップを入れる
- CSV、TSVの作り方・パースの仕方
- ルックアップ
foreach と Foreach-Objectで ループの抜け方が異なる
$list = @('1', '2', '3', '4') # foreach の場合は continue で抜ける foreach($item in $list) { if( ($item%2) -eq 0 ) { Write-Output $item } else { continue } } # Foreach-Object の場合は return で抜ける $list | Foreach-Object { if( ($_%2) -eq 0) { Write-Output $_ } else { return } }
Select-Object の出力を加工したい
以下のようにハッシュでプロパティ名とその値を指定してあげる。
Key名は任意の文字列でOK。
Select-Object Property,@{ Name = 'Label'; Expression = { script } }
> Get-Item .\hoge.txt | ` Select-Object FullName,@{N="mtime"; E={($_.LastWriteTimeUTC).ToString("yyyy-MM-ddTHH:mm:ss+09:00")}} FullName mtime -------- ----- E:\work\hoge.txt 2020-12-01T15:16:08+09:00
危険なコマンドを実行する際に確認のステップを入れる
Read-Host
を入れると良い感じになる。
%{ $cmd = 'icacls.exe .\' Write-Output "CMD: $cmd" $null = Read-Host "`rEnter で実行します" Invoke-Expression "$cmd" } while($true) { $cmd = "icacls.exe .\" Write-Output "CMD: $cmd" $ans = "" $ans = Read-Host "`r実行してもいいですか? (yes/no)" if("$ans" -eq 'yes') { Invoke-Expression "$cmd"; break }elseif("$ans" -eq 'no') { break }else{ continue } }
CSV、TSVの作り方・パースの仕方
CSV、TSVを作る
# + 演算子で文字列を結合 > "1" + "`t" + "2" + "`t" + "3" 1 2 3 > # 配列から生成 > $list = @("1", "2", "3") > > # デリミタを指定して1個の文字列に結合 > $list -join "`t" 1 2 3 # 指定の要素で結合 > $list[0,2] -join "`t" 1 3 # オブジェクトから生成 > $obj = [pscustomobject]@{ 'col1' = '1'; 'col2' = '2'; 'col3' = '3' } > > # オブジェクトを変換。UseQuotes オプションはPowershell7以降 > $obj | ConvertTo-Csv -Delimiter "`t" -UseQuotes Never col1 col2 col3 1 2 3
CSV、TSVをパースする
> $line = "1" + "`t" + "2" + "`t" + "3" > > # split演算子: 文字列を指定のデリミタで配列に変換 > $line -split "`t" 1 2 3 > > # ConvertFrom-CSV: 文字列を指定のデリミタでオブジェクトに変換 > $line | ConvertFrom-Csv -Delimiter "`t" -Header col1,col2,col3 col1 col2 col3 ---- ---- ---- 1 2 3
ルックアップ
例えば、Timestamp, Operation, Path のようなファイル操作を記録したTSV形式の監査ログファイルがあり、条件を指定して検索したい。
Where-Object
を使用した検索
- 柔軟な検索条件の指定が可能
- ハッシュテーブルを使用したルックアップより遅い
# TSVをオブジェクトに変換 $auditlog = Get-Content -Encoding UTF8 -Path $auditlog.tsv | ConvertFrom-Csv -Delimiter "`t" -Header Timestamp,Operation,Path # 条件を指定してレコード検索 $auditlog | ` Where-Object { $_.Path -match '.*\\hoge.xlsx' -and [datetime]$_.Timestamp -lt [datetime]"2020/12/1" }
ハッシュテーブルを使用した検索
- 非常に高速なルックアップが可能。ただし、キー名の重複は許可されない
- 以下の例だと、ログ中に同じパス文字列が複数存在した場合、先に読み込んだログは上書きされてしまうため、キー名が重複した場合は値を配列に追加する等の考慮が必要
# キー名=ファイルパス、値=レコード全体、としたハッシュテーブルを作成 $hashtable = @{} Get-Content -Encoding utf8 -Path $auditlog.tsv | ConvertFrom-Csv -Delimiter "`t" -Header Timestamp,Operation,Path | ` foreach { $hashtable[$_.Path] = $_ } # キー名=検索文字列(完全一致) を指定してルックアップ $pattern = '\\nas\share\salse\hoge.xlsx' $matched_logs = $hashtable[$pattern] # キー名にワイルドカードや正規表現は指定出来ないため、パターンマッチさせる場合は以下のようにアクセスする $hashtable.Keys | Where-Object {$_ -like "hoge*"} | foreach { $hashtable[$_] }