web-dev-qa-db-ja.com

PowerShellで関数に複数のパラメータを渡す方法

複数の文字列パラメータを受け取る関数がある場合、最初のパラメータはそれに割り当てられているすべてのデータを取得するように見え、残りのパラメータは空として渡されます。

簡単なテストスクリプト

Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test("ABC", "DEF")

生成された出力は

$arg1 value: ABC DEF
$arg2 value: 

正しい出力は次のようになります。

$arg1 value: ABC
$arg2 value: DEF

これは、複数のマシン上のv1とv2の間で一貫しているように見えるので、明らかに、私は何か問題を起こしています。誰もが正確に何を指摘できますか?

362
Nasir

PowerShellの関数呼び出し(すべてのバージョン)のパラメーターは、スペースで区切られており、コンマで区切られていません。また、括弧はまったく不要なので、Set-StrictModeがアクティブな場合、PowerShell 2.0以降では解析エラーが発生します。括弧で囲まれた引数は.NETメソッドでのみ使用されます。

function foo($a, $b, $c) {
   "a: $a; b: $b; c: $c"
}

ps> foo 1 2 3
a: 1; b: 2; c: 3
487
x0n

正しい答えはすでに提供されていますが、この問題は微妙な部分を理解したい人のためのいくつかの追加の詳細を正当化するのに十分普及しているようです。これは単なるコメントとして追加したはずですが、イラストを含めたいと思いました。PowerShellの機能に関するクイックリファレンスチャートからこれを切り離しました。これは関数fのシグネチャがf($a, $b, $c)であると仮定します。

syntax pitfalls of a function call

したがって、スペースで区切られた 位置 パラメータまたは順序に依存しない 名前付き parametersを使用して関数を呼び出すことができます。他の落とし穴は、あなたがカンマ、括弧、空白を認識する必要があることを明らかにしています。

さらに読むために私の記事を参照してください うさぎの穴を下って:PowerShellのパイプライン、関数、およびパラメーターの研究 Simple-Talk.comで公開されたこの記事にはクイックリファレンス/ウォールチャートへのリンクも含まれています。

232
Michael Sorens

PowerShell関数は、括弧なしで、また区切り文字としてコンマを使用せずに呼び出します。試してみてください。

   test "ABC" "DEF"

PowerShellでは、コンマ(、)は配列演算子です。

   $a = "one", "two", "three"

$ aを3つの値を持つ配列に設定します。

41
Todd

ここにいくつかの良い答えがありますが、私は他にもいくつか指摘したいと思いました。関数パラメータは、実際にはPowerShellが輝く場所です。たとえば、次のような高度な機能では、名前付きパラメータまたは位置パラメータを使用できます。

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [int] $Id
    )
}

それからパラメータ名を指定してそれを呼び出すことも、明示的に定義したので単に位置パラメータを使用することもできます。それで、これらのどちらでもうまくいくでしょう:

Get-Something -Id 34 -Name "Blah" 
Get-Something "Blah" 34

最初の例は、Nameが2番目に指定されていても機能します。これは、明示的にパラメータ名を使用したためです。ただし、2番目の例は位置に基づいて機能するため、Nameを最初に指定する必要があります。可能であれば、私は常にポジションを定義しようとしているので両方のオプションが利用可能です。

PowerShellには、パラメータセットを定義する機能もあります。メソッドのオーバーロードの代わりにこれを使用していますが、これも非常に便利です。

function Get-Something
{
    [CmdletBinding(DefaultParameterSetName='Name')]
    Param
    (
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Name')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Id')]
         [int] $Id
    )
}

この関数は名前かIDのどちらかを取りますが、両方は取りません。あなたはそれらを位置的にあるいは名前で使うことができます。それらは異なるタイプなので、PowerShellはそれを理解します。だからこれらのすべてがうまくいくだろう

Get-Something "some name"
Get-Something 23
Get-Something -Name "some name"
Get-Something -Id 23

