13

Copy and paste the following into a new Powershell ISE script and hit F5:

workflow workflow1{
    "in workflow1"
    func1
}
function func1 {
    "in func1"
    func2
}
function func2 {
    "in func2"
}
workflow1

the error I get is:

The term 'func2' is not recognized as the name of a cmdlet, function, script file, or operable program

I don't understand this. Why would func1 be in scope but not func2? Any help much appreciated. TIA.

jamiet
  • 10,501
  • 14
  • 80
  • 159
  • This is interesting. If I had to guess it would be because `Func1` is invoked from within the workflow definition directly but `func2` is not. From reading about workflow processing there do seem to be a number of restrictions about working between scopes. – JNK Dec 08 '14 at 15:38

4 Answers4

11

Think of Workflows as short-sighted programming elements.

A Workflow cannot see beyond what's immediately available in the scope. So nested functions are not working with a single workflow, because it cannot see them.

The fix is to nest workflows along with nested functions. Such as this:

workflow workflow1
{
    function func1 
    {
        "in func1"
        workflow workflow2
        {
            function func2 
            {
                "in func2"
            }
            func2
        }
        "in workflow2"
        workflow2
    }
    "in workflow1"
    func1
}
workflow1

Then it sees the nested functions:

in workflow1
in func1
in workflow2
in func2

More about it here

Micky Balladelli
  • 9,781
  • 2
  • 33
  • 31
  • 3
    Thanks Micky. Kind of annoying though, I have functions I want to use in different workflows, but now I can't. Kinda defeats the purpose of functions IMO. – jamiet Dec 09 '14 at 08:07
  • @jamiet Really late to the party but you can put the functions in a module and import the module for each workflow that needs it. – duct_tape_coder May 09 '19 at 20:15
1

Not really an answer to your question, but more a track to follow. Putting this in a comment would be too long.

From here :

When you run a script workflow, Windows PowerShell parses the script into an abstract syntax tree (AST). The presence of the “workflow” keyword causes the script-to-workflow compiler to use this AST to generate XAML, the format required by the Windows Workflow Foundation runtime. To create the user experience for interacting with this workflow, we then create a wrapper function that has the same parameters – but instead coordinates execution of the workflow within the PowerShell Workflow executive. You can see both the wrapper function and the generated XAML by executing:

Get-Command workflow1 |Format-List *

I did that for your specific workflow (see the workflow1 in the command above) and both XAML and PowerShell generated code are ... interesting. XAML code doesn't include any reference to func2, but contains a reference to func1.

David Brabant
  • 41,623
  • 16
  • 83
  • 111
  • interesting, you do seem to be onto something David. I'll keep digging – jamiet Dec 08 '14 at 16:09
  • 1
    If you call `Get-ChildItem function:func*` within the workflow, it doesn't list `func1` or `func2` at all. There do appear to be a lot of [seemingly arbitrary restrictions on workflows](http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/02/powershell-workflows-restrictions.aspx), but it doesn't seem to be very well documented. I mean, there's a [ton of examples](http://technet.microsoft.com/en-us/library/jj574157.aspx), but that doesn't explain how things work, just that they do. [This](http://blogs.technet.com/b/heyscriptingguy/archive/tags/workflow/) is the best resource I can find. – Bacon Bits Dec 08 '14 at 16:11
0

To vaguely summarise all the responses, don't question why it behaves this way, just accept that it does and deal with it. Fair enough.

I've written a whole deployment pipeline in none-workflow Powershell and I'd like to optimise it by using workflow's "foreach -parallel" however it seems the tax on doing so is that I'd have to go back and re-write the whole thing in workflow. That's too big a tax to pay unfortunately just to get a parallel foreach loop.

Lesson learned - use Powershell workflow from the get-go.

jamiet
  • 10,501
  • 14
  • 80
  • 159
0

You could wrap the functions and their calls inside an InlineScript - which could be a per-system script. Then run that inlinescript inside a foreach -Parallel loop working through the systems you want to query.

Thomas Lee
  • 1,158
  • 6
  • 13