2011-01-15 16 views
10

私はPowerShell関数をいくつか書いていますが、何かをして、既存の組み込み関数を透過的に呼び出します。私はすべての議論に手を差し伸べたい。私は議論の詳細を知る必要はありません。1つのPowerShell関数の 'argument-line'を別のPowerShell関数に渡すには?

でこれを行うには 'splat'を使用するのが疲れましたが、期待通りに機能しませんでした。

以下の例では、mylsというおもちゃの機能を書いていますが、こんにちは!を呼び出し、同じ組み込み関数Get-ChildItemを呼び出して、組み込みエイリアスlsが残りの引数行をそのまま呼び出していることを確認します。私はこれまで持っていることはかなりうまく動作します:myls

function myls 
{ 
    Write-Output "hello!" 
# $MyInvocation | Format-List   # <-- uncomment this line for debug info 
    Invoke-Expression ("Get-ChildItem " + $MyInvocation.UnboundArguments -join " ") 
} 

正しいバージョンでは、複数のセミコロン区切りのコマンドを含む行から、名前付き引数と、一つの引数で、引数なしで呼び出されて処理できる必要がありますスペースを含む文字列変数を含む引数の変数を使用します。基本的には、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ことができる方法があります私が望む行動を得るために?

短い回答:はい、可能です。悪いニュース:パラメータの詳細と、呼び出したい機能に関する他のメタデータを知っているコードが必要です。良いニュース:1つはすべて自分自身を書く必要はありません。このメタデータはプログラム的に利用可能であり、スケルトンプロキシコードを自動生成するために使用できるモジュールが存在します(@ Jaykulの答えを参照)。私はthe module named "MetaProgramming"を使用することを選択します。インポート後、ドロップインmylsスクリプトを生成することは死んで簡単です:

... 
    begin 
    { 
    Write-Output "hello!"    # <-- add this line 
    try { 
     $outBuffer = $null 
    ... 

出来上がり:

New-ProxyCommand ls > .\myls.ps1

その後1は、このように、新たに生成されたmyls.ps1スクリプトをカスタマイズすることができます!この新しいバージョンはすべてのテストに合格します。

答えて

4

lsのドロップインラッパーが必要な場合は、proper proxy functionと記述してください。 PoshCode.orgには、発電機のいくつかのバージョンが含まれています。the one from Lee Holmes' PowerShell Cookbook

+0

これは私が本当に必要なものです。ありがとう! – jwfearn

+0

つまり、自動コピー貼り付け。ただ驚くほど。 – alecov

+2

コピー貼り付けができれば、コード生成は不要です。 OPがやっていることは、コマンドをサブクラス化しようとすることです:オリジナルに基づいて新しいコマンドを書きますが、カスタムの変更を加えてスクリプトで行います。あなたがC#でそれをやっていたら、あなたはただ継承しています。しかし、PowerShellを使用しているので、最初のコマンドレット(PowerShellでは、これらのプロキシ関数を呼び出す)からパラメータのセットを複製することから始まる関数を記述する必要があります。コード生成のために泣いたことがあった場合、これがそれです。 – Jaykul

2

私はこれを信じる:

機能myls {書き込み出力 "こんにちは!"; iex "Get-ChildItem @args"}

は、予想通りの結果を得ることができます。

更新:

https://connect.microsoft.com/PowerShell/feedback/details/368512/splat-operator-args-doesnt-properly-pass-named-arguments?wa=wsignin1.0

それが解決されるまで、私はあることの使用を中止したい:名前付きパラメータを渡すために、このように@argsを使用して既知のバグが明らかにあります。

+0

これは近いです - エラーは発生しません - 残念ながらargsも無視されます。上のテストを試してみると、 'myls'と' myls -Exclude b'の出力は間違って同じです。 – jwfearn

+0

最初の行を付けずに試してみてください。 – mjolinor

4

ラッパーを正しく作成することは、残念ながら簡単ではありません。まず、スプラット演算子は、配列$argsではなく、ハッシュテーブル(たとえば、自動PSBoundParametersまたは別のもの)に適用されるはずです。

少なくとも2つのオプション(両方とも完璧ではない)とハック(更新セクションを参照)があります。

オプション1.「古典的な」ラッパーの作成方法を使用します。例:これはGet-Helpコマンドレットのラッパーである機能helpのためにどのように行われるかを参照してください。

Get-Content function:\help 

あなたはラッパー関数をラップコマンドレットがあることを持っているために持っているすべてパラメータをdeclarersていることがわかりますPSBoundParametersは、既存の関数パラメータにバインドされています。

あなたの例。関数がパラメータExcludeを宣言すると、サンプルコードが動作し始めます。手動配列$argsからハッシュテーブルを構築し、それにスプラット演算子を適用することが可能であるべきでは理論的には

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:Forceも渡されているがしかし、それは、Excludeだけではなく、Forceのために働きます。しかし、この作業は実際には魅力的ではありません。


UPDATE

まあ、さらに別のアドホックオプション(純粋なハック!)最小限の労力を必要とし、いくつかの些細な、主にインタラクティブな、シナリオで動作します実際にそこにあります。それは何とか深刻なコードのためではありません!

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 
+0

ハックは機能し、さまざまなオプションのパラメータをすべて処理する(または知ることさえ必要ない)という利点があります。 – jwfearn

+1

それは動作しますが、実際の使用には十分ではありません。 '$ MyInvocation.Line'は、他のステートメントも含めた全呼び出し行です。結果として、これは動作しません: '$ result = myls ...'。しかし、これはうまくいくようです: 'myls ... - 変わった結果'。 –

+0

ええ、私もそれに気づいた。修正が必要です。私が見つけたら教えてあげましょう。 – jwfearn