225

SharePointチームサイトのプロビジョニングに関連するいくつかのアクションを実行するPowerShell関数を開発しました。最終的に、関数がプロビジョニングされたサイトのURLを文字列として返すようにしたいので、関数の最後に次のコードがあります。

$rs = $url.ToString();
return $rs;

この関数を呼び出すコードは次のようになります。

$returnURL = MyFunction -param 1 ...

だから私は文字列を期待していますが、そうではありません。代わりに、System.Management.Automation.PSMethodタイプのオブジェクトです。文字列型ではなくその型を返すのはなぜですか?

4

10 に答える 10

307

PowerShellには、少なくとも従来のプログラミングの観点から見ると、非常に奇抜なリターンセマンティクスがあります。頭を包むための2つの主なアイデアがあります。

  • すべての出力がキャプチャされ、返されます
  • returnキーワードは、実際には論理的な出口点を示しているだけです

したがって、次の2つのスクリプトブロックは、まったく同じことを効果的に実行します。

$a = "Hello, World"
return $a

 

$a = "Hello, World"
$a
return

2番目の例の$a変数はパイプラインの出力として残され、前述のように、すべての出力が返されます。実際、2番目の例では、戻り値を完全に省略でき、同じ動作が得られます(関数が自然に完了して終了するため、戻り値が暗示されます)。

関数定義がなければ、PSMethodオブジェクトを取得する理由はわかりません。私の推測では、キャプチャされておらず、出力パイプラインに配置されているものがいくつか並んでいる可能性があります。

また、1行に複数の式をネストしない限り、これらのセミコロンはおそらく必要ないことにも注意してください。

リターンセマンティクスの詳細については、TechNetのabout_Returnページを参照するか、help returnPowerShell自体からコマンドを呼び出すことで確認できます。

于 2012-04-23T21:01:56.683 に答える
59

PowerShellのこの部分は、おそらく最も愚かな側面です。関数中に生成された無関係な出力は、結果を汚染します。出力がない場合もありますが、ある条件下では、計画された戻り値に加えて、他の計画外の出力があります。

そのため、元の関数呼び出しから割り当てを削除して、出力が画面に表示されるようにし、計画していなかったものがデバッガーウィンドウに表示されるまでステップスルーします(PowerShell ISEを使用)。

外部スコープで変数を予約するようなものでさえ、出力を引き起こします。そのような[boolean]$isEnabledものは、あなたがそれを作らない限り、迷惑なことにFalseを吐き出します[boolean]$isEnabled = $false

もう1つの良い方法は$someCollection.Add("thing")、新しいコレクション数を吐き出すことです。

于 2013-01-30T14:23:57.200 に答える
54

PowerShell 5を使用すると、クラスを作成できるようになります。関数をクラスに変更すると、returnはその直前のオブジェクトのみを返します。これが実際の簡単な例です。

class test_class {
    [int]return_what() {
        Write-Output "Hello, World!"
        return 808979
    }
}
$tc = New-Object -TypeName test_class
$tc.return_what()

これが関数の場合、期待される出力は次のようになります。

Hello World
808979

ただし、クラスとして返されるのは整数808979だけです。クラスは、宣言された型またはvoid型のみを返すという保証のようなものです。

于 2017-03-12T02:46:34.563 に答える
36

回避策として、関数から取得した配列の最後のオブジェクトを返してきました...これは優れたソリューションではありませんが、何もないよりはましです。

someFunction {
   $a = "hello"
   "Function is running"
   return $a
}

$b = someFunction
$b = $b[($b.count - 1)]  # Or
$b = $b[-1]              # Simpler

全体として、同じことを書くためのより単行的な方法は次のようになります。

$b = (someFunction $someParameter $andAnotherOne)[-1]
于 2014-07-08T11:38:03.627 に答える
8

コンソールに出力したいので、戻りの狂気を避けるために、単一の結果メンバーを持つ単純なHashtableオブジェクトを渡します。参照によるパススルーとして機能します。

function sample-loop($returnObj) {
  for($i = 0; $i -lt 10; $i++) {
    Write-Host "loop counter: $i"
    $returnObj.result++
  }
}

function main-sample() {
  $countObj = @{ result = 0 }
  sample-loop -returnObj $countObj
  Write-Host "_____________"
  Write-Host "Total = " ($countObj.result)
}

main-sample

私のGitHubプロジェクトunpackTunesで実際の使用例を見ることができます。