さまざまなパラメータセットに追加のパラメータを割り当てることもできます。 (これは明らかにかなり基本的な例です)関数内で、$ PsCmdlet.ParameterSetNameプロパティでどのパラメータセットが使用されたかを判断できます。例えば:

if($PsCmdlet.ParameterSetName -eq "Name")
{
    Write-Host "Doing something with name here"
}

それから、関連するメモとして、PowerShellのパラメータ検証もあります。これは私のお気に入りのPowerShell機能の1つであり、関数内のコードを非常にきれいにします。あなたが使用できるたくさんの検証があります。いくつかの例は

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidatePattern('^Some.*')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [ValidateRange(10,100)]
         [int] $Id
    )
}

最初の例では、ValidatePatternは、提供されたパラメータが期待しているものと一致することを保証する正規表現を受け入れます。そうでない場合は、直観的な例外がスローされ、何が問題なのか正確にわかります。したがって、その例では、「何か」はうまく機能しますが、「夏」は検証に合格しません。

ValidateRangeは、パラメーター値が整数として期待される範囲内にあることを確認します。したがって、10または99が動作しますが、101は例外をスローします。

もう1つの便利なものはValidateSetです。これを使用すると、許容値の配列を明示的に定義できます。何か他のものが入力された場合、例外がスローされます。他にもありますが、おそらく 最も有用な 1はValidateScriptです。これは$ trueと評価されなければならないスクリプトブロックをとるので、空が限界です。例えば:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidateScript({ Test-Path $_ -PathType 'Leaf' })]
         [ValidateScript({ (Get-Item $_ | select -Expand Extension) -eq ".csv" })]
         [string] $Path
    )
}

この例では、$ Pathが存在するだけでなく、それがファイルであり(ディレクトリではなく)、拡張子が.csvであることが保証されています。このレベルが必要な場合は、はるかに大きい複数行のスクリプトブロックを渡すことも、ここで行ったように複数のスクリプトブロックを使用することもできます。それは非常に便利です、そしてきれいな関数と直感的な例外をきれいにします。

32
user2233949
Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test "ABC" "DEF"
13
John B

あなたがC#/ Java/C++/Ruby/Python /今世紀からの言語を選ぶ開発者で、あなたが自分の関数をコンマで呼び出したいのなら、それがいつもしていることなので、何かが必要ですこのような:

$myModule = new-module -ascustomobject { 
    function test($arg1, $arg2) { 
        echo "arg1 = $arg1, and arg2 = $arg2"
    }
}

今電話してください:

$myModule.test("ABC", "DEF")

そして見ますよ

arg1 = ABC, and arg2 = DEF
10

関数に渡す引数の数がわからない(または気にしない)場合は、次のような非常に単純な方法を使用することもできます。

コード

function FunctionName()
{
    Write-Host $args
}

それはすべての議論をプリントアウトするでしょう。例えば:

FunctionName a b c 1 2 3

出力

a b c 1 2 3

私はこれが特に有用であると思う。多くの異なる(そしてオプションの)パラメータを持つことができる外部コマンドを使う関数を作成するとき、構文エラーなどに関するフィードバックを提供するために前記コマンドに頼る.

これはもう一つの現実的な例です(tracertコマンドへの関数の作成、私は切り捨てられた名前を覚えておく必要はありません)。

コード

Function traceroute
{
    Start-Process -FilePath "$env:systemroot\system32\tracert.exe" -ArgumentList $args -NoNewWindow
}
5
Draino

あなたがしようとした場合:

PS > Test("ABC", "GHI") ("DEF")

あなたが得る:

$arg1 value: ABC GHI
$arg2 value: DEF

括弧でパラメータを区切っているのがわかります

あなたがしようとした場合:

PS > $var = "C"
PS > Test ("AB" + $var) "DEF"

あなたが得る:

$arg1 value: ABC
$arg2 value: DEF

今すぐあなたは括弧のいくつかの即時の有用性を見つけることができた - スペースは次のパラメータのためのセパレータにならない - 代わりにあなたはeval関数を持っている。

5
RaSor

あなたがその関数で何をしているのか私にはわかりませんが、 'param'キーワードの使い方を見てください。それは関数にパラメータを渡すためにかなり強力であり、そしてそれをよりユーザーフレンドリーにします。以下はそれについてのマイクロソフトからの非常に複雑な記事へのリンクです。それは記事がそれを健全にするほど複雑ではありません。 パラメータの使用法

また、これはこのサイトの thread からの例です。

見てみな。

3
Rodney Fisk

これはよくある質問なので、PowerShell関数は 承認された動詞Verb-Noun)を関数名として使用する必要があります。また、パラメーターが必須およびパラメーターのposition

function Test-Script
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [string]$arg1,

        [Parameter(Mandatory=$true, Position=1)]
        [string]$arg2
    )

    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

関数にパラメータを渡すには、position:)を使うことができます。

Test-Script "Hello" "World"

あるいはあなたは指定パラメータ名前:)

Test-Script -arg1 "Hello" -arg2 "World"

あなたはC#の中で関数を呼び出すときのように括弧を使わないでください。


複数のパラメータを使用する場合は、alwaysを渡すことをお勧めします。これはreadのためです。

2
Martin Brandl
Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test("ABC") ("DEF")
2
user3222697
Function Test {
 Param([string]$arg1, [string]$arg2)
    Write-Host $arg1
    Write-Host $arg2
}

これは正しいparams宣言です https://technet.Microsoft.com/ja-jp/library/dd347600.aspx

そしてそれは確かにうまくいく

1
Serhii Kimlyk

私は先に次のように述べています。

よくある問題は単数形の$argを使うことですが、これは誤りです。
これは常に$argsのように複数形であるべきです。

問題ではありません。
実際、$argは他のものでもかまいません。問題は、コンマと括弧の使用でした。
私はうまくいった以下のコードを実行します、そして、出力は続きます:

コード:

Function Test([string]$var1, [string]$var2)
{
    Write-Host "`$var1 value: $var1"
    Write-Host "`$var2 value: $var2"
}

テスト "ABC" "DEF"

出力:

$ var1値:ABC $ var2値:DEF

1
Eric

ここでは触れていませんが、 飛び跳ねる あなたの引数は有効な代替手段であり、(Invoke-Expressionを使用するのではなく)動的にコマンドの引数を作成する場合に特に役立ちます。位置引数には配列を、名前付き引数にはハッシュテーブルを使用することができます。ここではいくつかの例を示します。

配列を含むスプラット(位置引数)

位置引数を用いたテスト接続

Test-Connection www.google.com localhost

アレイスプラッティング付き

$argumentArray = 'www.google.com', 'localhost'
Test-Connection @argumentArray

飛び散るときは、飛び越した変数を@ではなく$で参照します。 Hashtableを使って感嘆符を使う場合も同じです。

ハッシュテーブル付きスプラット(名前付き引数)

名前付き引数によるテスト接続

Test-Connection -ComputerName www.google.com -Source localhost

ハッシュテーブル飛び散りを使って

$argumentHash = @{
  ComputerName = 'www.google.com'
  Source = 'localhost'
}
Test-Connection @argumentHash

位置指定引数と名前付き引数の同時実行

位置引数と名前付き引数の両方を使用したテスト接続

Test-Connection www.google.com localhost -Count 1

飛び散り配列とハッシュテーブル

$argumentHash = @{
  Count = 1
}
$argumentArray = 'www.google.com', 'localhost'
Test-Connection @argumentHash @argumentArray
0

このように parameters function を渡すこともできます。

function FunctionName()
{
    Param ([string]$ParamName);
    #Operations
}
0
Kaushal Khamar