从PowerShell中的另一个函数调用函数

时间:2017-01-20 19:18:40

标签: function powershell workflow powershell-v5.0 powershell-workflow

第一次在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

这是它产生的错误:

The term 'logMessage' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    + CategoryInfo          : ObjectNotFound: (logMessage:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
    + PSComputerName        : [localhost]

我尝试在文件中移动logMessage函数,甚至尝试使用Global scope。

在任何其他语言中,我都可以从任何其他函数调用logMessage。因为这是一个功能的目的。

重用一段代码的“工作流方式”是什么?

我是否需要创建一些加载到工作流程中的日志记录模块?

3 个答案:

答案 0 :(得分:2)

Powershell要求在使用前定义函数('词法范围')。在您的示例中,您在定义它之前调用logMessage函数。

您还将示例结构化为Powershell工作流程。工作流有一些普通脚本没有的限制;你需要意识到这些差异。我this search做了一些关于差异的描述和讨论; the first "hit"提供了很好的信息。我还没有找到任何关于是否可以在工作流中定义函数的内容,但我会非常谨慎地在函数(或工作流)中定义函数。

答案 1 :(得分:2)

您可以将函数和函数调用移动到工作流内的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块相关联。例如,如果您在脚本块中定义函数然后尝试在InlineScript块之外调用func1函数(但仍在工作流中),它将失败,因为它超出了范围。

如果您在工作流程之外或工作流程内部而不是在InlineScript块中定义两个函数,则会发生同样的情况。

现在举例说明如何将其应用于运行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

您会注意到(并且如预期的那样)输出顺序是随机的,因为它是并行运行的。

答案 2 :(得分:0)

logMessage功能无法在func1功能中看到您的logMessage功能。即使func1函数在workflow test { function func1 { function logMessage { Write-Output "logMessage" } Write-Output "Func 1" logMessage } func1 } test 之上声明,它也是有效的。

对于这个简单的情况,您可以使用nested functions,如下所示:

PS D:\PShell> D:\PShell\SO\41770877.ps1
Func 1
logMessage

<强>输出

void ble_evt_gap_scan_response(const struct ble_msg_gap_scan_response_evt_t *msg)