Multiple functions inside foreach

This topic contains 9 replies, has 3 voices, and was last updated by Profile photo of Richard Diphoorn Richard Diphoorn 1 year, 7 months ago.

  • Author
    Posts
  • #26354
    Profile photo of Grant Harrington
    Grant Harrington
    Participant

    I've got two functions that work together, one generates data that is used in the second function.

    For a single input value it works fine, I'm trying to pass several variables (PC names) to loop through.

    Am trying to use a Workflow, but it's not giving the results I'd like. In this example, I'd like the output to be:
    Function 02 Variable 01
    Function 01 Variable 01
    Function 02 Variable 02
    Function 01 Variable 02

    Workflow get-workflow {
    
     param([string[]]$WFParam)
    
        Function get-f01 {
            param([string]$Param01)
            
            "Function 01 $Param01"
        } #end get-f01
    
    
        Function get-f02 {
            param([string]$Param02)
            
            "Function 02 $Param02"
            get-f01 -Param01 $FunctionVar
        } #end get-f02
    
      foreach -parallel($FunctionVar in $GlobalVar) {
    
            get-f02 -Param02 $FunctionVar
        } #end foreach
    } #end workflow
    
    $GlobalVar = 'Variable01','Variable02'
    get-workflow -WFParam $GlobalVar
  • #26356
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Well, you're doing two things wrong.

    First, your ForEach is referring to $GlobalVar. It should refer to $WFParam, right?

    Also, keep in mind that -Parallel won't necessarily go in order.

  • #26378
    Profile photo of Richard Diphoorn
    Richard Diphoorn
    Participant

    I've not tested it and I'm guessing here, but isn't it also a problem that function Get-F01 is called inside function Get-F02? I think the workflow cannot use the function. I will test it in a bit.

  • #26379
    Profile photo of Don Jones
    Don Jones
    Keymaster
  • #26381
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Oh, the other bit – inside Get-f02, you're not using the $Param02 you passed to it. You're using $FunctionVar.

    What's this produce for you?

    Workflow get-workflow {
    
     param([string[]]$WFParam)
    
        Function get-f01 {
            param([string]$Param01)
            
            "Function 01 $Param01"
        } #end get-f01
    
    
        Function get-f02 {
            param([string]$Param02)
            
            "Function 02 $Param02"
            get-f01 -Param01 $Param02
        } #end get-f02
    
      foreach -parallel($FunctionVar in $WFParam) {
    
            get-f02 -Param02 $FunctionVar
        } #end foreach
    } #end workflow
    
    $GlobalVar = "Variable01","Variable02"
    get-workflow -WFParam $GlobalVar
    
  • #26382
    Profile photo of Grant Harrington
    Grant Harrington
    Participant

    $GlobalVar = "Variable01","Variable02"
    get-workflow -WFParam $GlobalVar
    Function 02 Variable02
    Function 02 Variable01
    Microsoft.PowerShell.Utility\Write-Error : The term 'get-f01'….
    Microsoft.PowerShell.Utility\Write-Error : The term 'get-f01'….

    Making it a Function that contains the two Functions and running a foreach gives the desired results. Is that "efficient" use of coding, or would a Workflow still be the best solution?

    Function get-f03 {
    
    foreach ($FunctionVar in $GlobalVar) {
        Function get-f01 {
            [cmdletbinding()]
            param([Parameter(ValueFromPipeline)]
            [string]$Param01)
                    
            "Function 01 $FunctionVar"
        } #end get-f01
    
    
        Function get-f02 {
        [cmdletbinding()]
            param([Parameter(ValueFromPipeline)]
            [string]$Param02)
            
            "Function 02 $FunctionVar"
            get-f01 -Param01 $FunctionVar
        } #end get-f02
    get-f02 -Param02 $FunctionVar
    } #end foreach
    } #end get-f03
        $global:GlobalVar = 'Variable01','Variable02'
      get-f03 $GlobalVar
    

    Output of get-f03 $GlobalVar is (desired results).

    Function 02 Variable01
    Function 01 Variable01
    Function 02 Variable02
    Function 01 Variable02

  • #26383
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Well... there are reasons to use Workflow. If you need those reasons, Workflow is your only option. If you don't, it's a terrible option. Workflow isn't, technically, PowerShell; your code is being translated to WWF.

  • #26385
    Profile photo of Grant Harrington
    Grant Harrington
    Participant

    Thanks. I do have another option, which is break out of the Function wrapper and put all the code into one long script. I was hoping to keep the functions isolated for code manageability, but in the end I can do that. Or run them both inside in F03, which seems to work too.

    Thanks for the help.

  • #26386
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Yeah, in theory what you're trying should work. But it all comes down tot he fact that Workflow isn't PowerShell. What I suspect is happening is that each function is being implicitly wrapped in an InlineScript, since "function" isn't a WWF thing. That means each function lives in its own little universe; Workflow will pass in the global scope variables, but I'm betting that's why the two functions can't "see" each other. Unfortunately, so much happens invisibly under the hood that it can be hard to unwind.

    What you'd end up doing is having the Workflow call Function A, have Function A return a result, and have the Workflow top-level then call Function B, passing in Function A's result as input. So you're never calling more than one level deep. That ought to work.

    One of the many, many reasons I'm not a raging fan of how Workflow got done :(.

  • #26389
    Profile photo of Richard Diphoorn
    Richard Diphoorn
    Participant

    It's what I ment Don. It's not possible to use nested functions in a single workflow, and that's because the workflow can only see the functions within it's own scope. To be able to call the function inside the function, you have to call a new workflow within the workflow.

    Pffff.... it's too much for a friday. It's one of the reasons why I don't like workflow so much, because of this nesting and scoping issues.

You must be logged in to reply to this topic.