于 2015-08-23T23:27:31.957 に答える
7

Write-Output既存の答えは正しいですが、実際にはまたはで明示的に何かを返さない場合がありますがreturn、関数の結果には謎の値があります。これは、次のような組み込み関数の出力である可能性があります。New-Item

PS C:\temp> function ContrivedFolderMakerFunction {
>>    $folderName = [DateTime]::Now.ToFileTime()
>>    $folderPath = Join-Path -Path . -ChildPath $folderName
>>    New-Item -Path $folderPath -ItemType Directory
>>    return $true
>> }
PS C:\temp> $result = ContrivedFolderMakerFunction
PS C:\temp> $result


    Directory: C:\temp


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----         2/9/2020   4:32 PM                132257575335253136
True

ディレクトリ作成の余分なノイズはすべて収集され、出力に出力されます。これを軽減する簡単な方法| Out-Nullは、ステートメントの最後に追加するNew-Itemことです。または、結果を変数に割り当てて、その変数を使用しないようにすることもできます。このようになります...

PS C:\temp> function ContrivedFolderMakerFunction {
>>    $folderName = [DateTime]::Now.ToFileTime()
>>    $folderPath = Join-Path -Path . -ChildPath $folderName
>>    New-Item -Path $folderPath -ItemType Directory | Out-Null
>>    # -or-
>>    $throwaway = New-Item -Path $folderPath -ItemType Directory 
>>    return $true
>> }
PS C:\temp> $result = ContrivedFolderMakerFunction
PS C:\temp> $result
True

New-Itemおそらくこれらの中でより有名ですが、他の方法にはすべてのStringBuilder.Append*()方法とその方法が含まれSqlDataAdapter.Fill()ます。

于 2020-02-09T21:41:37.777 に答える
5

コードを見ずに言うのは難しいです。関数が複数のオブジェクトを返さないこと、および他の呼び出しから行われた結果をキャプチャすることを確認してください。あなたは何のために得ます:

@($returnURL).count

とにかく、2つの提案:

オブジェクトを文字列にキャストします。

...
return [string]$rs

または、上記と同じですが、入力するのが短い二重引用符で囲みます。

...
return "$rs"
于 2012-04-23T21:02:33.723 に答える
4

これらのシナリオでの関数の結果に関するLukeの説明は、正しいようです。根本的な原因を理解したいだけで、PowerShell製品チームはその動作について何かをします。これは非常に一般的なようで、デバッグに時間がかかりすぎました。

この問題を回避するために、関数呼び出しから値を返して使用するのではなく、グローバル変数を使用してきました。

グローバル変数の使用に関する別の質問は次の とおりです。グローバル変数名が関数に渡される変数である関数からグローバルPowerShell変数を設定する

于 2013-08-16T19:37:39.943 に答える
3

以下は単に答えとして4を返します。文字列のadd式を置き換えると、最初の文字列が返されます。

Function StartingMain {
  $a = 1 + 3
  $b = 2 + 5
  $c = 3 + 7
  Return $a
}

Function StartingEnd($b) {
  Write-Host $b
}

StartingEnd(StartingMain)

これは、アレイに対しても実行できます。以下の例では、「テキスト2」が返されます。

Function StartingMain {
  $a = ,@("Text 1","Text 2","Text 3")
  Return $a
}

Function StartingEnd($b) {
  Write-Host $b[1]
}

StartingEnd(StartingMain)

関数自体の下で関数を呼び出す必要があることに注意してください。そうしないと、最初に実行したときに、「StartingMain」が何であるかがわからないというエラーが返されます。

于 2014-07-17T06:49:34.193 に答える
1

戻る前に出力をクリアする必要があります。Out-Nullを使用してみてください。これがPowerShellのreturn仕組みです。必要な変数ではなく、関数全体の出力を返します。したがって、あなたの例は次のようになります。

function Return-Url
{
   param([string] $url)

   . {
       $rs = $url.ToString();
       return
   } | Out-Null
   
   return $rs
}

$result = Return-Url -url "https://stackoverflow.com/questions/10286164/function-return-value-in-powershell"

Write-Host $result
Write-Host $result.GetType()

そして結果は次のとおりです。

https://stackoverflow.com/questions/10286164/function-return-value-in-powershell
System.String

https://riptutorial.com/powershell/example/27037/how-to-work-with-functions-returnsへのクレジット

于 2021-08-26T16:58:21.933 に答える