PowerShell 5で初めて、別の関数からファイルにメッセージを書き込む関数を呼び出すことができません。以下は私がやっていることの簡略版です。
workflow test {
function logMessage {
param([string] $Msg)
Write-Output $Msg
}
function RemoveMachineFromCollection{
param([string]$Collection, [string]$Machine)
# If there's an error
LogMessage "Error Removing Machine"
# If all is good
LogMessage "successfully remove machine"
}
$Collections = DatabaseQuery1
foreach -parallel($coll in $Collections) {
logMessage "operating on $coll collection"
$Machines = DatabaseQuery2
foreach($Mach in $Machines) {
logMessage "Removing $Mach from $coll"
RemoveMachineFromCollection -Collection $coll -Machine $Mach
}
}
}
test
これが生成するエラーです:
「logMessage」という用語は、コマンドレット、関数、スクリプトファイル、または操作可能なプログラムの名前として認識されません。名前のスペルを確認するか、パスが含まれていた場合は、パスが正しいことを確認して再試行してください。 + CategoryInfo:ObjectNotFound:(logMessage:String)[]、CommandNotFoundException + FullyQualifiedErrorId :CommandNotFoundException + PSComputerName:[localhost]
ファイル内でlogMessage関数を移動してみましたが、グローバルスコープも試しました。
他の言語では、他の関数からlogMessageを呼び出すことができます。それが関数の目的だからです。
コードブロックを再利用する「ワークフローの方法」とは何ですか?
ワークフローに読み込まれるロギングモジュールを作成する必要がありますか?
以下のように、ワークフロー内で関数と関数呼び出しをInlineScript
(PowerShell ScriptBlock)に移動できます。
workflow test {
InlineScript
{
function func1{
Write-Output "Func 1"
logMessage
}
function logMessage{
Write-Output "logMessage"
}
func1
}
}
出力されます:
Func 1
logMessage
@JeffZeitlinが彼の回答で述べたように、ワークフローはPowerShellではなく、はるかに制限的です。 InlineScriptブロックでは通常のPowerShellコードを解釈できますが、スコープはInlineScriptブロックに関連付けられます。たとえば、スクリプトブロックで関数を定義した場合、func1
関数をInlineScriptブロックの外(ただしワークフロー内)で呼び出そうとすると、スコープ外であるため失敗します。
InlineScriptブロックではなく、ワークフローの外側またはワークフローの内側の2つの関数を定義する場合も、同じことが起こります。
次に、これをforeach -parallel
ループの実行に適用する方法の例を示します。
workflow test {
## workflow parameter
param($MyList)
## parallel foreach loop on workflow parameter
foreach -parallel ($Item in $MyList)
{
## inlinescript
inlinescript
{
## function func1 declaration
function func1{
param($MyItem)
Write-Output ('Func 1, MyItem {0}' -f $MyItem)
logMessage $MyItem
}
## function logMessage declaration
function logMessage{
param($MyItem)
Write-Output ('logMessage, MyItem: {0}' -f $MyItem)
}
## func1 call with $Using:Item statement
## $Using: prefix allows us to call items that are in the workflow scope but not in the inlinescript scope.
func1 $Using:Item
}
}
}
このワークフローの呼び出し例は次のようになります
PS> $MyList = 1,2,3
PS> test $MyList
Func 1, MyItem 3
Func 1, MyItem 1
Func 1, MyItem 2
logMessage, MyItem: 3
logMessage, MyItem: 2
logMessage, MyItem: 1
並列で実行されたため、出力順序がランダムであることがわかります(予想通り)。
Powershellでは、使用前に関数を定義する必要があります(「レキシカルスコープ」)。あなたの例では、定義する前にlogMessage
関数を呼び出しています。
また、例をPowershellワークフローとして構造化しました。ワークフローには、通常のスクリプトにはないいくつかの制限があります。これらの違いに注意する必要があります。私は this search を実行して、違いの説明と議論を見つけました。 最初の「ヒット」 は、適切な情報を提供します。ワークフローで関数を定義できるかどうかについては(まだ)何もわかりませんが、そもそも関数(またはワークフロー)内で関数を定義することには非常に注意が必要です。
logMessage
関数はfunc1
関数内からは見えません。 logMessage
関数がfunc1
の上に宣言されている場合でも有効です。
この単純なケースでは、次のように 入れ子関数 を使用できます。
workflow test {
function func1 {
function logMessage {
Write-Output "logMessage"
}
Write-Output "Func 1"
logMessage
}
func1
}
test
出力:
PS D:\PShell> D:\PShell\SO\41770877.ps1
Func 1
logMessage