首页 文章

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

提问于
浏览
4

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

  • 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
    

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

  • 0

    Powershell要求在使用前定义函数('lexical scope') . 在您的示例中,您在定义之前调用 logMessage 函数 .

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

  • 2

    func1 函数中看不到 logMessage 函数 . 即使 logMessage 函数在 func1 之上声明,它也是有效的 .

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

    workflow test {
    
        function func1 {
    
            function logMessage {
                Write-Output "logMessage"
            }
    
            Write-Output "Func 1"
            logMessage
        }
    
      func1
    
    }
    
    test
    

    Output

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

相关问题