コーディングTips.ps1
ファイルとディレクトリを区別する方法
Get-ChildItem でファイルやフォルダを列挙したとき、ファイルだけを対象、またはディレクトリだけを対象としたい。
PSIsContainerプロパティを使う
Get-ChildItem -r C:\TargetFolder | where { $_.PSIsContainer }
PSIsContainerはPowerShell上で参照できるプロパティ。
$True の場合はコンテナ(ディレクトリ)、$False の場合はコンテナ内のアイテム(ファイル)。
インスタンスの型チェックを使う
Get-ChildItem -r C:\TargetFolder | where { $_ -is [IO.FileInfo] }
-is 演算子で、オブジェクトが.NET Frameworkのある型である(またはその型を継承している)かどうか、を判定できる。
Get-ChildItemはファイルの場合は System.IO.FileInfo クラス、ディレクトリの場合はSystem.IO.DirectoryInfo クラスのインスタンスを返す。
Get-ChildItemがどんなオブジェクトを返してくるかは、Get-Member で調べることができる。
こちらの方が汎用性は高いと思われる。
.NET Frameworkの型名指定は角カッコ[]を使う(System名前空間は省略可能とのこと)。文字列で指定してもよいようだが、この方が型名をしていしていることが明示的なので、記法としてはよいと思う。
ファイルIO
PowerShellにはGet-Contentがあるので、テキストファイル処理のために.NET Frameworkクラスを使用する必要は通常ない。
しかし、たとえば System.Security.Cryptography で処理するため等で、生の FileStream オブジェクトインスタンスが欲しい場合がある。
$fs = New-Object IO.FileStream -ArgumentList "C:\target_file.txt", "Open", "Read"
ということで、コンストラクタへの引数を複数渡すときには -ArgumentList オプションが使える。
さらに、FileMode と FileAccess の列挙体の値を引数として渡すときに、それぞれの列挙体のメンバー名を文字列として渡せばよい。
これがわかれば以下の同義文も書ける。
$fs = [IO.System.File]::Open("C:\target_file.txt", "Open", "Read")
ところで、.NET Frameworkのクラスに渡すファイルパスが相対パスだった場合、それは$homeを基準に解釈されてしまう。
$pwdではないので、注意が必要。
これを補正するためには、コマンドレットを経由してフルパスを得るようにすればよい。コマンドレットは相対パスを$pwdを基準に解釈してくれる。
その1: Resolve-Pathでフルパス文字列を得る。
param ($FilePath) $fullPath = Resolve-Path $FilePath $fs = [IO.System.File]::Open($fullPath, "Open", "Read")
その2: Get-Itemを使ってFileInfoオブジェクトを取得する。FileInfoの他のプロパティも後で使いたいときなど。
param($FilePath) $fi = Get-Item $FilePath $fs = [IO.System.File]::Open($fi.FullName, "Open", "Read")
コマンドレットの標準エラー出力を捨てる
スクリプト中で try - catch を使ってエラー処理をしても、コマンドレットはエラー発生時には勝手に標準エラー出力に自分のエラーメッセージを吐き出してしまう。
これはかなりカッコ悪い。エラーメッセージを制御したいから try - catch を使っているのに、これでは意味がない。
そんなときには、コマンドレットの出力を $null にリダイレクトすることができる。
たとえば Resolve-Path は与えられたパスが存在しないとエラーを吐くが、これを catch してスクリプト独自のエラーメッセージを出したい場合。
param($Path) try { $fullPath = Resolve-Path $Path 2> $null } catch { Write-Output "My message is ... " ... }
これで Revolve-Path のエラーメッセージは捨てられて、catch節に制御が移る。
エラーが発生しなければ、$fullPath に Resolve-Path の結果が代入される。
スクリプトの実行停止
[System.Environment]::Exit(0)