Author Posts

June 11, 2015 at 6:56 pm

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

June 11, 2015 at 7:18 pm

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.

June 12, 2015 at 5:37 am

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.

June 12, 2015 at 5:49 am

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

June 12, 2015 at 6:42 am

$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

June 12, 2015 at 6:44 am

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.

June 12, 2015 at 6:48 am

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.

June 12, 2015 at 6:57 am

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 :(.

June 12, 2015 at 7:06 am

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.