Powershellで引数をMandatory(必須)にするときに地味にハマったこと
事象
Powershellでスペースありの文字列型の引数を受け取るとき、受け取った値にダブルクォーテーションがついてたりついてなかったりするので、それについて。
以下のようにparam
を使って引数を受け取る自作関数があったとします。
function Get-Hoge{ param( [Parameter(Mandatory)] [string]$arg ) Write-Host $arg }
で、関数を呼ぶ時は以下の2つの呼び出し方があります。 渡すのはスペースを含む文字列とします。
パターン1
PS C:\Users\nogam> Get-Hoge -arg "has space" has space
これは問題なさそうですね。
パターン2(Mandatoryにより入力待ちから入力する場合)
PS C:\Users\nogam> Get-Hoge コマンド パイプライン位置 1 のコマンドレット Get-Hoge 次のパラメーターに値を指定してください: arg: "has space" "has space"
のほうは、ダブルクォーテーション付きで渡されます。
"has space"ではなくhas spaceとだけ入力すれば、ふつうにhas spaceが渡されます。
これを回避するためには、以下のようにTrim
すればよいです。
Write-Host $arg.Trim("`"")
何がハマったのか
ここからはPowershellの仕様とは関係ない運用的な話になります。
例えば、上記の関数が以下のようにファイルパスを受け取るような関数だった場合を考えます。
function Open-HogeFile{ param( [Parameter(Mandatory)] [string]$file_path ) $file = [System.IO.File]::Open($file_path, [System.IO.FileMode]::Open) $file $file.Close() }
パターン1の場合
PS C:\Users\nogam> Open-HogeFile -file_path "C:\Users\nogam\Downloads\hoge.txt" CanRead : True CanWrite : True CanSeek : True IsAsync : False Length : 11 Name : C:\Users\nogam\Downloads\hoge.txt Position : 0 Handle : 4228 SafeFileHandle : Microsoft.Win32.SafeHandles.SafeFileHandle CanTimeout : False ReadTimeout : WriteTimeout :
問題なさそうです。しかしパターン2だと
PS C:\Users\nogam> Open-HogeFile コマンド パイプライン位置 1 のコマンドレット Open-HogeFile 次のパラメーターに値を指定してください: file_path: "C:\Users\nogam\Downloads\hoge.txt" "2" 個の引数を指定して "Open" を呼び出し中に例外が発生しました: "パスに無効な文字が含まれています。" 発生場所 C:\Users\nogam\Downloads\test.ps1:6 文字:5 + $file = [System.IO.File]::Open($file_path, [System.IO.FileMode]:: ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : ArgumentException null 値の式ではメソッドを呼び出せません。 発生場所 C:\Users\nogam\Downloads\test.ps1:8 文字:5 + $file.Close() + ~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) []、RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
当然ですが失敗します。
ところで、「この引数の渡し方は失敗するのがわかっているのに、なぜそんな渡し方をするの?」と思いますよね。
それは、この関数の運用を考えると見えてきます。この関数の利用者は、
1.エクスプローラーからファイルを右クリック⇒パスをコピー
2.関数を実行するときに、コピーしたパスをペースト
という手順を踏むことが多くなるはずです。
上記の1.でコピーしたパスはダブルクォーテーション付きでコピーされます。
また、この関数を利用するのがPowershellをあまり利用しない人だった場合、関数実行時に指定する引数と対話型プロンプトから指定する引数で渡し方が違うとは想像しにくいです
なので、引数はTrimして受けるのがいい気がしますね。
ここまでお読みいただきありがとうございます。