あるPowerShell関数の「引数」を別のパワーシェル関数に渡す方法は?
-
11-10-2019 - |
質問
私はいくつかのことを行ういくつかのPowerShell関数を書き込もうとしています。その後、既存の組み込み関数に透過的に呼び出します。手付かずのすべての議論を伝えたいです。私は議論の詳細を知りたくありません。
私はこれを行うために「スプラット」を使って疲れました @args
しかし、それは私が思っていたようにうまくいきませんでした。
以下の例では、私は呼ばれるおもちゃ機能を書きました myls
印刷することになっている こんにちは! そして、同じ組み込み関数を呼び出し、 Get-ChildItem
, 、組み込みエイリアス ls
引数の残りの部分との呼び出しはそのままです。私がこれまでに持っているものは非常にうまく機能します:
function myls
{
Write-Output "hello!"
# $MyInvocation | Format-List # <-- uncomment this line for debug info
Invoke-Expression ("Get-ChildItem " + $MyInvocation.UnboundArguments -join " ")
}
の正しいバージョン myls
複数のセミコロン区切りコマンドを含む行から、1つの引数、名前の引数で、1つの引数で、1つの引数で、1つの引数で、およびスペースを含む文字列変数を含む引数の変数を処理できる必要があります。基本的に、それはドロップインの代替品である必要があります ls
.
以下のテストは比較します myls
そしてビルトイン ls
:
注:スペースを節約するために排除および/または圧縮された出力
PS> md C:\p\d\x, C:\p\d\y, C:\p\d\"jay z"
PS> cd C:\p\d
PS> ls # no args
PS> myls # pass
PS> cd ..
PS> ls d # one arg
PS> myls d # pass
PS> $a="A"; $z="Z"; $y="y"; $jz="jay z"
PS> $a; ls d; $z # multiple statements
PS> $a; myls d; $z # pass
PS> $a; ls d -Exclude x; $z # named args
PS> $a; myls d -Exclude x; $z # pass
PS> $a; ls d -Exclude $y; $z # variables in arg-line
PS> $a; myls d -Exclude $y; $z # pass
PS> $a; ls d -Exclude $jz; $z # variables containing spaces in arg-line
PS> $a; myls d -Exclude $jz; $z # FAIL!
私が書き直すことができる方法はありますか? myls
私が欲しい行動を取得するには?
短い答え: はい、それは可能です。悪いニュース:呼び出したい関数に関するパラメーターやその他のメタデータの詳細を知っているコードが必要です。良いニュース: これをすべて自分で書く必要はありません. 。このメタデータはプログラムで利用可能であり、スケルトンプロキシコードを自動生成するために使用できるモジュールが存在します(以下の @jaykulの回答を参照)。使用することを選択します 「メタプログラム」という名前のモジュール. 。インポートしたら、ドロップインを生成します myls
スクリプトはシンプルです:
New-ProxyCommand ls > .\myls.ps1
その後、新しく生成されたカスタマイズを開始できます myls.ps1
スクリプト、このような:
...
begin
{
Write-Output "hello!" # <-- add this line
try {
$outBuffer = $null
...
出来上がり!この新しいバージョンはすべてのテストに合格します。
解決
LSのドロップインラッパーが必要な場合は、 適切なプロキシ関数. 。 poshcode.orgには、ジェネレーターにはいくつかのバージョンがあります。 Lee HolmesのPowershell Cookbookのもの
他のヒント
残念ながら、ラッパーを適切に作るのはそれほど簡単ではありません。まず第一に、Splat演算子はおそらくハッシュテーブルに適用する必要があります(例:自動 PSBoundParameters
または別の)、配列ではなく $args
直接。
少なくとも2つのオプション(両方とも完璧ではありません)とハック(更新セクションを参照)があります。
オプション1.ラッパーを作成する「クラシック」方法を使用します。例:これが関数に対してどのように行われるかを参照してください help
これはのラッパーです Get-Help
cmdlet:
Get-Content function:\help
ラッパー機能宣言者がわかります すべて ラップされたcmdletがそれを持つために持っているパラメーター PSBoundParameters
既存の関数パラメーターに制限されています.
あなたの例。関数がパラメーターを宣言する場合 Exclude
次に、サンプルコードが機能し始めます。しかし、それは機能します Exclude
のみ、そうではありません Force
, 、 けれど Force
渡されます:
function myls($Exclude) {
# only Exclude is in $PSBoundParameters even though we send Force, too:
$PSBoundParameters | Out-String | Out-Host
Write-Output "hello!"
Get-ChildItem @PSBoundParameters
}
cd d
myls -Exclude b -Force
オプション2.理論的には、配列からハッシュテーブルを構築することができるはずです $args
手動でスプラット演算子を適用します。しかし、このタスクは実質的に魅力的ではありません。
アップデート
まあ、実際には、最小限の労力を必要とする別のアドホックオプション(純粋なハック!)があり、いくつかの些細な、ほとんどインタラクティブなシナリオで機能します。それは何らかの形で深刻なコードのためではありません!
function myls {
# extra job
Write-Output "hello!"
# invoke/repeat the calling code line with myls "replaced" with Get-ChildItem
Set-Alias myls Get-ChildItem
Invoke-Expression $MyInvocation.Line
}
cd d
# variables can be used as the parameter values, too
$exclude = 'b'
myls -Exclude $exclude -Force
私はこれを信じています:
function myls {write-output "hello!"; iex "get-childitem @args"}
期待される結果の生成に近づきます。
更新:この方法で @argsを使用して名前のパラメーターを渡すことで、明らかに既知のバグがあります。
それが解決されるまでそれを使用することを中止します。