Using a recursive function beside a workflow Using a recursive function beside a workflow powershell powershell

Using a recursive function beside a workflow


Recursive calling is not permitted in workflows.

Give your path directly:

Instead of this:

Recurse($myPath)

do this:

Recurse $myPath

You can refer to this article:

Adding Nested functions and Nested Workflows


I eventually (of course just a few minutes after posting the question) solved this by just extracting the function into its own module:

get-files.psm1:

function Recurse(){    params(        [parameter(mandatory)][string]$path    )    .. create $folder    foreach ($i in $folder.files) {         $i    }    foreach ($i in $folder.subfolders) {        Recurse($i.path)    }}Export-ModuleMember -Function Recurse

get-files.psd1:

@{...FunctionsToExport = @(Recurse)...}

script.ps1:

workflow do-work {    params(        [parameter(mandatory)][object[]]$files    )    ...}Import-Module -Name "path\to\module\get-files.psm1"$files = Recurse -path $myPathdo-work -files $files

This seem to have made the main script to miss that Recurse uses recursion and it works.


For those looking to use a "parallel" workflow (no recursion) in a module, the solution is similar but a little different.

for example, this workflow can be used to start/stop service in parallel

Workflow Invoke-ServiceInParallelWF{    <#    .SYNOPSIS    Workflow to stop/start services in parallel on a server.    .DESCRIPTION    Utilizes a workflow to start/stop services running on a server in parallel to shorten the start/stop duration.    #>    Param(        [Parameter(Mandatory=$true)]        [string[]]$Name,        [Parameter(Mandatory=$true)]        [ValidateSet("Start","Stop")]        [string]$Action    )    if (!($Name.Count -gt 0))    {        throw "No services provided!"    }        # run parrallel on services argument    foreach -parallel ($svc in $Name){            InlineScript{                    #build object first for consistency            $props=[ordered]@{                Service=$using:svc;                Action=$using:action                Result=$null                Error=$null            }                        # Wrap in exception handler            Try{                #Perform the desired service action                if ($using:action -eq 'stop') {                    Stop-Service -name $using:svc -ErrorAction stop                } elseif ($using:action -eq 'start') {                    Start-Service -name $using:svc -ErrorAction stop                } else {                    $Action='unknown'                }                $props.Result='Success'            }            Catch{                $props.Result='Fail'                $props.Error="$_"            }                        # generate object back to workflow            New-Object -TypeName PSCustomObject -Property $props        }            }}

if you put this in your psm1 file and try to import it, it will fail with this error:

At C:\Source\Powershell\Common\Modules\MyModule\MyModule.psm1:1 char:1+ #+ ~A workflow cannot use recursion.    + CategoryInfo          : ParserError: (:) [], ParseException    + FullyQualifiedErrorId : RecursiveWorkflowNotSupported

To embed this in the module, do NOT put it in the .psm1 file, create a separate ps1 file and place it in the module folder.e.g. Invoke-ServiceInParallelWF.ps1

Then in your manifest (psd1) file, modify the ScriptsToProcess to include the ps1 file.

@{  # Script module or binary module file associated with this manifest.  RootModule = 'MyModule.psm1'  # Version number of this module.  ModuleVersion = '1.47.1'  # ID used to uniquely identify this module  GUID = 'bd4390dc-a8ad-4bce-8d69-f53ccf8e4163'  # Author of this module  Author = 'Justin Marshall'  # Script files (.ps1) that are run in the caller's environment prior to importing this module.  ScriptsToProcess = @('Invoke-ServiceInParallelWF.ps1')}

finally, import your module and test the function:

PS C:\source\powershell> Import-Module MyModule -forcePS C:\source\powershell> Invoke-ServiceInParallelWF -Action Start -Name w3svcService               : w3svcAction                : StartResult                : SuccessError                 :PSComputerName        : localhostPSSourceJobInstanceId : 1a564d5d-f363-44b7-a27e-88670764de2d