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