I have a solution in Powershell (7) where I have a module that includes a class, like
test.psm1
class TestClass {
[string]$Test
TestClass(
[string]$_test
) {
$this.Test = $_test
}
[void] TestMethod() {
xxx
}
}
In the main script I can successfully import the module including its classes and work with it.
In the main script I also want to process certain steps in parallel using jobs, like
using module .\test.psm1
[TestClass]$test = [TestClass]::new()
$job = $objects | ForEach-Object -Parallel {
[TestClass]$testJob = $using:test
} -ThrottleLimit $ParallelJobsThrottleLimit -AsJob
In these jobs I want to use an object of type TestClass that has been declared outside of the parallel statement.
All my approaches so far failed with Unable to find type
.
How can I make this work?
CodePudding user response:
As of PowerShell 7.2.x, the instances of a script block ({ ... }
) passed to ForEach-Object
-Parallel
, which run in parallel runspaces, do not see any of the caller's runspace state, which includes class
definitions.
Hence the need for the
$using:
scope to reference values stored in the caller's variables.Unfortunately, there is no equivalent mechanism for custom classes.
GitHub issue #12240 discusses a future enhancement that will allow parallel runspaces to see at least parts of the caller's state, which would hopefully included classes.
The problem, in a nutshell:
In order for parallel runspaces to see your
[TestClass]
too, they would have to import its containing module.However, only when you import a module via
using module
are a module's classes visible to the caller (not also when you useImport-Module
).Unfortunately,
using
statements may only be placed at the start of a script file, and therefore cannot be used inside script blocks.
There is a cumbersome workaround:
Define your
class
in a regular.ps1
script that you reference from theScriptsToProcess
entry of your module's manifest file (.psd1
)That way, when the module is first imported into a runspace, the
.ps1
script is dot-sourced in the caller's (importer's) scope, andclass
definitions therefore become visible.This allows you to use a regular
Import-Module
call in your parallel script block in order to see theclass
definition there.
Note that your module itself will not see such class
definitions by default - unless you explicitly dot-source the .ps1
file from the module's top-level code too.